diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
---|---|---|
committer | <> | 2014-05-08 15:03:54 +0000 |
commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Runtime/common/misc | |
parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
download | VirtualBox-master.tar.gz |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Runtime/common/misc')
35 files changed, 2507 insertions, 129 deletions
diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg1Weak.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg1Weak.cpp index ef0f35ee..06d6afa1 100644 --- a/src/VBox/Runtime/common/misc/RTAssertMsg1Weak.cpp +++ b/src/VBox/Runtime/common/misc/RTAssertMsg1Weak.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg2.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg2.cpp index 401baac8..69fbd049 100644 --- a/src/VBox/Runtime/common/misc/RTAssertMsg2.cpp +++ b/src/VBox/Runtime/common/misc/RTAssertMsg2.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg2Add.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg2Add.cpp index e0f3fb23..f8bd63ec 100644 --- a/src/VBox/Runtime/common/misc/RTAssertMsg2Add.cpp +++ b/src/VBox/Runtime/common/misc/RTAssertMsg2Add.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008-2009 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeak.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeak.cpp index 297e60d9..a36a30ac 100644 --- a/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeak.cpp +++ b/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeak.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008-2009 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeakV.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeakV.cpp index 99bc5e64..8ffe97e2 100644 --- a/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeakV.cpp +++ b/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeakV.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg2Weak.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg2Weak.cpp index 2b5b9cf6..7a40d265 100644 --- a/src/VBox/Runtime/common/misc/RTAssertMsg2Weak.cpp +++ b/src/VBox/Runtime/common/misc/RTAssertMsg2Weak.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008-2009 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/RTAssertMsg2WeakV.cpp b/src/VBox/Runtime/common/misc/RTAssertMsg2WeakV.cpp index 2d9b5eff..f54b0446 100644 --- a/src/VBox/Runtime/common/misc/RTAssertMsg2WeakV.cpp +++ b/src/VBox/Runtime/common/misc/RTAssertMsg2WeakV.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/RTFileModeToFlags.cpp b/src/VBox/Runtime/common/misc/RTFileModeToFlags.cpp new file mode 100644 index 00000000..b5e10a27 --- /dev/null +++ b/src/VBox/Runtime/common/misc/RTFileModeToFlags.cpp @@ -0,0 +1,337 @@ +/* $Id: RTFileModeToFlags.cpp $ */ +/** @file + * IPRT - RTFileModeToFlags. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include <iprt/assert.h> +#include <iprt/err.h> +#include <iprt/file.h> +#include <iprt/string.h> +#include "internal/iprt.h" + + +RTR3DECL(int) RTFileModeToFlags(const char *pszMode, uint64_t *puMode) +{ + AssertPtrReturn(pszMode, VERR_INVALID_POINTER); + AssertPtrReturn(puMode, VERR_INVALID_POINTER); + + int rc = VINF_SUCCESS; + + const char *pszCur = pszMode; + uint64_t uMode = 0; + char chPrev = 0; + + if (*pszCur == '\0') + return VERR_INVALID_PARAMETER; + + while ( pszCur + && *pszCur != '\0') + { + bool fSkip = false; + switch (*pszCur) + { + /* Opens an existing file for writing and places the + * file pointer at the end of the file. The file is + * created if it does not exist. */ + case 'a': + if ((uMode & RTFILE_O_ACTION_MASK) == 0) + { + uMode |= RTFILE_O_OPEN_CREATE + | RTFILE_O_WRITE + | RTFILE_O_APPEND; + } + else + rc = VERR_INVALID_PARAMETER; + break; + + case 'b': /* Binary mode. */ + /* Just skip as being valid. */ + fSkip = true; + break; + + /* Creates a file or open an existing one for + * writing only. The file pointer will be placed + * at the beginning of the file.*/ + case 'c': + if ((uMode & RTFILE_O_ACTION_MASK) == 0) + { + uMode |= RTFILE_O_OPEN_CREATE + | RTFILE_O_WRITE; + } + else + rc = VERR_INVALID_PARAMETER; + break; + + /* Opens an existing file for reading and places the + * file pointer at the beginning of the file. If the + * file does not exist an error will be returned. */ + case 'r': + if ((uMode & RTFILE_O_ACTION_MASK) == 0) + { + uMode |= RTFILE_O_OPEN + | RTFILE_O_READ; + } + else + rc = VERR_INVALID_PARAMETER; + break; + + case 't': /* Text mode. */ + /* Just skip as being valid. */ + fSkip = true; + break; + + /* Creates a new file or replaces an existing one + * for writing. Places the file pointer at the beginning. + * An existing file will be truncated to 0 bytes. */ + case 'w': + if ((uMode & RTFILE_O_ACTION_MASK) == 0) + { + uMode |= RTFILE_O_CREATE_REPLACE + | RTFILE_O_WRITE + | RTFILE_O_TRUNCATE; + } + else + rc = VERR_INVALID_PARAMETER; + break; + + /* Creates a new file and opens it for writing. Places + * the file pointer at the beginning. If the file + * exists an error will be returned. */ + case 'x': + if ((uMode & RTFILE_O_ACTION_MASK) == 0) + { + uMode |= RTFILE_O_CREATE + | RTFILE_O_WRITE; + } + else + rc = VERR_INVALID_PARAMETER; + break; + + case '+': + { + switch (chPrev) + { + case 'a': + case 'c': + case 'w': + case 'x': + /* Also open / create file with read access. */ + uMode |= RTFILE_O_READ; + break; + + case 'r': + /* Also open / create file with write access. */ + uMode |= RTFILE_O_WRITE; + break; + + case 'b': + case 't': + /* Silently eat skipped parameters. */ + fSkip = true; + break; + + case 0: /* No previous character yet. */ + case '+': + /* Eat plusses which don't belong to a command. */ + fSkip = true; + break; + + default: + rc = VERR_INVALID_PARAMETER; + break; + } + + break; + } + + default: + rc = VERR_INVALID_PARAMETER; + break; + } + + if (RT_FAILURE(rc)) + break; + + if (!fSkip) + chPrev = *pszCur; + pszCur++; + } + + /* No action mask set? */ + if ( RT_SUCCESS(rc) + && (uMode & RTFILE_O_ACTION_MASK) == 0) + rc = VERR_INVALID_PARAMETER; + + /** @todo Handle sharing mode. */ + uMode |= RTFILE_O_DENY_NONE; + + if (RT_SUCCESS(rc)) + *puMode = uMode; + + return rc; +} +RT_EXPORT_SYMBOL(RTFileModeToFlags); + + +RTR3DECL(int) RTFileModeToFlagsEx(const char *pszAccess, const char *pszDisposition, + const char *pszSharing, uint64_t *puMode) +{ + AssertPtrReturn(pszAccess, VERR_INVALID_POINTER); + AssertPtrReturn(pszDisposition, VERR_INVALID_POINTER); + /* pszSharing is not used yet. */ + AssertPtrReturn(puMode, VERR_INVALID_POINTER); + + int rc = VINF_SUCCESS; + + const char *pszCur = pszAccess; + uint64_t uMode = 0; + char chPrev = 0; + + if (*pszCur == '\0') + return VERR_INVALID_PARAMETER; + + /* + * Handle access mode. + */ + while ( pszCur + && *pszCur != '\0') + { + bool fSkip = false; + switch (*pszCur) + { + case 'b': /* Binary mode. */ + /* Just skip as being valid. */ + fSkip = true; + break; + + case 'r': /* Read. */ + uMode |= RTFILE_O_READ; + break; + + case 't': /* Text mode. */ + /* Just skip as being valid. */ + fSkip = true; + break; + + case 'w': /* Write. */ + uMode |= RTFILE_O_WRITE; + break; + + case '+': + { + switch (chPrev) + { + case 'w': + /* Also use read access in write mode. */ + uMode |= RTFILE_O_READ; + break; + + case 'r': + /* Also use write access in read mode. */ + uMode |= RTFILE_O_WRITE; + break; + + case 'b': + case 't': + /* Silently eat skipped parameters. */ + fSkip = true; + break; + + case 0: /* No previous character yet. */ + case '+': + /* Eat plusses which don't belong to a command. */ + fSkip = true; + break; + + default: + rc = VERR_INVALID_PARAMETER; + break; + } + + break; + } + + default: + rc = VERR_INVALID_PARAMETER; + break; + } + + if (RT_FAILURE(rc)) + break; + + if (!fSkip) + chPrev = *pszCur; + pszCur++; + } + + if (RT_FAILURE(rc)) + return rc; + + /* + * Handle disposition. + */ + pszCur = pszDisposition; + + /* Create a new file, always, overwrite an existing file. */ + if (!RTStrCmp(pszCur, "ca")) + uMode |= RTFILE_O_CREATE_REPLACE; + /* Create a new file if it does not exist, fail if exist. */ + else if (!RTStrCmp(pszCur, "ce")) + uMode |= RTFILE_O_CREATE; + /* Open existing file, create file if does not exist. */ + else if (!RTStrCmp(pszCur, "oc")) + uMode |= RTFILE_O_OPEN_CREATE; + /* Open existing file and place the file pointer at + * the end of the file, if opened with write access. + * Create the file if does not exist. */ + else if (!RTStrCmp(pszCur, "oa")) + uMode |= RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND; + /* Open existing, fail if does not exist. */ + else if (!RTStrCmp(pszCur, "oe")) + uMode |= RTFILE_O_OPEN; + /* Open and truncate existing, fail of not exist. */ + else if (!RTStrCmp(pszCur, "ot")) + uMode |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE; + else + rc = VERR_INVALID_PARAMETER; + + /* No action mask set? */ + if ( RT_SUCCESS(rc) + && (uMode & RTFILE_O_ACTION_MASK) == 0) + rc = VERR_INVALID_PARAMETER; + + /** @todo Handle sharing mode. */ + uMode |= RTFILE_O_DENY_NONE; + + if (RT_SUCCESS(rc)) + *puMode = uMode; + + return rc; +} +RT_EXPORT_SYMBOL(RTFileModeToFlagsEx); + diff --git a/src/VBox/Runtime/common/misc/RTFileOpenF.cpp b/src/VBox/Runtime/common/misc/RTFileOpenF.cpp index e2737bf6..73837369 100644 --- a/src/VBox/Runtime/common/misc/RTFileOpenF.cpp +++ b/src/VBox/Runtime/common/misc/RTFileOpenF.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/RTFileOpenV.cpp b/src/VBox/Runtime/common/misc/RTFileOpenV.cpp index 43214e06..b8ed619e 100644 --- a/src/VBox/Runtime/common/misc/RTFileOpenV.cpp +++ b/src/VBox/Runtime/common/misc/RTFileOpenV.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/aiomgr.cpp b/src/VBox/Runtime/common/misc/aiomgr.cpp new file mode 100644 index 00000000..43f12c87 --- /dev/null +++ b/src/VBox/Runtime/common/misc/aiomgr.cpp @@ -0,0 +1,1314 @@ +/* $Id: aiomgr.cpp $ */ +/** @file + * IPRT - Async I/O manager. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ + +#include <iprt/aiomgr.h> +#include <iprt/err.h> +#include <iprt/asm.h> +#include <iprt/mem.h> +#include <iprt/file.h> +#include <iprt/list.h> +#include <iprt/thread.h> +#include <iprt/assert.h> +#include <iprt/string.h> +#include <iprt/critsect.h> +#include <iprt/memcache.h> +#include <iprt/semaphore.h> +#include <iprt/queueatomic.h> + +#include "internal/magics.h" + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ + +/** Pointer to an internal async I/O file instance. */ +typedef struct RTAIOMGRFILEINT *PRTAIOMGRFILEINT; + +/** + * Blocking event types. + */ +typedef enum RTAIOMGREVENT +{ + /** Invalid tye */ + RTAIOMGREVENT_INVALID = 0, + /** No event pending. */ + RTAIOMGREVENT_NO_EVENT, + /** A file is added to the manager. */ + RTAIOMGREVENT_FILE_ADD, + /** A file is about to be closed. */ + RTAIOMGREVENT_FILE_CLOSE, + /** The async I/O manager is shut down. */ + RTAIOMGREVENT_SHUTDOWN, + /** 32bit hack */ + RTAIOMGREVENT_32BIT_HACK = 0x7fffffff +} RTAIOMGREVENT; + +/** + * Async I/O manager instance data. + */ +typedef struct RTAIOMGRINT +{ + /** Magic value. */ + uint32_t u32Magic; + /** Reference count. */ + volatile uint32_t cRefs; + /** Async I/O context handle. */ + RTFILEAIOCTX hAioCtx; + /** async I/O thread. */ + RTTHREAD hThread; + /** List of files assigned to this manager. */ + RTLISTANCHOR ListFiles; + /** Number of requests active currently. */ + unsigned cReqsActive; + /** Number of maximum requests active. */ + uint32_t cReqsActiveMax; + /** Memory cache for requests. */ + RTMEMCACHE hMemCacheReqs; + /** Critical section protecting the blocking event handling. */ + RTCRITSECT CritSectBlockingEvent; + /** Event semaphore for blocking external events. + * The caller waits on it until the async I/O manager + * finished processing the event. */ + RTSEMEVENT hEventSemBlock; + /** Blocking event type */ + volatile RTAIOMGREVENT enmBlockingEvent; + /** Event type data */ + union + { + /** The file to be added */ + volatile PRTAIOMGRFILEINT pFileAdd; + /** The file to be closed */ + volatile PRTAIOMGRFILEINT pFileClose; + } BlockingEventData; +} RTAIOMGRINT; +/** Pointer to an internal async I/O manager instance. */ +typedef RTAIOMGRINT *PRTAIOMGRINT; + +/** + * Async I/O manager file instance data. + */ +typedef struct RTAIOMGRFILEINT +{ + /** Magic value. */ + uint32_t u32Magic; + /** Reference count. */ + volatile uint32_t cRefs; + /** Flags. */ + uint32_t fFlags; + /** Opaque user data passed on creation. */ + void *pvUser; + /** File handle. */ + RTFILE hFile; + /** async I/O manager this file belongs to. */ + PRTAIOMGRINT pAioMgr; + /** Work queue for new requests. */ + RTQUEUEATOMIC QueueReqs; + /** Completion callback for this file. */ + PFNRTAIOMGRREQCOMPLETE pfnReqCompleted; + /** Data for exclusive use by the assigned async I/O manager. */ + struct + { + /** List node of assigned files for a async I/O manager. */ + RTLISTNODE NodeAioMgrFiles; + /** List of requests waiting for submission. */ + RTLISTANCHOR ListWaitingReqs; + /** Number of requests currently being processed for this endpoint + * (excluded flush requests). */ + unsigned cReqsActive; + } AioMgr; +} RTAIOMGRFILEINT; + +/** Flag whether the file is closed. */ +#define RTAIOMGRFILE_FLAGS_CLOSING RT_BIT_32(1) + +/** + * Request type. + */ +typedef enum RTAIOMGRREQTYPE +{ + /** Invalid request type. */ + RTAIOMGRREQTYPE_INVALID = 0, + /** Read reques type. */ + RTAIOMGRREQTYPE_READ, + /** Write request. */ + RTAIOMGRREQTYPE_WRITE, + /** Flush request. */ + RTAIOMGRREQTYPE_FLUSH, + /** Prefetech request. */ + RTAIOMGRREQTYPE_PREFETCH, + /** 32bit hack. */ + RTAIOMGRREQTYPE_32BIT_HACK = 0x7fffffff +} RTAIOMGRREQTYPE; +/** Pointer to a reques type. */ +typedef RTAIOMGRREQTYPE *PRTAIOMGRREQTYPE; + +/** + * Async I/O manager request. + */ +typedef struct RTAIOMGRREQ +{ + /** Atomic queue work item. */ + RTQUEUEATOMICITEM WorkItem; + /** Node for a waiting list. */ + RTLISTNODE NodeWaitingList; + /** Request flags. */ + uint32_t fFlags; + /** Transfer type. */ + RTAIOMGRREQTYPE enmType; + /** Assigned file request. */ + RTFILEAIOREQ hReqIo; + /** File the request belongs to. */ + PRTAIOMGRFILEINT pFile; + /** Opaque user data. */ + void *pvUser; + /** Start offset */ + RTFOFF off; + /** Data segment. */ + RTSGSEG DataSeg; + /** When non-zero the segment uses a bounce buffer because the provided buffer + * doesn't meet host requirements. */ + size_t cbBounceBuffer; + /** Pointer to the used bounce buffer if any. */ + void *pvBounceBuffer; + /** Start offset in the bounce buffer to copy from. */ + uint32_t offBounceBuffer; +} RTAIOMGRREQ; +/** Pointer to a I/O manager request. */ +typedef RTAIOMGRREQ *PRTAIOMGRREQ; + +/** Flag whether the request was prepared already. */ +#define RTAIOMGRREQ_FLAGS_PREPARED RT_BIT_32(0) + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ + +/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */ +#define RTAIOMGR_VALID_RETURN_RC(a_hAioMgr, a_rc) \ + do { \ + AssertPtrReturn((a_hAioMgr), (a_rc)); \ + AssertReturn((a_hAioMgr)->u32Magic == RTAIOMGR_MAGIC, (a_rc)); \ + } while (0) + +/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */ +#define RTAIOMGR_VALID_RETURN(a_hAioMgr) RTAIOMGR_VALID_RETURN_RC((hAioMgr), VERR_INVALID_HANDLE) + +/** Validates a handle and returns (void) if not valid. */ +#define RTAIOMGR_VALID_RETURN_VOID(a_hAioMgr) \ + do { \ + AssertPtrReturnVoid(a_hAioMgr); \ + AssertReturnVoid((a_hAioMgr)->u32Magic == RTAIOMGR_MAGIC); \ + } while (0) + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ + +static int rtAioMgrReqsEnqueue(PRTAIOMGRINT pThis, PRTAIOMGRFILEINT pFile, + PRTFILEAIOREQ pahReqs, unsigned cReqs); + +/** + * Removes an endpoint from the currently assigned manager. + * + * @returns TRUE if there are still requests pending on the current manager for this endpoint. + * FALSE otherwise. + * @param pEndpointRemove The endpoint to remove. + */ +static bool rtAioMgrFileRemove(PRTAIOMGRFILEINT pFile) +{ + /* Make sure that there is no request pending on this manager for the endpoint. */ + if (!pFile->AioMgr.cReqsActive) + { + RTListNodeRemove(&pFile->AioMgr.NodeAioMgrFiles); + return false; + } + + return true; +} + +/** + * Allocate a new I/O request. + * + * @returns Pointer to the allocated request or NULL if out of memory. + * @param pThis The async I/O manager instance. + */ +static PRTAIOMGRREQ rtAioMgrReqAlloc(PRTAIOMGRINT pThis) +{ + return (PRTAIOMGRREQ)RTMemCacheAlloc(pThis->hMemCacheReqs); +} + +/** + * Frees an I/O request. + * + * @returns nothing. + * @param pThis The async I/O manager instance. + * @param pReq The request to free. + */ +static void rtAioMgrReqFree(PRTAIOMGRINT pThis, PRTAIOMGRREQ pReq) +{ + if (pReq->cbBounceBuffer) + { + AssertPtr(pReq->pvBounceBuffer); + RTMemPageFree(pReq->pvBounceBuffer, pReq->cbBounceBuffer); + pReq->pvBounceBuffer = NULL; + pReq->cbBounceBuffer = 0; + } + pReq->fFlags = 0; + RTAioMgrFileRelease(pReq->pFile); + RTMemCacheFree(pThis->hMemCacheReqs, pReq); +} + +static void rtAioMgrReqCompleteRc(PRTAIOMGRINT pThis, PRTAIOMGRREQ pReq, + int rcReq, size_t cbTransfered) +{ + int rc = VINF_SUCCESS; + PRTAIOMGRFILEINT pFile; + + pFile = pReq->pFile; + pThis->cReqsActive--; + pFile->AioMgr.cReqsActive--; + + /* + * It is possible that the request failed on Linux with kernels < 2.6.23 + * if the passed buffer was allocated with remap_pfn_range or if the file + * is on an NFS endpoint which does not support async and direct I/O at the same time. + * The endpoint will be migrated to a failsafe manager in case a request fails. + */ + if (RT_FAILURE(rcReq)) + { + pFile->pfnReqCompleted(pFile, rcReq, pReq->pvUser); + rtAioMgrReqFree(pThis, pReq); + } + else + { + /* + * Restart an incomplete transfer. + * This usually means that the request will return an error now + * but to get the cause of the error (disk full, file too big, I/O error, ...) + * the transfer needs to be continued. + */ + if (RT_UNLIKELY( cbTransfered < pReq->DataSeg.cbSeg + || ( pReq->cbBounceBuffer + && cbTransfered < pReq->cbBounceBuffer))) + { + RTFOFF offStart; + size_t cbToTransfer; + uint8_t *pbBuf = NULL; + + Assert(cbTransfered % 512 == 0); + + if (pReq->cbBounceBuffer) + { + AssertPtr(pReq->pvBounceBuffer); + offStart = (pReq->off & ~((RTFOFF)512-1)) + cbTransfered; + cbToTransfer = pReq->cbBounceBuffer - cbTransfered; + pbBuf = (uint8_t *)pReq->pvBounceBuffer + cbTransfered; + } + else + { + Assert(!pReq->pvBounceBuffer); + offStart = pReq->off + cbTransfered; + cbToTransfer = pReq->DataSeg.cbSeg - cbTransfered; + pbBuf = (uint8_t *)pReq->DataSeg.pvSeg + cbTransfered; + } + + if ( pReq->enmType == RTAIOMGRREQTYPE_PREFETCH + || pReq->enmType == RTAIOMGRREQTYPE_READ) + { + rc = RTFileAioReqPrepareRead(pReq->hReqIo, pFile->hFile, offStart, + pbBuf, cbToTransfer, pReq); + } + else + { + AssertMsg(pReq->enmType == RTAIOMGRREQTYPE_WRITE, + ("Invalid transfer type\n")); + rc = RTFileAioReqPrepareWrite(pReq->hReqIo, pFile->hFile, offStart, + pbBuf, cbToTransfer, pReq); + } + AssertRC(rc); + + rc = rtAioMgrReqsEnqueue(pThis, pFile, &pReq->hReqIo, 1); + AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES), + ("Unexpected return code rc=%Rrc\n", rc)); + } + else if (pReq->enmType == RTAIOMGRREQTYPE_PREFETCH) + { + Assert(pReq->cbBounceBuffer); + pReq->enmType = RTAIOMGRREQTYPE_WRITE; + + memcpy(((uint8_t *)pReq->pvBounceBuffer) + pReq->offBounceBuffer, + pReq->DataSeg.pvSeg, + pReq->DataSeg.cbSeg); + + /* Write it now. */ + RTFOFF offStart = pReq->off & ~(RTFOFF)(512-1); + size_t cbToTransfer = RT_ALIGN_Z(pReq->DataSeg.cbSeg + (pReq->off - offStart), 512); + + rc = RTFileAioReqPrepareWrite(pReq->hReqIo, pFile->hFile, + offStart, pReq->pvBounceBuffer, cbToTransfer, pReq); + AssertRC(rc); + rc = rtAioMgrReqsEnqueue(pThis, pFile, &pReq->hReqIo, 1); + AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES), + ("Unexpected return code rc=%Rrc\n", rc)); + } + else + { + if (RT_SUCCESS(rc) && pReq->cbBounceBuffer) + { + if (pReq->enmType == RTAIOMGRREQTYPE_READ) + memcpy(pReq->DataSeg.pvSeg, + ((uint8_t *)pReq->pvBounceBuffer) + pReq->offBounceBuffer, + pReq->DataSeg.cbSeg); + } + + /* Call completion callback */ + pFile->pfnReqCompleted(pFile, rcReq, pReq->pvUser); + rtAioMgrReqFree(pThis, pReq); + } + } /* request completed successfully */ +} + +/** + * Wrapper around rtAioMgrReqCompleteRc(). + */ +static void rtAioMgrReqComplete(PRTAIOMGRINT pThis, RTFILEAIOREQ hReq) +{ + size_t cbTransfered = 0; + int rcReq = RTFileAioReqGetRC(hReq, &cbTransfered); + PRTAIOMGRREQ pReq = (PRTAIOMGRREQ)RTFileAioReqGetUser(hReq); + + rtAioMgrReqCompleteRc(pThis, pReq, rcReq, cbTransfered); +} + +/** + * Wrapper around RTFIleAioCtxSubmit() which is also doing error handling. + */ +static int rtAioMgrReqsEnqueue(PRTAIOMGRINT pThis, PRTAIOMGRFILEINT pFile, + PRTFILEAIOREQ pahReqs, unsigned cReqs) +{ + pThis->cReqsActive += cReqs; + pFile->AioMgr.cReqsActive += cReqs; + + int rc = RTFileAioCtxSubmit(pThis->hAioCtx, pahReqs, cReqs); + if (RT_FAILURE(rc)) + { + if (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES) + { + /* Append any not submitted task to the waiting list. */ + for (size_t i = 0; i < cReqs; i++) + { + int rcReq = RTFileAioReqGetRC(pahReqs[i], NULL); + + if (rcReq != VERR_FILE_AIO_IN_PROGRESS) + { + PRTAIOMGRREQ pReq = (PRTAIOMGRREQ)RTFileAioReqGetUser(pahReqs[i]); + + Assert(pReq->hReqIo == pahReqs[i]); + RTListAppend(&pFile->AioMgr.ListWaitingReqs, &pReq->NodeWaitingList); + pThis->cReqsActive--; + pFile->AioMgr.cReqsActive--; + } + } + + pThis->cReqsActiveMax = pThis->cReqsActive; + rc = VINF_SUCCESS; + } + else /* Another kind of error happened (full disk, ...) */ + { + /* An error happened. Find out which one caused the error and resubmit all other tasks. */ + for (size_t i = 0; i < cReqs; i++) + { + PRTAIOMGRREQ pReq = (PRTAIOMGRREQ)RTFileAioReqGetUser(pahReqs[i]); + int rcReq = RTFileAioReqGetRC(pahReqs[i], NULL); + + if (rcReq == VERR_FILE_AIO_NOT_SUBMITTED) + { + /* We call ourself again to do any error handling which might come up now. */ + rc = rtAioMgrReqsEnqueue(pThis, pFile, &pahReqs[i], 1); + AssertRC(rc); + } + else if (rcReq != VERR_FILE_AIO_IN_PROGRESS) + rtAioMgrReqCompleteRc(pThis, pReq, rcReq, 0); + } + } + } + + return VINF_SUCCESS; +} + +/** + * Adds a list of requests to the waiting list. + * + * @returns nothing. + * @param pFile The file instance to add the requests to. + * @param pReqsHead The head of the request list to add. + */ +static void rtAioMgrFileAddReqsToWaitingList(PRTAIOMGRFILEINT pFile, PRTAIOMGRREQ pReqsHead) +{ + while (pReqsHead) + { + PRTAIOMGRREQ pReqCur = pReqsHead; + + pReqsHead = (PRTAIOMGRREQ)pReqsHead->WorkItem.pNext; + pReqCur->WorkItem.pNext = NULL; + RTListAppend(&pFile->AioMgr.ListWaitingReqs, &pReqCur->NodeWaitingList); + } +} + +/** + * Prepare the native I/o request ensuring that all alignment prerequisites of + * the host are met. + * + * @returns IPRT statuse code. + * @param pFile The file instance data. + * @param pReq The request to prepare. + */ +static int rtAioMgrReqPrepareNonBuffered(PRTAIOMGRFILEINT pFile, PRTAIOMGRREQ pReq) +{ + int rc = VINF_SUCCESS; + RTFOFF offStart = pReq->off & ~(RTFOFF)(512-1); + size_t cbToTransfer = RT_ALIGN_Z(pReq->DataSeg.cbSeg + (pReq->off - offStart), 512); + void *pvBuf = pReq->DataSeg.pvSeg; + bool fAlignedReq = cbToTransfer == pReq->DataSeg.cbSeg + && offStart == pReq->off; + + /* + * Check if the alignment requirements are met. + * Offset, transfer size and buffer address + * need to be on a 512 boundary. + */ + if ( !fAlignedReq + /** @todo: || ((pEpClassFile->uBitmaskAlignment & (RTR3UINTPTR)pvBuf) != (RTR3UINTPTR)pvBuf) */) + { + /* Create bounce buffer. */ + pReq->cbBounceBuffer = cbToTransfer; + + AssertMsg(pReq->off >= offStart, ("Overflow in calculation off=%llu offStart=%llu\n", + pReq->off, offStart)); + pReq->offBounceBuffer = pReq->off - offStart; + + /** @todo: I think we need something like a RTMemAllocAligned method here. + * Current assumption is that the maximum alignment is 4096byte + * (GPT disk on Windows) + * so we can use RTMemPageAlloc here. + */ + pReq->pvBounceBuffer = RTMemPageAlloc(cbToTransfer); + if (RT_LIKELY(pReq->pvBounceBuffer)) + { + pvBuf = pReq->pvBounceBuffer; + + if (pReq->enmType == RTAIOMGRREQTYPE_WRITE) + { + if ( RT_UNLIKELY(cbToTransfer != pReq->DataSeg.cbSeg) + || RT_UNLIKELY(offStart != pReq->off)) + { + /* We have to fill the buffer first before we can update the data. */ + pReq->enmType = RTAIOMGRREQTYPE_WRITE; + } + else + memcpy(pvBuf, pReq->DataSeg.pvSeg, pReq->DataSeg.cbSeg); + } + } + else + rc = VERR_NO_MEMORY; + } + else + pReq->cbBounceBuffer = 0; + + if (RT_SUCCESS(rc)) + { + if (pReq->enmType == RTAIOMGRREQTYPE_WRITE) + { + rc = RTFileAioReqPrepareWrite(pReq->hReqIo, pFile->hFile, + offStart, pvBuf, cbToTransfer, pReq); + } + else /* Read or prefetch request. */ + rc = RTFileAioReqPrepareRead(pReq->hReqIo, pFile->hFile, + offStart, pvBuf, cbToTransfer, pReq); + AssertRC(rc); + pReq->fFlags |= RTAIOMGRREQ_FLAGS_PREPARED; + } + + return rc; +} + +/** + * Prepare a new request for enqueuing. + * + * @returns IPRT status code. + * @param pReq The request to prepare. + * @param phReqIo Where to store the handle to the native I/O request on success. + */ +static int rtAioMgrPrepareReq(PRTAIOMGRREQ pReq, PRTFILEAIOREQ phReqIo) +{ + int rc = VINF_SUCCESS; + PRTAIOMGRFILEINT pFile = pReq->pFile; + + switch (pReq->enmType) + { + case RTAIOMGRREQTYPE_FLUSH: + { + rc = RTFileAioReqPrepareFlush(pReq->hReqIo, pFile->hFile, pReq); + break; + } + case RTAIOMGRREQTYPE_READ: + case RTAIOMGRREQTYPE_WRITE: + { + rc = rtAioMgrReqPrepareNonBuffered(pFile, pReq); + break; + } + default: + AssertMsgFailed(("Invalid transfer type %d\n", pReq->enmType)); + } /* switch transfer type */ + + if (RT_SUCCESS(rc)) + *phReqIo = pReq->hReqIo; + + return rc; +} + +/** + * Prepare newly submitted requests for processing. + * + * @returns IPRT status code + * @param pThis The async I/O manager instance data. + * @param pFile The file instance. + * @param pReqsNew The list of new requests to prepare. + */ +static int rtAioMgrPrepareNewReqs(PRTAIOMGRINT pThis, + PRTAIOMGRFILEINT pFile, + PRTAIOMGRREQ pReqsNew) +{ + RTFILEAIOREQ apReqs[20]; + unsigned cRequests = 0; + int rc = VINF_SUCCESS; + + /* Go through the list and queue the requests. */ + while ( pReqsNew + && (pThis->cReqsActive + cRequests < pThis->cReqsActiveMax) + && RT_SUCCESS(rc)) + { + PRTAIOMGRREQ pCurr = pReqsNew; + pReqsNew = (PRTAIOMGRREQ)pReqsNew->WorkItem.pNext; + + pCurr->WorkItem.pNext = NULL; + AssertMsg(VALID_PTR(pCurr->pFile) && (pCurr->pFile == pFile), + ("Files do not match\n")); + AssertMsg(!(pCurr->fFlags & RTAIOMGRREQ_FLAGS_PREPARED), + ("Request on the new list is already prepared\n")); + + rc = rtAioMgrPrepareReq(pCurr, &apReqs[cRequests]); + if (RT_FAILURE(rc)) + rtAioMgrReqCompleteRc(pThis, pCurr, rc, 0); + else + cRequests++; + + /* Queue the requests if the array is full. */ + if (cRequests == RT_ELEMENTS(apReqs)) + { + rc = rtAioMgrReqsEnqueue(pThis, pFile, apReqs, cRequests); + cRequests = 0; + AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES), + ("Unexpected return code\n")); + } + } + + if (cRequests) + { + rc = rtAioMgrReqsEnqueue(pThis, pFile, apReqs, cRequests); + AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES), + ("Unexpected return code rc=%Rrc\n", rc)); + } + + if (pReqsNew) + { + /* Add the rest of the tasks to the pending list */ + rtAioMgrFileAddReqsToWaitingList(pFile, pReqsNew); + } + + /* Insufficient resources are not fatal. */ + if (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES) + rc = VINF_SUCCESS; + + return rc; +} + +/** + * Queues waiting requests. + * + * @returns IPRT status code. + * @param pThis The async I/O manager instance data. + * @param pFile The file to get the requests from. + */ +static int rtAioMgrQueueWaitingReqs(PRTAIOMGRINT pThis, PRTAIOMGRFILEINT pFile) +{ + RTFILEAIOREQ apReqs[20]; + unsigned cRequests = 0; + int rc = VINF_SUCCESS; + PRTAIOMGRREQ pReqIt; + PRTAIOMGRREQ pReqItNext; + + /* Go through the list and queue the requests. */ + RTListForEachSafe(&pFile->AioMgr.ListWaitingReqs, pReqIt, pReqItNext, RTAIOMGRREQ, NodeWaitingList) + { + RTListNodeRemove(&pReqIt->NodeWaitingList); + AssertMsg(VALID_PTR(pReqIt->pFile) && (pReqIt->pFile == pFile), + ("Files do not match\n")); + + if (!(pReqIt->fFlags & RTAIOMGRREQ_FLAGS_PREPARED)) + { + rc = rtAioMgrPrepareReq(pReqIt, &apReqs[cRequests]); + if (RT_FAILURE(rc)) + rtAioMgrReqCompleteRc(pThis, pReqIt, rc, 0); + else + cRequests++; + } + else + { + apReqs[cRequests] = pReqIt->hReqIo; + cRequests++; + } + + /* Queue the requests if the array is full. */ + if (cRequests == RT_ELEMENTS(apReqs)) + { + rc = rtAioMgrReqsEnqueue(pThis, pFile, apReqs, cRequests); + cRequests = 0; + AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES), + ("Unexpected return code\n")); + } + } + + if (cRequests) + { + rc = rtAioMgrReqsEnqueue(pThis, pFile, apReqs, cRequests); + AssertMsg(RT_SUCCESS(rc) || (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES), + ("Unexpected return code rc=%Rrc\n", rc)); + } + + /* Insufficient resources are not fatal. */ + if (rc == VERR_FILE_AIO_INSUFFICIENT_RESSOURCES) + rc = VINF_SUCCESS; + + return rc; +} + +/** + * Adds all pending requests for the given file. + * + * @returns IPRT status code. + * @param pThis The async I/O manager instance data. + * @param pFile The file to get the requests from. + */ +static int rtAioMgrQueueReqs(PRTAIOMGRINT pThis, PRTAIOMGRFILEINT pFile) +{ + int rc = VINF_SUCCESS; + PRTAIOMGRFILEINT pReqsHead = NULL; + + /* Check the pending list first */ + if (!RTListIsEmpty(&pFile->AioMgr.ListWaitingReqs)) + rc = rtAioMgrQueueWaitingReqs(pThis, pFile); + + if ( RT_SUCCESS(rc) + && RTListIsEmpty(&pFile->AioMgr.ListWaitingReqs)) + { + PRTAIOMGRREQ pReqsNew = (PRTAIOMGRREQ)RTQueueAtomicRemoveAll(&pFile->QueueReqs); + + if (pReqsNew) + { + rc = rtAioMgrPrepareNewReqs(pThis, pFile, pReqsNew); + AssertRC(rc); + } + } + + return rc; +} + +/** + * Checks all files for new requests. + * + * @returns IPRT status code. + * @param pThis The I/O manager instance data. + */ +static int rtAioMgrCheckFiles(PRTAIOMGRINT pThis) +{ + int rc = VINF_SUCCESS; + PRTAIOMGRFILEINT pIt; + + RTListForEach(&pThis->ListFiles, pIt, RTAIOMGRFILEINT, AioMgr.NodeAioMgrFiles) + { + rc = rtAioMgrQueueReqs(pThis, pIt); + if (RT_FAILURE(rc)) + return rc; + } + + return rc; +} + +/** + * Process a blocking event from the outside. + * + * @returns IPRT status code. + * @param pThis The async I/O manager instance data. + */ +static int rtAioMgrProcessBlockingEvent(PRTAIOMGRINT pThis) +{ + int rc = VINF_SUCCESS; + bool fNotifyWaiter = false; + + switch (pThis->enmBlockingEvent) + { + case RTAIOMGREVENT_NO_EVENT: + /* Nothing to do. */ + break; + case RTAIOMGREVENT_FILE_ADD: + { + PRTAIOMGRFILEINT pFile = ASMAtomicReadPtrT(&pThis->BlockingEventData.pFileAdd, PRTAIOMGRFILEINT); + AssertMsg(VALID_PTR(pFile), ("Adding file event without a file to add\n")); + + RTListAppend(&pThis->ListFiles, &pFile->AioMgr.NodeAioMgrFiles); + fNotifyWaiter = true; + break; + } + case RTAIOMGREVENT_FILE_CLOSE: + { + PRTAIOMGRFILEINT pFile = ASMAtomicReadPtrT(&pThis->BlockingEventData.pFileClose, PRTAIOMGRFILEINT); + AssertMsg(VALID_PTR(pFile), ("Close file event without a file to close\n")); + + if (!(pFile->fFlags & RTAIOMGRFILE_FLAGS_CLOSING)) + { + /* Make sure all requests finished. Process the queues a last time first. */ + rc = rtAioMgrQueueReqs(pThis, pFile); + AssertRC(rc); + + pFile->fFlags |= RTAIOMGRFILE_FLAGS_CLOSING; + fNotifyWaiter = !rtAioMgrFileRemove(pFile); + } + else if (!pFile->AioMgr.cReqsActive) + fNotifyWaiter = true; + break; + } + case RTAIOMGREVENT_SHUTDOWN: + { + if (!pThis->cReqsActive) + fNotifyWaiter = true; + break; + } + default: + AssertReleaseMsgFailed(("Invalid event type %d\n", pThis->enmBlockingEvent)); + } + + if (fNotifyWaiter) + { + /* Release the waiting thread. */ + rc = RTSemEventSignal(pThis->hEventSemBlock); + AssertRC(rc); + } + + return rc; +} + +/** + * async I/O manager worker loop. + * + * @returns IPRT status code. + * @param hThreadSelf The thread handle this worker belongs to. + * @param pvUser Opaque user data (Pointer to async I/O manager instance). + */ +static DECLCALLBACK(int) rtAioMgrWorker(RTTHREAD hThreadSelf, void *pvUser) +{ + PRTAIOMGRINT pThis = (PRTAIOMGRINT)pvUser; + bool fRunning = true; + int rc = VINF_SUCCESS; + + do + { + uint32_t cReqsCompleted = 0; + RTFILEAIOREQ ahReqsCompleted[32]; + rc = RTFileAioCtxWait(pThis->hAioCtx, 1, RT_INDEFINITE_WAIT, &ahReqsCompleted[0], + RT_ELEMENTS(ahReqsCompleted), &cReqsCompleted); + if (rc == VERR_INTERRUPTED) + { + /* Process external event. */ + rtAioMgrProcessBlockingEvent(pThis); + rc = rtAioMgrCheckFiles(pThis); + } + else if (RT_FAILURE(rc)) + { + /* Something bad happened. */ + /** @todo: */ + } + else + { + /* Requests completed. */ + for (uint32_t i = 0; i < cReqsCompleted; i++) + rtAioMgrReqComplete(pThis, ahReqsCompleted[i]); + + /* Check files for new requests and queue waiting requests. */ + rc = rtAioMgrCheckFiles(pThis); + } + } while ( fRunning + && RT_SUCCESS(rc)); + + return rc; +} + +/** + * Wakes up the async I/O manager. + * + * @returns IPRT status code. + * @param pThis The async I/O manager. + */ +static int rtAioMgrWakeup(PRTAIOMGRINT pThis) +{ + return RTFileAioCtxWakeup(pThis->hAioCtx); +} + +/** + * Waits until the async I/O manager handled the given event. + * + * @returns IPRT status code. + * @param pThis The async I/O manager. + * @param enmEvent The event to pass to the manager. + */ +static int rtAioMgrWaitForBlockingEvent(PRTAIOMGRINT pThis, RTAIOMGREVENT enmEvent) +{ + Assert(pThis->enmBlockingEvent == RTAIOMGREVENT_NO_EVENT); + ASMAtomicWriteU32((volatile uint32_t *)&pThis->enmBlockingEvent, enmEvent); + + /* Wakeup the async I/O manager */ + int rc = rtAioMgrWakeup(pThis); + if (RT_FAILURE(rc)) + return rc; + + /* Wait for completion. */ + rc = RTSemEventWait(pThis->hEventSemBlock, RT_INDEFINITE_WAIT); + AssertRC(rc); + + ASMAtomicWriteU32((volatile uint32_t *)&pThis->enmBlockingEvent, RTAIOMGREVENT_NO_EVENT); + + return rc; +} + +/** + * Add a given file to the given I/O manager. + * + * @returns IPRT status code. + * @param pThis The async I/O manager. + * @param pFile The file to add. + */ +static int rtAioMgrAddFile(PRTAIOMGRINT pThis, PRTAIOMGRFILEINT pFile) +{ + /* Update the assigned I/O manager. */ + ASMAtomicWritePtr(&pFile->pAioMgr, pThis); + + int rc = RTCritSectEnter(&pThis->CritSectBlockingEvent); + AssertRCReturn(rc, rc); + + ASMAtomicWritePtr(&pThis->BlockingEventData.pFileAdd, pFile); + rc = rtAioMgrWaitForBlockingEvent(pThis, RTAIOMGREVENT_FILE_ADD); + ASMAtomicWriteNullPtr(&pThis->BlockingEventData.pFileAdd); + + RTCritSectLeave(&pThis->CritSectBlockingEvent); + return rc; +} + +/** + * Removes a given file from the given I/O manager. + * + * @returns IPRT status code. + * @param pThis The async I/O manager. + * @param pFile The file to remove. + */ +static int rtAioMgrCloseFile(PRTAIOMGRINT pThis, PRTAIOMGRFILEINT pFile) +{ + int rc = RTCritSectEnter(&pThis->CritSectBlockingEvent); + AssertRCReturn(rc, rc); + + ASMAtomicWritePtr(&pThis->BlockingEventData.pFileClose, pFile); + rc = rtAioMgrWaitForBlockingEvent(pThis, RTAIOMGREVENT_FILE_CLOSE); + ASMAtomicWriteNullPtr(&pThis->BlockingEventData.pFileClose); + + RTCritSectLeave(&pThis->CritSectBlockingEvent); + + return rc; +} + +/** + * Process a shutdown event. + * + * @returns IPRT status code. + * @param pThis The async I/O manager to shut down. + */ +static int rtAioMgrShutdown(PRTAIOMGRINT pThis) +{ + int rc = RTCritSectEnter(&pThis->CritSectBlockingEvent); + AssertRCReturn(rc, rc); + + rc = rtAioMgrWaitForBlockingEvent(pThis, RTAIOMGREVENT_SHUTDOWN); + RTCritSectLeave(&pThis->CritSectBlockingEvent); + + return rc; +} + +/** + * Destroys an async I/O manager. + * + * @returns nothing. + * @param pThis The async I/O manager instance to destroy. + */ +static void rtAioMgrDestroy(PRTAIOMGRINT pThis) +{ + int rc; + + rc = rtAioMgrShutdown(pThis); + AssertRC(rc); + + rc = RTThreadWait(pThis->hThread, RT_INDEFINITE_WAIT, NULL); + AssertRC(rc); + + rc = RTFileAioCtxDestroy(pThis->hAioCtx); + AssertRC(rc); + + rc = RTMemCacheDestroy(pThis->hMemCacheReqs); + AssertRC(rc); + + pThis->hThread = NIL_RTTHREAD; + pThis->hAioCtx = NIL_RTFILEAIOCTX; + pThis->hMemCacheReqs = NIL_RTMEMCACHE; + pThis->u32Magic = ~RTAIOMGR_MAGIC; + RTCritSectDelete(&pThis->CritSectBlockingEvent); + RTSemEventDestroy(pThis->hEventSemBlock); + RTMemFree(pThis); +} + +/** + * Queues a new request for processing. + */ +static void rtAioMgrFileQueueReq(PRTAIOMGRFILEINT pThis, PRTAIOMGRREQ pReq) +{ + RTAioMgrFileRetain(pThis); + RTQueueAtomicInsert(&pThis->QueueReqs, &pReq->WorkItem); + rtAioMgrWakeup(pThis->pAioMgr); +} + +/** + * Destroys an async I/O manager file. + * + * @returns nothing. + * @param pThis The async I/O manager file. + */ +static void rtAioMgrFileDestroy(PRTAIOMGRFILEINT pThis) +{ + pThis->u32Magic = ~RTAIOMGRFILE_MAGIC; + rtAioMgrCloseFile(pThis->pAioMgr, pThis); + RTAioMgrRelease(pThis->pAioMgr); + RTMemFree(pThis); +} + +/** + * Queues a new I/O request. + * + * @returns IPRT status code. + * @param hAioMgrFile The I/O manager file handle. + * @param off Start offset of the I/o request. + * @param pSgBuf Data S/G buffer. + * @param cbIo How much to transfer. + * @param pvUser Opaque user data. + * @param enmType I/O direction type (read/write). + */ +static int rtAioMgrFileIoReqCreate(RTAIOMGRFILE hAioMgrFile, RTFOFF off, PRTSGBUF pSgBuf, + size_t cbIo, void *pvUser, RTAIOMGRREQTYPE enmType) +{ + int rc; + PRTAIOMGRFILEINT pFile = hAioMgrFile; + PRTAIOMGRINT pAioMgr; + + AssertPtrReturn(pFile, VERR_INVALID_HANDLE); + pAioMgr = pFile->pAioMgr; + + PRTAIOMGRREQ pReq = rtAioMgrReqAlloc(pAioMgr); + if (RT_LIKELY(pReq)) + { + unsigned cSeg = 1; + size_t cbSeg = RTSgBufSegArrayCreate(pSgBuf, &pReq->DataSeg, &cSeg, cbIo); + + if (cbSeg == cbIo) + { + pReq->enmType = enmType; + pReq->pFile = pFile; + pReq->pvUser = pvUser; + pReq->off = off; + rtAioMgrFileQueueReq(pFile, pReq); + rc = VERR_FILE_AIO_IN_PROGRESS; + } + else + { + /** @todo: Real S/G buffer support. */ + rtAioMgrReqFree(pAioMgr, pReq); + rc = VERR_NOT_SUPPORTED; + } + } + else + rc = VERR_NO_MEMORY; + + return rc; +} + +/** + * Request constructor for the memory cache. + * + * @returns IPRT status code. + * @param hMemCache The cache handle. + * @param pvObj The memory object that should be initialized. + * @param pvUser The user argument. + */ +static DECLCALLBACK(int) rtAioMgrReqCtor(RTMEMCACHE hMemCache, void *pvObj, void *pvUser) +{ + PRTAIOMGRREQ pReq = (PRTAIOMGRREQ)pvObj; + + memset(pReq, 0, sizeof(RTAIOMGRREQ)); + return RTFileAioReqCreate(&pReq->hReqIo); +} + +/** + * Request destructor for the memory cache. + * + * @param hMemCache The cache handle. + * @param pvObj The memory object that should be destroyed. + * @param pvUser The user argument. + */ +static DECLCALLBACK(void) rtAioMgrReqDtor(RTMEMCACHE hMemCache, void *pvObj, void *pvUser) +{ + PRTAIOMGRREQ pReq = (PRTAIOMGRREQ)pvObj; + int rc = RTFileAioReqDestroy(pReq->hReqIo); + + AssertRC(rc); +} + +RTDECL(int) RTAioMgrCreate(PRTAIOMGR phAioMgr, uint32_t cReqsMax) +{ + int rc = VINF_SUCCESS; + PRTAIOMGRINT pThis; + + AssertPtrReturn(phAioMgr, VERR_INVALID_POINTER); + AssertReturn(cReqsMax > 0, VERR_INVALID_PARAMETER); + + pThis = (PRTAIOMGRINT)RTMemAllocZ(sizeof(RTAIOMGRINT)); + if (pThis) + { + pThis->u32Magic = RTAIOMGR_MAGIC; + pThis->cRefs = 1; + pThis->enmBlockingEvent = RTAIOMGREVENT_NO_EVENT; + RTListInit(&pThis->ListFiles); + rc = RTCritSectInit(&pThis->CritSectBlockingEvent); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventCreate(&pThis->hEventSemBlock); + if (RT_SUCCESS(rc)) + { + rc = RTMemCacheCreate(&pThis->hMemCacheReqs, sizeof(RTAIOMGRREQ), + 0, UINT32_MAX, rtAioMgrReqCtor, rtAioMgrReqDtor, NULL, 0); + if (RT_SUCCESS(rc)) + { + rc = RTFileAioCtxCreate(&pThis->hAioCtx, cReqsMax == UINT32_MAX + ? RTFILEAIO_UNLIMITED_REQS + : cReqsMax, + RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS); + if (RT_SUCCESS(rc)) + { + rc = RTThreadCreateF(&pThis->hThread, rtAioMgrWorker, pThis, 0, RTTHREADTYPE_IO, + RTTHREADFLAGS_WAITABLE, "AioMgr-%u", cReqsMax); + if (RT_FAILURE(rc)) + { + rc = RTFileAioCtxDestroy(pThis->hAioCtx); + AssertRC(rc); + } + } + + if (RT_FAILURE(rc)) + RTMemCacheDestroy(pThis->hMemCacheReqs); + } + + if (RT_FAILURE(rc)) + RTSemEventDestroy(pThis->hEventSemBlock); + } + + if (RT_FAILURE(rc)) + RTCritSectDelete(&pThis->CritSectBlockingEvent); + } + + if (RT_FAILURE(rc)) + RTMemFree(pThis); + } + else + rc = VERR_NO_MEMORY; + + if (RT_SUCCESS(rc)) + *phAioMgr = pThis; + + return rc; +} + +RTDECL(uint32_t) RTAioMgrRetain(RTAIOMGR hAioMgr) +{ + PRTAIOMGRINT pThis = hAioMgr; + AssertReturn(hAioMgr != NIL_RTAIOMGR, UINT32_MAX); + AssertPtrReturn(pThis, UINT32_MAX); + AssertReturn(pThis->u32Magic == RTAIOMGR_MAGIC, UINT32_MAX); + + uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs); + AssertMsg(cRefs > 1 && cRefs < _1G, ("%#x %p\n", cRefs, pThis)); + return cRefs; +} + +RTDECL(uint32_t) RTAioMgrRelease(RTAIOMGR hAioMgr) +{ + PRTAIOMGRINT pThis = hAioMgr; + if (pThis == NIL_RTAIOMGR) + return 0; + AssertPtrReturn(pThis, UINT32_MAX); + AssertReturn(pThis->u32Magic == RTAIOMGR_MAGIC, UINT32_MAX); + + uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs); + AssertMsg(cRefs < _1G, ("%#x %p\n", cRefs, pThis)); + if (cRefs == 0) + rtAioMgrDestroy(pThis); + return cRefs; +} + +RTDECL(int) RTAioMgrFileCreate(RTAIOMGR hAioMgr, RTFILE hFile, PFNRTAIOMGRREQCOMPLETE pfnReqComplete, + void *pvUser, PRTAIOMGRFILE phAioMgrFile) +{ + int rc = VINF_SUCCESS; + PRTAIOMGRFILEINT pThis; + + AssertReturn(hAioMgr != NIL_RTAIOMGR, VERR_INVALID_HANDLE); + AssertReturn(hFile != NIL_RTFILE, VERR_INVALID_HANDLE); + AssertPtrReturn(pfnReqComplete, VERR_INVALID_POINTER); + AssertPtrReturn(phAioMgrFile, VERR_INVALID_POINTER); + + pThis = (PRTAIOMGRFILEINT)RTMemAllocZ(sizeof(RTAIOMGRFILEINT)); + if (pThis) + { + pThis->u32Magic = RTAIOMGRFILE_MAGIC; + pThis->cRefs = 1; + pThis->hFile = hFile; + pThis->pAioMgr = hAioMgr; + pThis->pvUser = pvUser; + pThis->pfnReqCompleted = pfnReqComplete; + RTQueueAtomicInit(&pThis->QueueReqs); + RTListInit(&pThis->AioMgr.ListWaitingReqs); + RTAioMgrRetain(hAioMgr); + rc = RTFileAioCtxAssociateWithFile(pThis->pAioMgr->hAioCtx, hFile); + if (RT_FAILURE(rc)) + rtAioMgrFileDestroy(pThis); + else + rtAioMgrAddFile(pThis->pAioMgr, pThis); + } + else + rc = VERR_NO_MEMORY; + + if (RT_SUCCESS(rc)) + *phAioMgrFile = pThis; + + return rc; +} + +RTDECL(uint32_t) RTAioMgrFileRetain(RTAIOMGRFILE hAioMgrFile) +{ + PRTAIOMGRFILEINT pThis = hAioMgrFile; + AssertReturn(hAioMgrFile != NIL_RTAIOMGRFILE, UINT32_MAX); + AssertPtrReturn(pThis, UINT32_MAX); + AssertReturn(pThis->u32Magic == RTAIOMGRFILE_MAGIC, UINT32_MAX); + + uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs); + AssertMsg(cRefs > 1 && cRefs < _1G, ("%#x %p\n", cRefs, pThis)); + return cRefs; +} + +RTDECL(uint32_t) RTAioMgrFileRelease(RTAIOMGRFILE hAioMgrFile) +{ + PRTAIOMGRFILEINT pThis = hAioMgrFile; + if (pThis == NIL_RTAIOMGRFILE) + return 0; + AssertPtrReturn(pThis, UINT32_MAX); + AssertReturn(pThis->u32Magic == RTAIOMGRFILE_MAGIC, UINT32_MAX); + + uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs); + AssertMsg(cRefs < _1G, ("%#x %p\n", cRefs, pThis)); + if (cRefs == 0) + rtAioMgrFileDestroy(pThis); + return cRefs; +} + +RTDECL(void *) RTAioMgrFileGetUser(RTAIOMGRFILE hAioMgrFile) +{ + PRTAIOMGRFILEINT pThis = hAioMgrFile; + + AssertPtrReturn(pThis, NULL); + return pThis->pvUser; +} + +RTDECL(int) RTAioMgrFileRead(RTAIOMGRFILE hAioMgrFile, RTFOFF off, + PRTSGBUF pSgBuf, size_t cbRead, void *pvUser) +{ + return rtAioMgrFileIoReqCreate(hAioMgrFile, off, pSgBuf, cbRead, pvUser, + RTAIOMGRREQTYPE_READ); +} + +RTDECL(int) RTAioMgrFileWrite(RTAIOMGRFILE hAioMgrFile, RTFOFF off, + PRTSGBUF pSgBuf, size_t cbWrite, void *pvUser) +{ + return rtAioMgrFileIoReqCreate(hAioMgrFile, off, pSgBuf, cbWrite, pvUser, + RTAIOMGRREQTYPE_WRITE); +} + +RTDECL(int) RTAioMgrFileFlush(RTAIOMGRFILE hAioMgrFile, void *pvUser) +{ + PRTAIOMGRFILEINT pFile = hAioMgrFile; + PRTAIOMGRINT pAioMgr; + + AssertPtrReturn(pFile, VERR_INVALID_HANDLE); + + pAioMgr = pFile->pAioMgr; + + PRTAIOMGRREQ pReq = rtAioMgrReqAlloc(pAioMgr); + if (RT_UNLIKELY(!pReq)) + return VERR_NO_MEMORY; + + pReq->pFile = pFile; + pReq->enmType = RTAIOMGRREQTYPE_FLUSH; + pReq->pvUser = pvUser; + rtAioMgrFileQueueReq(pFile, pReq); + + return VERR_FILE_AIO_IN_PROGRESS; +} + diff --git a/src/VBox/Runtime/common/misc/assert.cpp b/src/VBox/Runtime/common/misc/assert.cpp index d69a12b4..991fa0be 100644 --- a/src/VBox/Runtime/common/misc/assert.cpp +++ b/src/VBox/Runtime/common/misc/assert.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -137,10 +137,12 @@ RTDECL(void) RTAssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFi #else /* !IN_RING0 */ # if !defined(IN_RING3) && !defined(LOG_NO_COM) +# if 0 /* Enable this iff you have a COM port and really want this debug info. */ RTLogComPrintf("\n!!Assertion Failed!!\n" "Expression: %s\n" "Location : %s(%d) %s\n", pszExpr, pszFile, uLine, pszFunction); +# endif # endif PRTLOGGER pLog = RTLogRelDefaultInstance(); @@ -245,9 +247,11 @@ static void rtAssertMsg2Worker(bool fInitial, const char *pszFormat, va_list va) #else /* !IN_RING0 */ # if !defined(IN_RING3) && !defined(LOG_NO_COM) +# if 0 /* Enable this iff you have a COM port and really want this debug info. */ va_copy(vaCopy, va); RTLogComPrintfV(pszFormat, vaCopy); va_end(vaCopy); +# endif # endif PRTLOGGER pLog = RTLogRelDefaultInstance(); diff --git a/src/VBox/Runtime/common/misc/buildconfig.cpp b/src/VBox/Runtime/common/misc/buildconfig.cpp index 54e87b39..3509a949 100644 --- a/src/VBox/Runtime/common/misc/buildconfig.cpp +++ b/src/VBox/Runtime/common/misc/buildconfig.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/cidr.cpp b/src/VBox/Runtime/common/misc/cidr.cpp index d64d8e43..802fc01e 100644 --- a/src/VBox/Runtime/common/misc/cidr.cpp +++ b/src/VBox/Runtime/common/misc/cidr.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -37,7 +37,7 @@ #include <iprt/stream.h> -RTDECL(int) RTCidrStrToIPv4(const char *pszAddress, PRTIPV4ADDR pNetwork, PRTIPV4ADDR pNetmask) +RTDECL(int) RTCidrStrToIPv4(const char *pszAddress, PRTNETADDRIPV4 pNetwork, PRTNETADDRIPV4 pNetmask) { uint8_t cBits; uint8_t addr[4]; @@ -110,8 +110,8 @@ RTDECL(int) RTCidrStrToIPv4(const char *pszAddress, PRTIPV4ADDR pNetwork, PRTIPV if ((u32Network & ~u32Netmask) != 0) return VERR_INVALID_PARAMETER; - *pNetmask = u32Netmask; - *pNetwork = u32Network; + pNetmask->u = u32Netmask; + pNetwork->u = u32Network; return VINF_SUCCESS; } RT_EXPORT_SYMBOL(RTCidrStrToIPv4); diff --git a/src/VBox/Runtime/common/misc/getopt.cpp b/src/VBox/Runtime/common/misc/getopt.cpp index f4321404..cf538f20 100644 --- a/src/VBox/Runtime/common/misc/getopt.cpp +++ b/src/VBox/Runtime/common/misc/getopt.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2007-2011 Oracle Corporation + * Copyright (C) 2007-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -27,6 +27,7 @@ /******************************************************************************* * Header Files * *******************************************************************************/ +#include <iprt/cidr.h> #include <iprt/net.h> /* must come before getopt.h */ #include <iprt/getopt.h> #include "internal/iprt.h" @@ -92,8 +93,6 @@ RT_EXPORT_SYMBOL(RTGetOptInit); /** * Converts an stringified IPv4 address into the RTNETADDRIPV4 representation. * - * @todo This should be move to some generic part of the runtime. - * * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on * failure. * @@ -102,32 +101,8 @@ RT_EXPORT_SYMBOL(RTGetOptInit); */ static int rtgetoptConvertIPv4Addr(const char *pszValue, PRTNETADDRIPV4 pAddr) { - char *pszNext; - int rc = RTStrToUInt8Ex(RTStrStripL(pszValue), &pszNext, 10, &pAddr->au8[0]); - if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) - return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - if (*pszNext++ != '.') - return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - - rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[1]); - if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) - return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - if (*pszNext++ != '.') - return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - - rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[2]); - if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) - return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - if (*pszNext++ != '.') + if (RT_FAILURE(RTNetStrToIPv4Addr(pszValue, pAddr))) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - - rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[3]); - if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES) - return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - pszNext = RTStrStripL(pszNext); - if (*pszNext) - return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - return VINF_SUCCESS; } @@ -135,8 +110,6 @@ static int rtgetoptConvertIPv4Addr(const char *pszValue, PRTNETADDRIPV4 pAddr) /** * Converts an stringified Ethernet MAC address into the RTMAC representation. * - * @todo This should be move to some generic part of the runtime. - * * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on * failure. * @@ -145,42 +118,9 @@ static int rtgetoptConvertIPv4Addr(const char *pszValue, PRTNETADDRIPV4 pAddr) */ static int rtgetoptConvertMacAddr(const char *pszValue, PRTMAC pAddr) { - /* - * Not quite sure if I should accept stuff like "08::27:::1" here... - * The code is accepting "::" patterns now, except for for the first - * and last parts. - */ - /* first */ - char *pszNext; - int rc = RTStrToUInt8Ex(RTStrStripL(pszValue), &pszNext, 16, &pAddr->au8[0]); - if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) - return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - if (*pszNext++ != ':') - return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - - /* middle */ - for (unsigned i = 1; i < 5; i++) - { - if (*pszNext == ':') - pAddr->au8[i] = 0; - else - { - rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[i]); - if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) - return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - if (*pszNext != ':') - return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - } - pszNext++; - } - - /* last */ - rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[5]); - if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES) - return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; - pszNext = RTStrStripL(pszNext); - if (*pszNext) + int rc = RTNetStrToMacAddr(pszValue, pAddr); + if (RT_FAILURE(rc)) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; return VINF_SUCCESS; @@ -257,7 +197,7 @@ static PCRTGETOPTDEF rtGetOptSearchLong(const char *pszOption, PCRTGETOPTDEF paO if (!(fFlags & RTGETOPTINIT_FLAGS_NO_STD_OPTS)) for (uint32_t i = 0; i < RT_ELEMENTS(g_aStdOptions); i++) if ( !strcmp(pszOption, g_aStdOptions[i].pszLong) - || ( pOpt->fFlags & RTGETOPT_FLAG_ICASE + || ( g_aStdOptions[i].fFlags & RTGETOPT_FLAG_ICASE && !RTStrICmp(pszOption, g_aStdOptions[i].pszLong))) return &g_aStdOptions[i]; @@ -435,8 +375,17 @@ static int rtGetOptProcessValue(uint32_t fFlags, const char *pszValue, PRTGETOPT pValueUnion->IPv4Addr = Addr; break; } -#if 0 /** @todo CIDR */ -#endif + + case RTGETOPT_REQ_IPV4CIDR: + { + RTNETADDRIPV4 network; + RTNETADDRIPV4 netmask; + if (RT_FAILURE(RTCidrStrToIPv4(pszValue, &network, &netmask))) + return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; + pValueUnion->CidrIPv4.IPv4Network.u = network.u; + pValueUnion->CidrIPv4.IPv4Netmask.u = netmask.u; + break; + } case RTGETOPT_REQ_MACADDR: { @@ -791,8 +740,8 @@ RTDECL(RTEXITCODE) RTGetOptPrintError(int ch, PCRTGETOPTUNION pValueUnion) else if (ch == VERR_GETOPT_UNKNOWN_OPTION) RTMsgError("Unknown option: '%s'", pValueUnion->psz); else if (ch == VERR_GETOPT_INVALID_ARGUMENT_FORMAT) - /** @todo r=klaus not really ideal, as the option isn't available */ - RTMsgError("Invalid argument format: '%s'", pValueUnion->psz); + /** @todo r=klaus not really ideal, as the value isn't available */ + RTMsgError("The value given '%s' has an invalid format.", pValueUnion->pDef->pszLong); else if (pValueUnion->pDef) RTMsgError("%s: %Rrs\n", pValueUnion->pDef->pszLong, ch); else diff --git a/src/VBox/Runtime/common/misc/getoptargv.cpp b/src/VBox/Runtime/common/misc/getoptargv.cpp index 651b6f43..8f749e17 100644 --- a/src/VBox/Runtime/common/misc/getoptargv.cpp +++ b/src/VBox/Runtime/common/misc/getoptargv.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/handletable.cpp b/src/VBox/Runtime/common/misc/handletable.cpp index 80eb2387..375e79db 100644 --- a/src/VBox/Runtime/common/misc/handletable.cpp +++ b/src/VBox/Runtime/common/misc/handletable.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -57,6 +57,8 @@ RTDECL(int) RTHandleTableCreateEx(PRTHANDLETABLE phHandleTable, uint32_t fFlags, *phHandleTable = NIL_RTHANDLETABLE; AssertPtrNullReturn(pfnRetain, VERR_INVALID_POINTER); AssertReturn(!(fFlags & ~RTHANDLETABLE_FLAGS_MASK), VERR_INVALID_PARAMETER); + AssertReturn(RT_BOOL(fFlags & RTHANDLETABLE_FLAGS_LOCKED) + RT_BOOL(fFlags & RTHANDLETABLE_FLAGS_LOCKED_IRQ_SAFE) < 2, + VERR_INVALID_PARAMETER); AssertReturn(cMax > 0, VERR_INVALID_PARAMETER); AssertReturn(UINT32_MAX - cMax >= uBase, VERR_INVALID_PARAMETER); @@ -100,9 +102,13 @@ RTDECL(int) RTHandleTableCreateEx(PRTHANDLETABLE phHandleTable, uint32_t fFlags, pThis->cLevel1 = cLevel1 < RTHT_LEVEL1_DYN_ALLOC_THRESHOLD ? cLevel1 : 0; pThis->iFreeHead = NIL_RTHT_INDEX; pThis->iFreeTail = NIL_RTHT_INDEX; - if (fFlags & RTHANDLETABLE_FLAGS_LOCKED) + if (fFlags & (RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_LOCKED_IRQ_SAFE)) { - int rc = RTSpinlockCreate(&pThis->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "RTHandleTableCreateEx"); + int rc; + if (fFlags & RTHANDLETABLE_FLAGS_LOCKED_IRQ_SAFE) + rc = RTSpinlockCreate(&pThis->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTHandleTableCreateEx"); + else + rc = RTSpinlockCreate(&pThis->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "RTHandleTableCreateEx"); if (RT_FAILURE(rc)) { RTMemFree(pThis); diff --git a/src/VBox/Runtime/common/misc/handletable.h b/src/VBox/Runtime/common/misc/handletable.h index 65448397..6e76463a 100644 --- a/src/VBox/Runtime/common/misc/handletable.h +++ b/src/VBox/Runtime/common/misc/handletable.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -222,9 +222,7 @@ DECLINLINE(PRTHTENTRYCTX) rtHandleTableLookupWithCtx(PRTHANDLETABLEINT pThis, ui DECLINLINE(void) rtHandleTableLock(PRTHANDLETABLEINT pThis) { if (pThis->hSpinlock != NIL_RTSPINLOCK) - { RTSpinlockAcquire(pThis->hSpinlock); - } } diff --git a/src/VBox/Runtime/common/misc/handletablectx.cpp b/src/VBox/Runtime/common/misc/handletablectx.cpp index 9da5b144..b4d5bfcd 100644 --- a/src/VBox/Runtime/common/misc/handletablectx.cpp +++ b/src/VBox/Runtime/common/misc/handletablectx.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/handletablesimple.cpp b/src/VBox/Runtime/common/misc/handletablesimple.cpp index 36f2a8fc..2969dacc 100644 --- a/src/VBox/Runtime/common/misc/handletablesimple.cpp +++ b/src/VBox/Runtime/common/misc/handletablesimple.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/http.cpp b/src/VBox/Runtime/common/misc/http.cpp new file mode 100644 index 00000000..52baa39e --- /dev/null +++ b/src/VBox/Runtime/common/misc/http.cpp @@ -0,0 +1,550 @@ +/* $Id: http.cpp $ */ +/** @file + * IPRT - HTTP communication API. + */ + +/* + * Copyright (C) 2012-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include <iprt/http.h> +#include "internal/iprt.h" + +#include <iprt/assert.h> +#include <iprt/env.h> +#include <iprt/err.h> +#include <iprt/mem.h> +#include <iprt/string.h> +#include <iprt/file.h> +#include <iprt/stream.h> + +#include <curl/curl.h> +#include <openssl/ssl.h> +#include "internal/magics.h" + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +typedef struct RTHTTPINTERNAL +{ + /** magic value */ + uint32_t u32Magic; + /** cURL handle */ + CURL *pCurl; + long lLastResp; + /** custom headers */ + struct curl_slist *pHeaders; + /** CA certificate for HTTPS authentication check */ + char *pcszCAFile; + /** abort the current HTTP request if true */ + bool fAbort; +} RTHTTPINTERNAL; +typedef RTHTTPINTERNAL *PRTHTTPINTERNAL; + +typedef struct RTHTTPMEMCHUNK +{ + char *pszMem; + size_t cb; +} RTHTTPMEMCHUNK; +typedef RTHTTPMEMCHUNK *PRTHTTPMEMCHUNK; + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +#define CURL_FAILED(rcCurl) (RT_UNLIKELY(rcCurl != CURLE_OK)) + +/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */ +#define RTHTTP_VALID_RETURN_RC(hHttp, rcCurl) \ + do { \ + AssertPtrReturn((hHttp), (rcCurl)); \ + AssertReturn((hHttp)->u32Magic == RTHTTP_MAGIC, (rcCurl)); \ + } while (0) + +/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */ +#define RTHTTP_VALID_RETURN(hHTTP) RTHTTP_VALID_RETURN_RC((hHttp), VERR_INVALID_HANDLE) + +/** Validates a handle and returns (void) if not valid. */ +#define RTHTTP_VALID_RETURN_VOID(hHttp) \ + do { \ + AssertPtrReturnVoid(hHttp); \ + AssertReturnVoid((hHttp)->u32Magic == RTHTTP_MAGIC); \ + } while (0) + + +RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp) +{ + AssertPtrReturn(phHttp, VERR_INVALID_PARAMETER); + + CURLcode rcCurl = curl_global_init(CURL_GLOBAL_ALL); + if (CURL_FAILED(rcCurl)) + return VERR_HTTP_INIT_FAILED; + + CURL *pCurl = curl_easy_init(); + if (!pCurl) + return VERR_HTTP_INIT_FAILED; + + PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)RTMemAllocZ(sizeof(RTHTTPINTERNAL)); + if (!pHttpInt) + return VERR_NO_MEMORY; + + pHttpInt->u32Magic = RTHTTP_MAGIC; + pHttpInt->pCurl = pCurl; + + *phHttp = (RTHTTP)pHttpInt; + + return VINF_SUCCESS; +} + +RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp) +{ + if (!hHttp) + return; + + PRTHTTPINTERNAL pHttpInt = hHttp; + RTHTTP_VALID_RETURN_VOID(pHttpInt); + + pHttpInt->u32Magic = RTHTTP_MAGIC_DEAD; + + curl_easy_cleanup(pHttpInt->pCurl); + + if (pHttpInt->pHeaders) + curl_slist_free_all(pHttpInt->pHeaders); + + if (pHttpInt->pcszCAFile) + RTStrFree(pHttpInt->pcszCAFile); + + RTMemFree(pHttpInt); + + curl_global_cleanup(); +} + +static DECLCALLBACK(size_t) rtHttpWriteData(void *pvBuf, size_t cb, size_t n, void *pvUser) +{ + PRTHTTPMEMCHUNK pMem = (PRTHTTPMEMCHUNK)pvUser; + size_t cbAll = cb * n; + + pMem->pszMem = (char*)RTMemRealloc(pMem->pszMem, pMem->cb + cbAll + 1); + if (pMem->pszMem) + { + memcpy(&pMem->pszMem[pMem->cb], pvBuf, cbAll); + pMem->cb += cbAll; + pMem->pszMem[pMem->cb] = '\0'; + } + return cbAll; +} + +static DECLCALLBACK(int) rtHttpProgress(void *pData, double DlTotal, double DlNow, + double UlTotal, double UlNow) +{ + PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)pData; + AssertReturn(pHttpInt->u32Magic == RTHTTP_MAGIC, 1); + + return pHttpInt->fAbort ? 1 : 0; +} + +RTR3DECL(int) RTHttpAbort(RTHTTP hHttp) +{ + PRTHTTPINTERNAL pHttpInt = hHttp; + RTHTTP_VALID_RETURN(pHttpInt); + + pHttpInt->fAbort = true; + + return VINF_SUCCESS; +} + +RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp) +{ + PRTHTTPINTERNAL pHttpInt = hHttp; + RTHTTP_VALID_RETURN(pHttpInt); + + /* + * Very limited right now, just enought to make it work for ourselves. + */ + char szProxy[_1K]; + int rc = RTEnvGetEx(RTENV_DEFAULT, "http_proxy", szProxy, sizeof(szProxy), NULL); + if (RT_SUCCESS(rc)) + { + int rcCurl; + if (!strncmp(szProxy, RT_STR_TUPLE("http://"))) + { + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]); + if (CURL_FAILED(rcCurl)) + return VERR_INVALID_PARAMETER; + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, 80); + if (CURL_FAILED(rcCurl)) + return VERR_INVALID_PARAMETER; + } + else + { + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]); + if (CURL_FAILED(rcCurl)) + return VERR_INVALID_PARAMETER; + } + } + else if (rc == VERR_ENV_VAR_NOT_FOUND) + rc = VINF_SUCCESS; + + return rc; +} + +RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pcszProxy, uint32_t uPort, + const char *pcszProxyUser, const char *pcszProxyPwd) +{ + PRTHTTPINTERNAL pHttpInt = hHttp; + RTHTTP_VALID_RETURN(pHttpInt); + AssertPtrReturn(pcszProxy, VERR_INVALID_PARAMETER); + + int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, pcszProxy); + if (CURL_FAILED(rcCurl)) + return VERR_INVALID_PARAMETER; + + if (uPort != 0) + { + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, (long)uPort); + if (CURL_FAILED(rcCurl)) + return VERR_INVALID_PARAMETER; + } + + if (pcszProxyUser && pcszProxyPwd) + { + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYUSERNAME, pcszProxyUser); + if (CURL_FAILED(rcCurl)) + return VERR_INVALID_PARAMETER; + + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPASSWORD, pcszProxyPwd); + if (CURL_FAILED(rcCurl)) + return VERR_INVALID_PARAMETER; + } + + return VINF_SUCCESS; +} + +RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, size_t cHeaders, const char * const *papszHeaders) +{ + PRTHTTPINTERNAL pHttpInt = hHttp; + RTHTTP_VALID_RETURN(pHttpInt); + + if (!cHeaders) + { + if (pHttpInt->pHeaders) + curl_slist_free_all(pHttpInt->pHeaders); + pHttpInt->pHeaders = 0; + return VINF_SUCCESS; + } + + struct curl_slist *pHeaders = NULL; + for (size_t i = 0; i < cHeaders; i++) + pHeaders = curl_slist_append(pHeaders, papszHeaders[i]); + + pHttpInt->pHeaders = pHeaders; + int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_HTTPHEADER, pHeaders); + if (CURL_FAILED(rcCurl)) + return VERR_INVALID_PARAMETER; + + return VINF_SUCCESS; +} + +RTR3DECL(int) RTHttpCertDigest(RTHTTP hHttp, char *pcszCert, size_t cbCert, + uint8_t **pabSha1, size_t *pcbSha1, + uint8_t **pabSha512, size_t *pcbSha512) +{ + int rc = VINF_SUCCESS; + + BIO *cert = BIO_new_mem_buf(pcszCert, (int)cbCert); + if (cert) + { + X509 *crt = NULL; + if (PEM_read_bio_X509(cert, &crt, NULL, NULL)) + { + unsigned cb; + unsigned char md[EVP_MAX_MD_SIZE]; + + int rc1 = X509_digest(crt, EVP_sha1(), md, &cb); + if (rc1 > 0) + { + *pabSha1 = (uint8_t*)RTMemAlloc(cb); + if (*pabSha1) + { + memcpy(*pabSha1, md, cb); + *pcbSha1 = cb; + + rc1 = X509_digest(crt, EVP_sha512(), md, &cb); + if (rc1 > 0) + { + *pabSha512 = (uint8_t*)RTMemAlloc(cb); + if (*pabSha512) + { + memcpy(*pabSha512, md, cb); + *pcbSha512 = cb; + } + else + rc = VERR_NO_MEMORY; + } + else + rc = VERR_HTTP_CACERT_WRONG_FORMAT; + } + else + rc = VERR_NO_MEMORY; + } + else + rc = VERR_HTTP_CACERT_WRONG_FORMAT; + X509_free(crt); + } + else + rc = VERR_HTTP_CACERT_WRONG_FORMAT; + BIO_free(cert); + } + else + rc = VERR_INTERNAL_ERROR; + + if (RT_FAILURE(rc)) + { + RTMemFree(*pabSha512); + RTMemFree(*pabSha1); + } + + return rc; +} + +RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pcszCAFile) +{ + PRTHTTPINTERNAL pHttpInt = hHttp; + RTHTTP_VALID_RETURN(pHttpInt); + + if (pHttpInt->pcszCAFile) + RTStrFree(pHttpInt->pcszCAFile); + pHttpInt->pcszCAFile = RTStrDup(pcszCAFile); + if (!pHttpInt->pcszCAFile) + return VERR_NO_MEMORY; + + return VINF_SUCCESS; +} + + +/** + * Figures out the IPRT status code for a GET. + * + * @returns IPRT status code. + * @param pHttpInt HTTP instance. + * @param rcCurl What curl returned. + */ +static int rtHttpGetCalcStatus(PRTHTTPINTERNAL pHttpInt, int rcCurl) +{ + int rc = VERR_INTERNAL_ERROR; + if (rcCurl == CURLE_OK) + { + curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_RESPONSE_CODE, &pHttpInt->lLastResp); + switch (pHttpInt->lLastResp) + { + case 200: + /* OK, request was fulfilled */ + case 204: + /* empty response */ + rc = VINF_SUCCESS; + break; + case 400: + /* bad request */ + rc = VERR_HTTP_BAD_REQUEST; + break; + case 403: + /* forbidden, authorization will not help */ + rc = VERR_HTTP_ACCESS_DENIED; + break; + case 404: + /* URL not found */ + rc = VERR_HTTP_NOT_FOUND; + break; + } + } + else + { + switch (rcCurl) + { + case CURLE_URL_MALFORMAT: + case CURLE_COULDNT_RESOLVE_HOST: + rc = VERR_HTTP_NOT_FOUND; + break; + case CURLE_COULDNT_CONNECT: + rc = VERR_HTTP_COULDNT_CONNECT; + break; + case CURLE_SSL_CONNECT_ERROR: + rc = VERR_HTTP_SSL_CONNECT_ERROR; + break; + case CURLE_SSL_CACERT: + /* The peer certificate cannot be authenticated with the CA certificates + * set by RTHttpSetCAFile(). We need other or additional CA certificates. */ + rc = VERR_HTTP_CACERT_CANNOT_AUTHENTICATE; + break; + case CURLE_SSL_CACERT_BADFILE: + /* CAcert file (see RTHttpSetCAFile()) has wrong format */ + rc = VERR_HTTP_CACERT_WRONG_FORMAT; + break; + case CURLE_ABORTED_BY_CALLBACK: + /* forcefully aborted */ + rc = VERR_HTTP_ABORTED; + break; + default: + break; + } + } + + return rc; +} + +RTR3DECL(int) RTHttpGet(RTHTTP hHttp, const char *pcszUrl, char **ppszResponse) +{ + PRTHTTPINTERNAL pHttpInt = hHttp; + RTHTTP_VALID_RETURN(pHttpInt); + + pHttpInt->fAbort = false; + + int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pcszUrl); + if (CURL_FAILED(rcCurl)) + return VERR_INVALID_PARAMETER; + +#if 0 + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1); + if (CURL_FAILED(rcCurl)) + return VERR_INVALID_PARAMETER; +#endif + + const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt"; + if (pHttpInt->pcszCAFile) + pcszCAFile = pHttpInt->pcszCAFile; + if (RTFileExists(pcszCAFile)) + { + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile); + if (CURL_FAILED(rcCurl)) + return VERR_INTERNAL_ERROR; + } + + RTHTTPMEMCHUNK chunk = { NULL, 0 }; + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteData); + if (CURL_FAILED(rcCurl)) + return VERR_INTERNAL_ERROR; + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void*)&chunk); + if (CURL_FAILED(rcCurl)) + return VERR_INTERNAL_ERROR; + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress); + if (CURL_FAILED(rcCurl)) + return VERR_INTERNAL_ERROR; + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSDATA, (void*)pHttpInt); + if (CURL_FAILED(rcCurl)) + return VERR_INTERNAL_ERROR; + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_NOPROGRESS, (long)0); + if (CURL_FAILED(rcCurl)) + return VERR_INTERNAL_ERROR; + + rcCurl = curl_easy_perform(pHttpInt->pCurl); + int rc = rtHttpGetCalcStatus(pHttpInt, rcCurl); + *ppszResponse = chunk.pszMem; + + return rc; +} + + +static size_t rtHttpWriteDataToFile(void *pvBuf, size_t cb, size_t n, void *pvUser) +{ + size_t cbAll = cb * n; + RTFILE hFile = (RTFILE)(intptr_t)pvUser; + + size_t cbWritten = 0; + int rc = RTFileWrite(hFile, pvBuf, cbAll, &cbWritten); + if (RT_SUCCESS(rc)) + return cbWritten; + return 0; +} + + +RTR3DECL(int) RTHttpGetFile(RTHTTP hHttp, const char *pszUrl, const char *pszDstFile) +{ + PRTHTTPINTERNAL pHttpInt = hHttp; + RTHTTP_VALID_RETURN(pHttpInt); + + /* + * Set up the request. + */ + pHttpInt->fAbort = false; + + int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pszUrl); + if (CURL_FAILED(rcCurl)) + return VERR_INVALID_PARAMETER; + +#if 0 + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1); + if (CURL_FAILED(rcCurl)) + return VERR_INVALID_PARAMETER; +#endif + + const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt"; + if (pHttpInt->pcszCAFile) + pcszCAFile = pHttpInt->pcszCAFile; + if (RTFileExists(pcszCAFile)) + { + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile); + if (CURL_FAILED(rcCurl)) + return VERR_INTERNAL_ERROR; + } + + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteDataToFile); + if (CURL_FAILED(rcCurl)) + return VERR_INTERNAL_ERROR; + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress); + if (CURL_FAILED(rcCurl)) + return VERR_INTERNAL_ERROR; + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSDATA, (void*)pHttpInt); + if (CURL_FAILED(rcCurl)) + return VERR_INTERNAL_ERROR; + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_NOPROGRESS, (long)0); + if (CURL_FAILED(rcCurl)) + return VERR_INTERNAL_ERROR; + + /* + * Open the output file. + */ + RTFILE hFile; + int rc = RTFileOpen(&hFile, pszDstFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_READWRITE); + if (RT_SUCCESS(rc)) + { + rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void *)(uintptr_t)hFile); + if (!CURL_FAILED(rcCurl)) + { + /* + * Perform the request. + */ + rcCurl = curl_easy_perform(pHttpInt->pCurl); + rc = rtHttpGetCalcStatus(pHttpInt, rcCurl); + } + else + rc = VERR_INTERNAL_ERROR; + + int rc2 = RTFileClose(hFile); + if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) + rc = rc2; + } + + return rc; +} + diff --git a/src/VBox/Runtime/common/misc/lockvalidator.cpp b/src/VBox/Runtime/common/misc/lockvalidator.cpp index 245d5b64..eac25db1 100644 --- a/src/VBox/Runtime/common/misc/lockvalidator.cpp +++ b/src/VBox/Runtime/common/misc/lockvalidator.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009-2010 Oracle Corporation + * Copyright (C) 2009-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -3438,6 +3438,31 @@ RTDECL(void) RTLockValidatorRecSharedInit(PRTLOCKVALRECSHRD pRec, RTLOCKVALCLASS } +RTDECL(int) RTLockValidatorRecSharedCreateV(PRTLOCKVALRECSHRD *ppRec, RTLOCKVALCLASS hClass, + uint32_t uSubClass, void *pvLock, bool fSignaller, bool fEnabled, + const char *pszNameFmt, va_list va) +{ + PRTLOCKVALRECSHRD pRec; + *ppRec = pRec = (PRTLOCKVALRECSHRD)RTMemAlloc(sizeof(*pRec)); + if (!pRec) + return VERR_NO_MEMORY; + RTLockValidatorRecSharedInitV(pRec, hClass, uSubClass, pvLock, fSignaller, fEnabled, pszNameFmt, va); + return VINF_SUCCESS; +} + + +RTDECL(int) RTLockValidatorRecSharedCreate(PRTLOCKVALRECSHRD *ppRec, RTLOCKVALCLASS hClass, + uint32_t uSubClass, void *pvLock, bool fSignaller, bool fEnabled, + const char *pszNameFmt, ...) +{ + va_list va; + va_start(va, pszNameFmt); + int rc = RTLockValidatorRecSharedCreateV(ppRec, hClass, uSubClass, pvLock, fSignaller, fEnabled, pszNameFmt, va); + va_end(va); + return rc; +} + + RTDECL(void) RTLockValidatorRecSharedDelete(PRTLOCKVALRECSHRD pRec) { Assert(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC); @@ -3478,6 +3503,18 @@ RTDECL(void) RTLockValidatorRecSharedDelete(PRTLOCKVALRECSHRD pRec) } +RTDECL(void) RTLockValidatorRecSharedDestroy(PRTLOCKVALRECSHRD *ppRec) +{ + PRTLOCKVALRECSHRD pRec = *ppRec; + *ppRec = NULL; + if (pRec) + { + RTLockValidatorRecSharedDelete(pRec); + RTMemFree(pRec); + } +} + + RTDECL(uint32_t) RTLockValidatorRecSharedSetSubClass(PRTLOCKVALRECSHRD pRec, uint32_t uSubClass) { AssertPtrReturn(pRec, RTLOCKVAL_SUB_CLASS_INVALID); diff --git a/src/VBox/Runtime/common/misc/message.cpp b/src/VBox/Runtime/common/misc/message.cpp index e3657426..643121af 100644 --- a/src/VBox/Runtime/common/misc/message.cpp +++ b/src/VBox/Runtime/common/misc/message.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/once.cpp b/src/VBox/Runtime/common/misc/once.cpp index 0ac8fe42..a3b6f606 100644 --- a/src/VBox/Runtime/common/misc/once.cpp +++ b/src/VBox/Runtime/common/misc/once.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2007 Oracle Corporation + * Copyright (C) 2007-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -31,11 +31,91 @@ #include <iprt/once.h> #include "internal/iprt.h" +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/critsect.h> +#include <iprt/err.h> +#include <iprt/initterm.h> #include <iprt/semaphore.h> #include <iprt/thread.h> -#include <iprt/err.h> -#include <iprt/assert.h> -#include <iprt/asm.h> + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +#ifdef IN_RING3 + +/** For initializing the clean-up list code. */ +static RTONCE g_OnceCleanUp = RTONCE_INITIALIZER; +/** Critical section protecting the clean-up list. */ +static RTCRITSECT g_CleanUpCritSect; +/** The clean-up list. */ +static RTLISTANCHOR g_CleanUpList; + + +/** @callback_method_impl{FNRTTERMCALLBACK} */ +static DECLCALLBACK(void) rtOnceTermCallback(RTTERMREASON enmReason, int32_t iStatus, void *pvUser) +{ + bool const fLazyCleanUpOk = RTTERMREASON_IS_LAZY_CLEANUP_OK(enmReason); + RTCritSectEnter(&g_CleanUpCritSect); /* Potentially dangerous. */ + + PRTONCE pCur, pPrev; + RTListForEachReverseSafe(&g_CleanUpList, pCur, pPrev, RTONCE, CleanUpNode) + { + /* + * Mostly reset it before doing the callback. + * + * Should probably introduce some new states here, but I'm not sure + * it's really worth it at this point. + */ + PFNRTONCECLEANUP pfnCleanUp = pCur->pfnCleanUp; + void *pvUserCleanUp = pCur->pvUser; + pCur->pvUser = NULL; + pCur->pfnCleanUp = NULL; + ASMAtomicWriteS32(&pCur->rc, VERR_WRONG_ORDER); + + pfnCleanUp(pvUserCleanUp, fLazyCleanUpOk); + + /* + * Reset the reset of the state if we're being unloaded or smth. + */ + if (!fLazyCleanUpOk) + { + ASMAtomicWriteS32(&pCur->rc, VERR_INTERNAL_ERROR); + ASMAtomicWriteS32(&pCur->iState, RTONCESTATE_UNINITIALIZED); + } + } + + RTCritSectLeave(&g_CleanUpCritSect); + NOREF(pvUser); NOREF(enmReason); NOREF(iStatus); +} + + + +/** + * Initializes the globals (using RTOnce). + * + * @returns IPRT status code + * @param pvUser Unused. + */ +static DECLCALLBACK(int32_t) rtOnceInitCleanUp(void *pvUser) +{ + NOREF(pvUser); + RTListInit(&g_CleanUpList); + int rc = RTCritSectInit(&g_CleanUpCritSect); + if (RT_SUCCESS(rc)) + { + rc = RTTermRegisterCallback(rtOnceTermCallback, NULL); + if (RT_SUCCESS(rc)) + return rc; + + RTCritSectDelete(&g_CleanUpCritSect); + } + return rc; +} + +#endif /* IN_RING3 */ + /** @@ -156,7 +236,7 @@ static int rtOnceOtherThread(PRTONCE pOnce, PRTSEMEVENTMULTI phEvtM) } -RTDECL(int) RTOnceSlow(PRTONCE pOnce, PFNRTONCE pfnOnce, void *pvUser1, void *pvUser2) +RTDECL(int) RTOnceSlow(PRTONCE pOnce, PFNRTONCE pfnOnce, PFNRTONCECLEANUP pfnCleanUp, void *pvUser) { /* * Validate input (strict builds only). @@ -181,6 +261,21 @@ RTDECL(int) RTOnceSlow(PRTONCE pOnce, PFNRTONCE pfnOnce, void *pvUser1, void *pv || iState == RTONCESTATE_BUSY_HAVE_SEM , VERR_INTERNAL_ERROR); +#ifndef IN_RING3 + AssertReturn(!pfnCleanUp, VERR_NOT_SUPPORTED); +#else /* IN_RING3 */ + + /* + * Make sure our clean-up bits are working if needed later. + */ + if (pfnCleanUp) + { + int rc = RTOnce(&g_OnceCleanUp, rtOnceInitCleanUp, NULL); + if (RT_FAILURE(rc)) + return rc; + } +#endif /* IN_RING3 */ + /* * Do we initialize it? */ @@ -191,9 +286,23 @@ RTDECL(int) RTOnceSlow(PRTONCE pOnce, PFNRTONCE pfnOnce, void *pvUser1, void *pv /* * Yes, so do the execute once stuff. */ - rcOnce = pfnOnce(pvUser1, pvUser2); + rcOnce = pfnOnce(pvUser); ASMAtomicWriteS32(&pOnce->rc, rcOnce); +#ifdef IN_RING3 + /* + * Register clean-up if requested and we were successful. + */ + if (pfnCleanUp && RT_SUCCESS(rcOnce)) + { + RTCritSectEnter(&g_CleanUpCritSect); + pOnce->pfnCleanUp = pfnCleanUp; + pOnce->pvUser = pvUser; + RTListAppend(&g_CleanUpList, &pOnce->CleanUpNode); + RTCritSectLeave(&g_CleanUpCritSect); + } +#endif + /* * If there is a sempahore to signal, we're in for some extra work here. */ @@ -253,10 +362,22 @@ RTDECL(void) RTOnceReset(PRTONCE pOnce) Assert(pOnce->hEventMulti == NIL_RTSEMEVENTMULTI); int32_t iState = ASMAtomicUoReadS32(&pOnce->iState); AssertMsg( iState == RTONCESTATE_DONE - && iState == RTONCESTATE_UNINITIALIZED, + || iState == RTONCESTATE_UNINITIALIZED, ("%d\n", iState)); NOREF(iState); +#ifdef IN_RING3 + /* Unregister clean-up. */ + if (pOnce->pfnCleanUp) + { + RTCritSectEnter(&g_CleanUpCritSect); + RTListNodeRemove(&pOnce->CleanUpNode); + pOnce->pfnCleanUp = NULL; + pOnce->pvUser = NULL; + RTCritSectLeave(&g_CleanUpCritSect); + } +#endif /* IN_RING3 */ + /* Do the same as RTONCE_INITIALIZER does. */ ASMAtomicWriteS32(&pOnce->rc, VERR_INTERNAL_ERROR); ASMAtomicWriteS32(&pOnce->iState, RTONCESTATE_UNINITIALIZED); diff --git a/src/VBox/Runtime/common/misc/req.cpp b/src/VBox/Runtime/common/misc/req.cpp index a137d89d..fa3e0c26 100644 --- a/src/VBox/Runtime/common/misc/req.cpp +++ b/src/VBox/Runtime/common/misc/req.cpp @@ -228,7 +228,7 @@ RT_EXPORT_SYMBOL(RTReqRelease); RTDECL(int) RTReqSubmit(PRTREQ hReq, RTMSINTERVAL cMillies) { - LogFlow(("RTReqQueue: hReq=%p cMillies=%d\n", hReq, cMillies)); + LogFlow(("RTReqSubmit: hReq=%p cMillies=%d\n", hReq, cMillies)); /* * Verify the supplied package. @@ -267,7 +267,7 @@ RTDECL(int) RTReqSubmit(PRTREQ hReq, RTMSINTERVAL cMillies) if (!(fFlags & RTREQFLAGS_NO_WAIT)) rc = RTReqWait(pReq, cMillies); - LogFlow(("RTReqQueue: returns %Rrc\n", rc)); + LogFlow(("RTReqSubmit: returns %Rrc\n", rc)); return rc; } RT_EXPORT_SYMBOL(RTReqSubmit); diff --git a/src/VBox/Runtime/common/misc/reqpool.cpp b/src/VBox/Runtime/common/misc/reqpool.cpp index e7ab2be2..bf63d110 100644 --- a/src/VBox/Runtime/common/misc/reqpool.cpp +++ b/src/VBox/Runtime/common/misc/reqpool.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/reqqueue.cpp b/src/VBox/Runtime/common/misc/reqqueue.cpp index 76fc6235..4d8a6ec3 100644 --- a/src/VBox/Runtime/common/misc/reqqueue.cpp +++ b/src/VBox/Runtime/common/misc/reqqueue.cpp @@ -98,7 +98,7 @@ RT_EXPORT_SYMBOL(RTReqQueueDestroy); RTDECL(int) RTReqQueueProcess(RTREQQUEUE hQueue, RTMSINTERVAL cMillies) { - LogFlow(("RTReqProcess %x\n", hQueue)); + LogFlow(("RTReqQueueProcess %x\n", hQueue)); /* * Check input. @@ -137,7 +137,7 @@ RTDECL(int) RTReqQueueProcess(RTREQQUEUE hQueue, RTMSINTERVAL cMillies) */ PRTREQ pReq = pReqs; if (pReq->pNext) - Log2(("RTReqProcess: 2+ requests: %p %p %p\n", pReq, pReq->pNext, pReq->pNext->pNext)); + Log2(("RTReqQueueProcess: 2+ requests: %p %p %p\n", pReq, pReq->pNext, pReq->pNext->pNext)); pReqs = NULL; while (pReq) { @@ -168,7 +168,7 @@ RTDECL(int) RTReqQueueProcess(RTREQQUEUE hQueue, RTMSINTERVAL cMillies) } } - LogFlow(("RTReqProcess: returns %Rrc\n", rc)); + LogFlow(("RTReqQueueProcess: returns %Rrc\n", rc)); return rc; } RT_EXPORT_SYMBOL(RTReqQueueProcess); @@ -209,7 +209,7 @@ RT_EXPORT_SYMBOL(RTReqQueueCallEx); RTDECL(int) RTReqQueueCallV(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args) { - LogFlow(("RTReqCallV: cMillies=%d fFlags=%#x pfnFunction=%p cArgs=%d\n", cMillies, fFlags, pfnFunction, cArgs)); + LogFlow(("RTReqQueueCallV: cMillies=%d fFlags=%#x pfnFunction=%p cArgs=%d\n", cMillies, fFlags, pfnFunction, cArgs)); /* * Check input. @@ -258,10 +258,10 @@ RTDECL(int) RTReqQueueCallV(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMill if (!(fFlags & RTREQFLAGS_NO_WAIT)) { *ppReq = pReq; - LogFlow(("RTReqCallV: returns %Rrc *ppReq=%p\n", rc, pReq)); + LogFlow(("RTReqQueueCallV: returns %Rrc *ppReq=%p\n", rc, pReq)); } else - LogFlow(("RTReqCallV: returns %Rrc\n", rc)); + LogFlow(("RTReqQueueCallV: returns %Rrc\n", rc)); Assert(rc != VERR_INTERRUPTED); return rc; } diff --git a/src/VBox/Runtime/common/misc/sanity-c.c b/src/VBox/Runtime/common/misc/sanity-c.c index 042cf383..61b1dddb 100644 --- a/src/VBox/Runtime/common/misc/sanity-c.c +++ b/src/VBox/Runtime/common/misc/sanity-c.c @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2007 Oracle Corporation + * Copyright (C) 2007-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/sanity-cpp.cpp b/src/VBox/Runtime/common/misc/sanity-cpp.cpp index ea0202d9..e6464288 100644 --- a/src/VBox/Runtime/common/misc/sanity-cpp.cpp +++ b/src/VBox/Runtime/common/misc/sanity-cpp.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2007 Oracle Corporation + * Copyright (C) 2007-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/sanity.h b/src/VBox/Runtime/common/misc/sanity.h index f0461c42..89151389 100644 --- a/src/VBox/Runtime/common/misc/sanity.h +++ b/src/VBox/Runtime/common/misc/sanity.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2007 Oracle Corporation + * Copyright (C) 2007-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/semspingpong.cpp b/src/VBox/Runtime/common/misc/semspingpong.cpp index e13bed82..10633147 100644 --- a/src/VBox/Runtime/common/misc/semspingpong.cpp +++ b/src/VBox/Runtime/common/misc/semspingpong.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/setjmp.asm b/src/VBox/Runtime/common/misc/setjmp.asm index 9bacbbc4..f4960d98 100644 --- a/src/VBox/Runtime/common/misc/setjmp.asm +++ b/src/VBox/Runtime/common/misc/setjmp.asm @@ -4,7 +4,7 @@ ; ; -; Copyright (C) 2006-2009 Oracle Corporation +; Copyright (C) 2006-2010 Oracle Corporation ; ; This file is part of VirtualBox Open Source Edition (OSE), as ; available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Runtime/common/misc/sg.cpp b/src/VBox/Runtime/common/misc/sg.cpp index fe089b81..2866722d 100644 --- a/src/VBox/Runtime/common/misc/sg.cpp +++ b/src/VBox/Runtime/common/misc/sg.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -31,6 +31,7 @@ #include <iprt/sg.h> #include <iprt/string.h> #include <iprt/assert.h> +#include <iprt/asm.h> static void *sgBufGet(PRTSGBUF pSgBuf, size_t *pcbData) @@ -46,7 +47,7 @@ static void *sgBufGet(PRTSGBUF pSgBuf, size_t *pcbData) return NULL; } - AssertReleaseMsg( pSgBuf->cbSegLeft <= 5 * _1M + AssertReleaseMsg( pSgBuf->cbSegLeft <= 32 * _1M && (uintptr_t)pSgBuf->pvSegCur >= (uintptr_t)pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg && (uintptr_t)pSgBuf->pvSegCur + pSgBuf->cbSegLeft <= (uintptr_t)pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg + pSgBuf->paSegs[pSgBuf->idxSeg].cbSeg, ("pSgBuf->idxSeg=%d pSgBuf->cSegs=%d pSgBuf->pvSegCur=%p pSgBuf->cbSegLeft=%zd pSgBuf->paSegs[%d].pvSeg=%p pSgBuf->paSegs[%d].cbSeg=%zd\n", @@ -314,7 +315,7 @@ RTDECL(size_t) RTSgBufCopyToBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy) } -RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy) +RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, const void *pvBuf, size_t cbCopy) { AssertPtrReturn(pSgBuf, 0); AssertPtrReturn(pvBuf, 0); @@ -332,7 +333,7 @@ RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy) memcpy(pvDst, pvBuf, cbThisCopy); cbLeft -= cbThisCopy; - pvBuf = (void *)((uintptr_t)pvBuf + cbThisCopy); + pvBuf = (const void *)((uintptr_t)pvBuf + cbThisCopy); } return cbCopy - cbLeft; @@ -421,3 +422,52 @@ RTDECL(size_t) RTSgBufSegArrayCreate(PRTSGBUF pSgBuf, PRTSGSEG paSeg, unsigned * return cb; } +RTDECL(bool) RTSgBufIsZero(PRTSGBUF pSgBuf, size_t cbCheck) +{ + bool fIsZero = true; + size_t cbLeft = cbCheck; + RTSGBUF SgBufTmp; + + RTSgBufClone(&SgBufTmp, pSgBuf); + + while (cbLeft) + { + size_t cbThisCheck = cbLeft; + void *pvBuf = sgBufGet(&SgBufTmp, &cbThisCheck); + + if (!cbThisCheck) + break; + + /* Use optimized inline assembler if possible. */ + if ( !(cbThisCheck % 4) + && (cbThisCheck * 8 <= UINT32_MAX)) + { + if (ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbThisCheck * 8) != -1) + { + fIsZero = false; + break; + } + } + else + { + for (unsigned i = 0; i < cbThisCheck; i++) + { + char *pbBuf = (char *)pvBuf; + if (*pbBuf) + { + fIsZero = false; + break; + } + pvBuf = pbBuf + 1; + } + + if (!fIsZero) + break; + } + + cbLeft -= cbThisCheck; + } + + return fIsZero; +} + diff --git a/src/VBox/Runtime/common/misc/term.cpp b/src/VBox/Runtime/common/misc/term.cpp index 7b789df8..7a7fb765 100644 --- a/src/VBox/Runtime/common/misc/term.cpp +++ b/src/VBox/Runtime/common/misc/term.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -76,10 +76,9 @@ static PRTTERMCALLBACKREC g_pCallbackHead = NULL; * Initializes the globals. * * @returns IPRT status code - * @param pvUser1 Ignored. - * @param pvUser2 Ignored. + * @param pvUser Ignored. */ -static DECLCALLBACK(int32_t) rtTermInitOnce(void *pvUser1, void *pvUser2) +static DECLCALLBACK(int32_t) rtTermInitOnce(void *pvUser) { RTSEMFASTMUTEX hFastMutex; int rc; @@ -92,8 +91,7 @@ static DECLCALLBACK(int32_t) rtTermInitOnce(void *pvUser1, void *pvUser2) if (RT_SUCCESS(rc)) g_hFastMutex = hFastMutex; - NOREF(pvUser1); - NOREF(pvUser2); + NOREF(pvUser); return rc; } @@ -110,7 +108,7 @@ RTDECL(int) RTTermRegisterCallback(PFNRTTERMCALLBACK pfnCallback, void *pvUser) */ AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER); - rc = RTOnce(&g_InitTermCallbacksOnce, rtTermInitOnce, NULL, NULL); + rc = RTOnce(&g_InitTermCallbacksOnce, rtTermInitOnce, NULL); if (RT_FAILURE(rc)) return rc; diff --git a/src/VBox/Runtime/common/misc/thread.cpp b/src/VBox/Runtime/common/misc/thread.cpp index f1d4b1d2..1be4a458 100644 --- a/src/VBox/Runtime/common/misc/thread.cpp +++ b/src/VBox/Runtime/common/misc/thread.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -185,6 +185,20 @@ DECLHIDDEN(int) rtThreadInit(void) } +#ifdef IN_RING3 +/** + * Called when IPRT was first initialized in unobtrusive mode and later changed + * to obtrustive. + * + * This is only applicable in ring-3. + */ +DECLHIDDEN(void) rtThreadReInitObtrusive(void) +{ + rtThreadNativeReInitObtrusive(); +} +#endif + + /** * Terminates the thread database. */ |