summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime/common/misc
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/common/misc')
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg1Weak.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg2.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg2Add.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg2AddWeak.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg2AddWeakV.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg2Weak.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTAssertMsg2WeakV.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTFileModeToFlags.cpp337
-rw-r--r--src/VBox/Runtime/common/misc/RTFileOpenF.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/RTFileOpenV.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/aiomgr.cpp1314
-rw-r--r--src/VBox/Runtime/common/misc/assert.cpp6
-rw-r--r--src/VBox/Runtime/common/misc/buildconfig.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/cidr.cpp8
-rw-r--r--src/VBox/Runtime/common/misc/getopt.cpp89
-rw-r--r--src/VBox/Runtime/common/misc/getoptargv.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/handletable.cpp12
-rw-r--r--src/VBox/Runtime/common/misc/handletable.h4
-rw-r--r--src/VBox/Runtime/common/misc/handletablectx.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/handletablesimple.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/http.cpp550
-rw-r--r--src/VBox/Runtime/common/misc/lockvalidator.cpp39
-rw-r--r--src/VBox/Runtime/common/misc/message.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/once.cpp135
-rw-r--r--src/VBox/Runtime/common/misc/req.cpp4
-rw-r--r--src/VBox/Runtime/common/misc/reqpool.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/reqqueue.cpp12
-rw-r--r--src/VBox/Runtime/common/misc/sanity-c.c2
-rw-r--r--src/VBox/Runtime/common/misc/sanity-cpp.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/sanity.h2
-rw-r--r--src/VBox/Runtime/common/misc/semspingpong.cpp2
-rw-r--r--src/VBox/Runtime/common/misc/setjmp.asm2
-rw-r--r--src/VBox/Runtime/common/misc/sg.cpp58
-rw-r--r--src/VBox/Runtime/common/misc/term.cpp12
-rw-r--r--src/VBox/Runtime/common/misc/thread.cpp16
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.
*/