Index: /trunk/include/VBox/sup.h
===================================================================
--- /trunk/include/VBox/sup.h	(revision 19865)
+++ /trunk/include/VBox/sup.h	(revision 19866)
@@ -308,4 +308,128 @@
 
 
+/** Event semaphore handle. Ring-0 / ring-3. */
+typedef R0PTRTYPE(struct SUPSEMEVENTHANDLE *) SUPSEMEVENT;
+/** Pointer to an event semaphore handle. */
+typedef SUPSEMEVENT *PSUPSEMEVENT;
+/** Nil event semaphore handle. */
+#define NIL_SUPSEMEVENT         ((SUPSEMEVENT)0)
+
+/**
+ * Creates a single release event semaphore.
+ *
+ * @returns VBox status code.
+ * @param   pSession        The session handle of the caller.
+ * @param   phEvent         Where to return the handle to the event semaphore.
+ */
+SUPDECL(int) SUPSemEventCreate(PSUPDRVSESSION pSession, PSUPSEMEVENT phEvent);
+
+/**
+ * Closes a single release event semaphore handle.
+ *
+ * @returns VBox status code.
+ * @param   pSession            The session handle of the caller.
+ * @param   hEvent              The handle. Nil is quietly ignored.
+ */
+SUPDECL(int) SUPSemEventClose(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent);
+
+/**
+ * Signals a single release event semaphore.
+ *
+ * @returns VBox status code.
+ * @param   pSession            The session handle of the caller.
+ * @param   hEvent              The semaphore handle.
+ */
+SUPDECL(int) SUPSemEventSignal(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent);
+
+#ifdef IN_RING0
+/**
+ * Waits on a single release event semaphore, not interruptible.
+ *
+ * @returns VBox status code.
+ * @param   pSession            The session handle of the caller.
+ * @param   hEvent              The semaphore handle.
+ * @param   cMillies            The number of milliseconds to wait.
+ * @remarks Not available in ring-3.
+ */
+SUPDECL(int) SUPSemEventWait(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies);
+#endif
+
+/**
+ * Waits on a single release event semaphore, interruptible.
+ *
+ * @returns VBox status code.
+ * @param   pSession            The session handle of the caller.
+ * @param   hEvent              The semaphore handle.
+ * @param   cMillies            The number of milliseconds to wait.
+ */
+SUPDECL(int) SUPSemEventWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies);
+
+
+/** Multiple release event semaphore handle. Ring-0 / ring-3. */
+typedef R0PTRTYPE(struct SUPSEMEVENTMULTIHANDLE *)  SUPSEMEVENTMULTI;
+/** Pointer to an multiple release event semaphore handle. */
+typedef SUPSEMEVENTMULTI                           *PSUPSEMEVENTMULTI;
+/** Nil multiple release event semaphore handle. */
+#define NIL_SUPSEMEVENTMULTI                        ((SUPSEMEVENTMULTI)0)
+
+/**
+ * Creates a multiple release event semaphore.
+ *
+ * @returns VBox status code.
+ * @param   pSession        The session handle of the caller.
+ * @param   phEventMulti    Where to return the handle to the event semaphore.
+ */
+SUPDECL(int) SUPSemEventMultiCreate(PSUPDRVSESSION pSession, PSUPSEMEVENTMULTI phEventMulti);
+
+/**
+ * Closes a multiple release event semaphore handle.
+ *
+ * @returns VBox status code.
+ * @param   pSession            The session handle of the caller.
+ * @param   hEventMulti         The handle. Nil is quietly ignored.
+ */
+SUPDECL(int) SUPSemEventMultiClose(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti);
+
+/**
+ * Signals a multiple release event semaphore.
+ *
+ * @returns VBox status code.
+ * @param   pSession            The session handle of the caller.
+ * @param   hEventMulti         The semaphore handle.
+ */
+SUPDECL(int) SUPSemEventMultiSignal(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti);
+
+/**
+ * Resets a multiple release event semaphore.
+ *
+ * @returns VBox status code.
+ * @param   pSession            The session handle of the caller.
+ * @param   hEventMulti         The semaphore handle.
+ */
+SUPDECL(int) SUPSemEventMultiReset(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti);
+
+#ifdef IN_RING0
+/**
+ * Waits on a multiple release event semaphore, not interruptible.
+ *
+ * @returns VBox status code.
+ * @param   pSession            The session handle of the caller.
+ * @param   hEventMulti         The semaphore handle.
+ * @param   cMillies            The number of milliseconds to wait.
+ * @remarks Not available in ring-3.
+ */
+SUPDECL(int) SUPSemEventMultiWait(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies);
+#endif
+
+/**
+ * Waits on a multiple release event semaphore, interruptible.
+ *
+ * @returns VBox status code.
+ * @param   pSession            The session handle of the caller.
+ * @param   hEventMulti         The semaphore handle.
+ * @param   cMillies            The number of milliseconds to wait.
+ */
+SUPDECL(int) SUPSemEventMultiWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies);
+
 
 #ifdef IN_RING3
@@ -858,4 +982,8 @@
     /** Internal network interface. */
     SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE,
+    /** Single release event semaphore. */
+    SUPDRVOBJTYPE_SEM_EVENT,
+    /** Multiple release event semaphore. */
+    SUPDRVOBJTYPE_SEM_EVENT_MULTI,
     /** The first invalid object type in this end. */
     SUPDRVOBJTYPE_END,
Index: /trunk/src/VBox/HostDrivers/Support/SUPDrv.c
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrv.c	(revision 19865)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrv.c	(revision 19866)
@@ -38,11 +38,12 @@
 #endif
 #include <iprt/alloc.h>
+#include <iprt/cpuset.h>
+#include <iprt/handletable.h>
+#include <iprt/mp.h>
+#include <iprt/power.h>
+#include <iprt/process.h>
 #include <iprt/semaphore.h>
 #include <iprt/spinlock.h>
 #include <iprt/thread.h>
-#include <iprt/process.h>
-#include <iprt/mp.h>
-#include <iprt/power.h>
-#include <iprt/cpuset.h>
 #include <iprt/uuid.h>
 #include <VBox/param.h>
@@ -125,4 +126,6 @@
 *   Internal Functions                                                         *
 *******************************************************************************/
+static DECLCALLBACK(int)    supdrvSessionObjHandleRetain(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser);
+static DECLCALLBACK(void)   supdrvSessionObjHandleDelete(RTHANDLETABLE hHandleTable, uint32_t h, void *pvObj, void *pvCtx, void *pvUser);
 static int      supdrvMemAdd(PSUPDRVMEMREF pMem, PSUPDRVSESSION pSession);
 static int      supdrvMemRelease(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, SUPDRVMEMREFTYPE eType);
@@ -178,4 +181,15 @@
 DECLASM(int)    UNWIND_WRAP(SUPR0PageFree)(PSUPDRVSESSION pSession, RTR3PTR pvR3);
 //DECLASM(int)    UNWIND_WRAP(SUPR0Printf)(const char *pszFormat, ...);
+DECLASM(int)    UNWIND_WRAP(SUPSemEventCreate)(PSUPDRVSESSION pSession, PSUPSEMEVENT phEvent);
+DECLASM(int)    UNWIND_WRAP(SUPSemEventClose)(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent);
+DECLASM(int)    UNWIND_WRAP(SUPSemEventSignal)(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent);
+DECLASM(int)    UNWIND_WRAP(SUPSemEventWait)(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies);
+DECLASM(int)    UNWIND_WRAP(SUPSemEventWaitNoResume)(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies);
+DECLASM(int)    UNWIND_WRAP(SUPSemEventMultiCreate)(PSUPDRVSESSION pSession, PSUPSEMEVENTMULTI phEventMulti);
+DECLASM(int)    UNWIND_WRAP(SUPSemEventMultiClose)(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti);
+DECLASM(int)    UNWIND_WRAP(SUPSemEventMultiSignal)(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti);
+DECLASM(int)    UNWIND_WRAP(SUPSemEventMultiReset)(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti);
+DECLASM(int)    UNWIND_WRAP(SUPSemEventMultiWait)(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies);
+DECLASM(int)    UNWIND_WRAP(SUPSemEventMultiWaitNoResume)(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies);
 DECLASM(SUPPAGINGMODE) UNWIND_WRAP(SUPR0GetPagingMode)(void);
 DECLASM(void *) UNWIND_WRAP(RTMemAlloc)(size_t cb) RT_NO_THROW;
@@ -316,4 +330,15 @@
     { "SUPR0PageFree",                          (void *)UNWIND_WRAP(SUPR0PageFree) },
     { "SUPR0Printf",                            (void *)SUPR0Printf }, /** @todo needs wrapping? */
+    { "SUPSemEventCreate",                      (void *)UNWIND_WRAP(SUPSemEventCreate) },
+    { "SUPSemEventClose",                       (void *)UNWIND_WRAP(SUPSemEventClose) },
+    { "SUPSemEventSignal",                      (void *)UNWIND_WRAP(SUPSemEventSignal) },
+    { "SUPSemEventWait",                        (void *)UNWIND_WRAP(SUPSemEventWait) },
+    { "SUPSemEventWaitNoResume",                (void *)UNWIND_WRAP(SUPSemEventWaitNoResume) },
+    { "SUPSemEventMultiCreate",                 (void *)UNWIND_WRAP(SUPSemEventMultiCreate) },
+    { "SUPSemEventMultiClose",                  (void *)UNWIND_WRAP(SUPSemEventMultiClose) },
+    { "SUPSemEventMultiSignal",                 (void *)UNWIND_WRAP(SUPSemEventMultiSignal) },
+    { "SUPSemEventMultiReset",                  (void *)UNWIND_WRAP(SUPSemEventMultiReset) },
+    { "SUPSemEventMultiWait",                   (void *)UNWIND_WRAP(SUPSemEventMultiWait) },
+    { "SUPSemEventMultiWaitNoResume",           (void *)UNWIND_WRAP(SUPSemEventMultiWaitNoResume) },
     { "SUPR0GetPagingMode",                     (void *)UNWIND_WRAP(SUPR0GetPagingMode) },
     { "SUPR0EnableVTx",                         (void *)SUPR0EnableVTx },
@@ -649,30 +674,37 @@
         if (!rc)
         {
-            Assert(pSession->Spinlock != NIL_RTSPINLOCK);
-            pSession->pDevExt           = pDevExt;
-            pSession->u32Cookie         = BIRD_INV;
-            /*pSession->pLdrUsage         = NULL;
-            pSession->pVM               = NULL;
-            pSession->pUsage            = NULL;
-            pSession->pGip              = NULL;
-            pSession->fGipReferenced    = false;
-            pSession->Bundle.cUsed      = 0; */
-            pSession->Uid               = NIL_RTUID;
-            pSession->Gid               = NIL_RTGID;
-            if (fUser)
-            {
-                pSession->Process       = RTProcSelf();
-                pSession->R0Process     = RTR0ProcHandleSelf();
-            }
-            else
-            {
-                pSession->Process       = NIL_RTPROCESS;
-                pSession->R0Process     = NIL_RTR0PROCESS;
-            }
-
-            LogFlow(("Created session %p initial cookie=%#x\n", pSession, pSession->u32Cookie));
-            return VINF_SUCCESS;
-        }
-
+            rc = RTHandleTableCreateEx(&pSession->hHandleTable,
+                                       RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_CONTEXT,
+                                       1 /*uBase*/, 32768 /*cMax*/, supdrvSessionObjHandleRetain, pSession);
+            if (RT_SUCCESS(rc))
+            {
+                Assert(pSession->Spinlock != NIL_RTSPINLOCK);
+                pSession->pDevExt           = pDevExt;
+                pSession->u32Cookie         = BIRD_INV;
+                /*pSession->pLdrUsage         = NULL;
+                pSession->pVM               = NULL;
+                pSession->pUsage            = NULL;
+                pSession->pGip              = NULL;
+                pSession->fGipReferenced    = false;
+                pSession->Bundle.cUsed      = 0; */
+                pSession->Uid               = NIL_RTUID;
+                pSession->Gid               = NIL_RTGID;
+                if (fUser)
+                {
+                    pSession->Process       = RTProcSelf();
+                    pSession->R0Process     = RTR0ProcHandleSelf();
+                }
+                else
+                {
+                    pSession->Process       = NIL_RTPROCESS;
+                    pSession->R0Process     = NIL_RTR0PROCESS;
+                }
+
+                LogFlow(("Created session %p initial cookie=%#x\n", pSession, pSession->u32Cookie));
+                return VINF_SUCCESS;
+            }
+
+            RTSpinlockDestroy(pSession->Spinlock);
+        }
         RTMemFree(pSession);
         *ppSession = NULL;
@@ -721,4 +753,5 @@
 void VBOXCALL supdrvCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
 {
+    int                 rc;
     PSUPDRVBUNDLE       pBundle;
     LogFlow(("supdrvCleanupSession: pSession=%p\n", pSession));
@@ -728,4 +761,11 @@
      */
     RTLogSetDefaultInstanceThread(NULL, (uintptr_t)pSession);
+
+    /*
+     * Destroy the handle table.
+     */
+    rc = RTHandleTableDestroy(pSession->hHandleTable, supdrvSessionObjHandleDelete, pSession);
+    AssertRC(rc);
+    pSession->hHandleTable = NIL_RTHANDLETABLE;
 
     /*
@@ -915,4 +955,41 @@
     }
     Log2(("umapping GIP - done\n"));
+}
+
+
+/**
+ * RTHandleTableDestroy callback used by supdrvCleanupSession.
+ *
+ * @returns IPRT status code, see SUPR0ObjAddRef.
+ * @param   hHandleTable    The handle table handle. Ignored.
+ * @param   pvObj           The object pointer.
+ * @param   pvCtx           Context. NULL.
+ * @param   pvUser          Session pointer.
+ */
+static DECLCALLBACK(int) supdrvSessionObjHandleRetain(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)
+{
+    Assert(!pvCtx);
+    NOREF(pvCtx);
+    NOREF(hHandleTable);
+    return SUPR0ObjAddRef(pvObj, (PSUPDRVSESSION)pvUser);
+}
+
+
+/**
+ * RTHandleTableDestroy callback used by supdrvCleanupSession.
+ *
+ * @param   hHandleTable    The handle table handle. Ignored.
+ * @param   h               The handle value. Ignored.
+ * @param   pvObj           The object pointer.
+ * @param   pvCtx           Context. NULL.
+ * @param   pvUser          Session pointer.
+ */
+static DECLCALLBACK(void) supdrvSessionObjHandleDelete(RTHANDLETABLE hHandleTable, uint32_t h, void *pvObj, void *pvCtx, void *pvUser)
+{
+    Assert(!pvCtx);
+    NOREF(pvCtx);
+    NOREF(h);
+    NOREF(hHandleTable);
+    SUPR0ObjRelease(pvObj, (PSUPDRVSESSION)pvUser);
 }
 
@@ -3180,4 +3257,351 @@
         RTSemFastMutexRelease(pSession->pDevExt->mtxComponentFactory);
     }
+    return rc;
+}
+
+
+/**
+ * Destructor for objects created by SUPSemEventCreate.
+ *
+ * @param   pvObj               The object handle.
+ * @param   pvUser1             The IPRT event handle.
+ * @param   pvUser2             NULL.
+ */
+static DECLCALLBACK(void) supR0SemEventDestructor(void *pvObj, void *pvUser1, void *pvUser2)
+{
+    Assert(pvUser2 == NULL);
+    NOREF(pvObj);
+    RTSemEventDestroy((RTSEMEVENT)pvUser1);
+}
+
+
+SUPDECL(int) SUPSemEventCreate(PSUPDRVSESSION pSession, PSUPSEMEVENT phEvent)
+{
+    int         rc;
+    RTSEMEVENT  hEventReal;
+
+    /*
+     * Input validation.
+     */
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    AssertPtrReturn(phEvent, VERR_INVALID_POINTER);
+
+    /*
+     * Create the event semaphore object.
+     */
+    rc = RTSemEventCreate(&hEventReal);
+    if (RT_SUCCESS(rc))
+    {
+        void *pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_SEM_EVENT, supR0SemEventDestructor, hEventReal, NULL);
+        if (pvObj)
+        {
+            uint32_t h32;
+            rc = RTHandleTableAllocWithCtx(pSession->hHandleTable, pvObj, SUPDRV_HANDLE_CTX_EVENT, &h32);
+            if (RT_SUCCESS(rc))
+            {
+                *phEvent = (SUPSEMEVENT)(uintptr_t)h32;
+                return VINF_SUCCESS;
+            }
+            SUPR0ObjRelease(pvObj, pSession);
+        }
+        else
+            RTSemEventDestroy(hEventReal);
+    }
+    return rc;
+}
+
+
+SUPDECL(int) SUPSemEventClose(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent)
+{
+    uint32_t    h32;
+    PSUPDRVOBJ  pObj;
+
+    /*
+     * Input validation.
+     */
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    if (hEvent == NIL_SUPSEMEVENT)
+        return VINF_SUCCESS;
+    h32 = (uint32_t)(uintptr_t)hEvent;
+    if (h32 != (uintptr_t)hEvent)
+        return VERR_INVALID_HANDLE;
+
+    /*
+     * Do the job.
+     */
+    pObj = (PSUPDRVOBJ)RTHandleTableFreeWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT);
+    if (!pObj)
+        return VERR_INVALID_HANDLE;
+
+    Assert(pObj->cUsage >= 2);
+    SUPR0ObjRelease(pObj, pSession);        /* The free call above. */
+    return SUPR0ObjRelease(pObj, pSession); /* The handle table reference. */
+}
+
+
+SUPDECL(int) SUPSemEventSignal(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent)
+{
+    int         rc;
+    uint32_t    h32;
+    PSUPDRVOBJ  pObj;
+
+    /*
+     * Input validation.
+     */
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    h32 = (uint32_t)(uintptr_t)hEvent;
+    if (h32 != (uintptr_t)hEvent)
+        return VERR_INVALID_HANDLE;
+    pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT);
+    if (!pObj)
+        return VERR_INVALID_HANDLE;
+
+    /*
+     * Do the job.
+     */
+    rc = RTSemEventSignal((RTSEMEVENT)pObj->pvUser1);
+
+    SUPR0ObjRelease(pObj, pSession);
+    return rc;
+}
+
+
+SUPDECL(int) SUPSemEventWait(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies)
+{
+    int         rc;
+    uint32_t    h32;
+    PSUPDRVOBJ  pObj;
+
+    /*
+     * Input validation.
+     */
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    h32 = (uint32_t)(uintptr_t)hEvent;
+    if (h32 != (uintptr_t)hEvent)
+        return VERR_INVALID_HANDLE;
+    pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT);
+    if (!pObj)
+        return VERR_INVALID_HANDLE;
+
+    /*
+     * Do the job.
+     */
+    rc = RTSemEventWait((RTSEMEVENT)pObj->pvUser1, cMillies);
+
+    SUPR0ObjRelease(pObj, pSession);
+    return rc;
+}
+
+
+SUPDECL(int) SUPSemEventWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies)
+{
+    int         rc;
+    uint32_t    h32;
+    PSUPDRVOBJ  pObj;
+
+    /*
+     * Input validation.
+     */
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    h32 = (uint32_t)(uintptr_t)hEvent;
+    if (h32 != (uintptr_t)hEvent)
+        return VERR_INVALID_HANDLE;
+    pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT);
+    if (!pObj)
+        return VERR_INVALID_HANDLE;
+
+    /*
+     * Do the job.
+     */
+    rc = RTSemEventWaitNoResume((RTSEMEVENT)pObj->pvUser1, cMillies);
+
+    SUPR0ObjRelease(pObj, pSession);
+    return rc;
+}
+
+
+/**
+ * Destructor for objects created by SUPSemEventMultiCreate.
+ *
+ * @param   pvObj               The object handle.
+ * @param   pvUser1             The IPRT event handle.
+ * @param   pvUser2             NULL.
+ */
+static DECLCALLBACK(void) supR0SemEventMultiDestructor(void *pvObj, void *pvUser1, void *pvUser2)
+{
+    Assert(pvUser2 == NULL);
+    NOREF(pvObj);
+    RTSemEventMultiDestroy((RTSEMEVENTMULTI)pvUser1);
+}
+
+
+SUPDECL(int) SUPSemEventMultiCreate(PSUPDRVSESSION pSession, PSUPSEMEVENTMULTI phEventMulti)
+{
+    int             rc;
+    RTSEMEVENTMULTI hEventMultReal;
+
+    /*
+     * Input validation.
+     */
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    AssertPtrReturn(phEventMulti, VERR_INVALID_POINTER);
+
+    /*
+     * Create the event semaphore object.
+     */
+    rc = RTSemEventMultiCreate(&hEventMultReal);
+    if (RT_SUCCESS(rc))
+    {
+        void *pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_SEM_EVENT_MULTI, supR0SemEventMultiDestructor, hEventMultReal, NULL);
+        if (pvObj)
+        {
+            uint32_t h32;
+            rc = RTHandleTableAllocWithCtx(pSession->hHandleTable, pvObj, &h32, SUPDRV_HANDLE_CTX_EVENT_MULTI);
+            if (RT_SUCCESS(rc))
+            {
+                *phEventMulti = (SUPSEMEVENTMULTI)(uintptr_t)h32;
+                return VINF_SUCCESS;
+            }
+            SUPR0ObjRelease(pvObj, pSession);
+        }
+        else
+            RTSemEventMultiDestroy(hEventMultReal);
+    }
+    return rc;
+}
+
+
+SUPDECL(int) SUPSemEventMultiClose(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti)
+{
+    uint32_t    h32;
+    PSUPDRVOBJ  pObj;
+
+    /*
+     * Input validation.
+     */
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    if (hEventMulti == NIL_SUPSEMEVENTMULTI)
+        return VINF_SUCCESS;
+    h32 = (uint32_t)(uintptr_t)hEventMulti;
+    if (h32 != (uintptr_t)hEventMulti)
+        return VERR_INVALID_HANDLE;
+
+    /*
+     * Do the job.
+     */
+    pObj = (PSUPDRVOBJ)RTHandleTableFreeWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT_MULTI);
+    if (!pObj)
+        return VERR_INVALID_HANDLE;
+
+    Assert(pObj->cUsage >= 2);
+    SUPR0ObjRelease(pObj, pSession);        /* The free call above. */
+    return SUPR0ObjRelease(pObj, pSession); /* The handle table reference. */
+}
+
+
+SUPDECL(int) SUPSemEventMultiSignal(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti)
+{
+    int         rc;
+    uint32_t    h32;
+    PSUPDRVOBJ  pObj;
+
+    /*
+     * Input validation.
+     */
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    h32 = (uint32_t)(uintptr_t)hEventMulti;
+    if (h32 != (uintptr_t)hEventMulti)
+        return VERR_INVALID_HANDLE;
+    pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT_MULTI);
+    if (!pObj)
+        return VERR_INVALID_HANDLE;
+
+    /*
+     * Do the job.
+     */
+    rc = RTSemEventMultiSignal((RTSEMEVENTMULTI)pObj->pvUser1);
+
+    SUPR0ObjRelease(pObj, pSession);
+    return rc;
+}
+
+
+SUPDECL(int) SUPSemEventMultiReset(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti)
+{
+    int         rc;
+    uint32_t    h32;
+    PSUPDRVOBJ  pObj;
+
+    /*
+     * Input validation.
+     */
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    h32 = (uint32_t)(uintptr_t)hEventMulti;
+    if (h32 != (uintptr_t)hEventMulti)
+        return VERR_INVALID_HANDLE;
+    pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT_MULTI);
+    if (!pObj)
+        return VERR_INVALID_HANDLE;
+
+    /*
+     * Do the job.
+     */
+    rc = RTSemEventMultiReset((RTSEMEVENTMULTI)pObj->pvUser1);
+
+    SUPR0ObjRelease(pObj, pSession);
+    return rc;
+}
+
+
+SUPDECL(int) SUPSemEventMultiWait(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies)
+{
+    int         rc;
+    uint32_t    h32;
+    PSUPDRVOBJ  pObj;
+
+    /*
+     * Input validation.
+     */
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    h32 = (uint32_t)(uintptr_t)hEventMulti;
+    if (h32 != (uintptr_t)hEventMulti)
+        return VERR_INVALID_HANDLE;
+    pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT_MULTI);
+    if (!pObj)
+        return VERR_INVALID_HANDLE;
+
+    /*
+     * Do the job.
+     */
+    rc = RTSemEventMultiWait((RTSEMEVENTMULTI)pObj->pvUser1, cMillies);
+
+    SUPR0ObjRelease(pObj, pSession);
+    return rc;
+}
+
+
+SUPDECL(int) SUPSemEventMultiWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies)
+{
+    int         rc;
+    uint32_t    h32;
+    PSUPDRVOBJ  pObj;
+
+    /*
+     * Input validation.
+     */
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    h32 = (uint32_t)(uintptr_t)hEventMulti;
+    if (h32 != (uintptr_t)hEventMulti)
+        return VERR_INVALID_HANDLE;
+    pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT_MULTI);
+    if (!pObj)
+        return VERR_INVALID_HANDLE;
+
+    /*
+     * Do the job.
+     */
+    rc = RTSemEventMultiWaitNoResume((RTSEMEVENTMULTI)pObj->pvUser1, cMillies);
+
+    SUPR0ObjRelease(pObj, pSession);
     return rc;
 }
Index: /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h	(revision 19865)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h	(revision 19866)
@@ -309,4 +309,14 @@
 
 
+/** @name Context values for the per-session handle tables.
+ * The context value is used to distiguish between the different kinds of
+ * handles, making the handle table API do all the work.
+ * @{ */
+/** Handle context value for single release event handles.  */
+#define SUPDRV_HANDLE_CTX_EVENT         ((void *)(uintptr_t)(SUPDRVOBJTYPE_SEM_EVENT))
+/** Handle context value for multiple release event handles.  */
+#define SUPDRV_HANDLE_CTX_EVENT_MULTI   ((void *)(uintptr_t)(SUPDRVOBJTYPE_SEM_EVENT_MULTI))
+/** @} */
+
 
 /*******************************************************************************
@@ -494,10 +504,11 @@
     uint32_t                        u32Cookie;
 
+    /** The VM associated with the session. */
+    PVM                             pVM;
+    /** Handle table for IPRT semaphore wrapper APIs.
+     * Programmable from R0 and R3. */
+    RTHANDLETABLE                   hHandleTable;
     /** Load usage records. (protected by SUPDRVDEVEXT::mtxLdr) */
     PSUPDRVLDRUSAGE volatile        pLdrUsage;
-    /** The VM associated with the session. */
-    PVM                             pVM;
-    /** List of generic usage records. (protected by SUPDRVDEVEXT::SpinLock) */
-    PSUPDRVUSAGE volatile           pUsage;
 
     /** Spinlock protecting the bundles and the GIP members. */
@@ -509,4 +520,6 @@
     /** Bundle of locked memory objects. */
     SUPDRVBUNDLE                    Bundle;
+    /** List of generic usage records. (protected by SUPDRVDEVEXT::SpinLock) */
+    PSUPDRVUSAGE volatile           pUsage;
 
     /** The user id of the session. (Set by the OS part.) */
Index: /trunk/src/VBox/HostDrivers/Support/SUPR0.def
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPR0.def	(revision 19865)
+++ /trunk/src/VBox/HostDrivers/Support/SUPR0.def	(revision 19866)
@@ -54,4 +54,15 @@
     SUPR0MemFree
     SUPR0Printf
+    SUPSemEventCreate
+    SUPSemEventClose
+    SUPSemEventSignal
+    SUPSemEventWait
+    SUPSemEventWaitNoResume
+    SUPSemEventMultiCreate
+    SUPSemEventMultiClose
+    SUPSemEventMultiSignal
+    SUPSemEventMultiReset
+    SUPSemEventMultiWait
+    SUPSemEventMultiWaitNoResume
     SUPR0GetPagingMode
     SUPR0EnableVTx
Index: /trunk/src/VBox/HostDrivers/Support/linux/Makefile
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/linux/Makefile	(revision 19865)
+++ /trunk/src/VBox/HostDrivers/Support/linux/Makefile	(revision 19866)
@@ -104,4 +104,6 @@
 	common/log/logcom.o \
 	common/log/logformat.o \
+	common/misc/handletable.o \
+	common/misc/handletablectx.o \
 	common/string/strformat.o \
 	common/string/strformatrt.o \
Index: /trunk/src/VBox/HostDrivers/Support/linux/files_vboxdrv
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/linux/files_vboxdrv	(revision 19865)
+++ /trunk/src/VBox/HostDrivers/Support/linux/files_vboxdrv	(revision 19866)
@@ -37,4 +37,5 @@
     ${PATH_ROOT}/include/iprt/err.h=>include/iprt/err.h \
     ${PATH_ROOT}/include/iprt/heap.h=>include/iprt/heap.h \
+    ${PATH_ROOT}/include/iprt/handletable.h=>include/iprt/handletable.h \
     ${PATH_ROOT}/include/iprt/initterm.h=>include/iprt/initterm.h \
     ${PATH_ROOT}/include/iprt/log.h=>include/iprt/log.h \
@@ -81,4 +82,7 @@
     ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/udivdi3.c=>math/gcc/udivdi3.c \
     ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/umoddi3.c=>math/gcc/umoddi3.c \
+    ${PATH_ROOT}/src/VBox/Runtime/common/misc/handletable.cpp=>common/misc/handletable.c \
+    ${PATH_ROOT}/src/VBox/Runtime/common/misc/handletable.h=>common/misc/handletable.h \
+    ${PATH_ROOT}/src/VBox/Runtime/common/misc/handletablectx.cpp=>common/misc/handletablectx.c \
     ${PATH_ROOT}/src/VBox/Runtime/common/string/strformat.cpp=>common/string/strformat.c \
     ${PATH_ROOT}/src/VBox/Runtime/common/string/strformatrt.cpp=>common/string/strformatrt.c \
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPDrvA-win.asm
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPDrvA-win.asm	(revision 19865)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPDrvA-win.asm	(revision 19866)
@@ -75,4 +75,15 @@
 NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPR0PageFree
 ;NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPR0Printf            - cannot wrap this buster.
+NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPSemEventCreate
+NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPSemEventClose
+NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPSemEventSignal
+NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPSemEventWait
+NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPSemEventWaitNoResume
+NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPSemEventMultiCreate
+NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPSemEventMultiClose
+NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPSemEventMultiSignal
+NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPSemEventMultiReset
+NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPSemEventMultiWait
+NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPSemEventMultiWaitNoResume
 NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, SUPR0GetPagingMode
 NtWrapDyn2DrvFunctionWithAllRegParams  supdrvNtWrap, RTMemAlloc
