Index: trunk/src/VBox/Runtime/r0drv/nt/semevent-r0drv-nt.cpp
===================================================================
--- trunk/src/VBox/Runtime/r0drv/nt/semevent-r0drv-nt.cpp	(revision 32708)
+++ trunk/src/VBox/Runtime/r0drv/nt/semevent-r0drv-nt.cpp	(revision 33038)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -26,5 +26,4 @@
 
 
-
 /*******************************************************************************
 *   Header Files                                                               *
@@ -32,8 +31,11 @@
 #include "the-nt-kernel.h"
 #include <iprt/semaphore.h>
-#include <iprt/alloc.h>
+
+#include <iprt/asm.h>
 #include <iprt/assert.h>
-#include <iprt/asm.h>
 #include <iprt/err.h>
+#include <iprt/lockvalidator.h>
+#include <iprt/mem.h>
+#include <iprt/time.h>
 
 #include "internal/magics.h"
@@ -50,4 +52,6 @@
     /** Magic value (RTSEMEVENT_MAGIC). */
     uint32_t volatile   u32Magic;
+    /** Reference counter. */
+    uint32_t volatile   cRefs;
     /** The NT Event object. */
     KEVENT              Event;
@@ -67,12 +71,38 @@
 
     PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)RTMemAlloc(sizeof(*pThis));
-    if (!pThis)
-        return VERR_NO_MEMORY;
-
-    pThis->u32Magic = RTSEMEVENT_MAGIC;
-    KeInitializeEvent(&pThis->Event, SynchronizationEvent, FALSE);
-
-    *phEventSem = pThis;
-    return VINF_SUCCESS;
+    if (pThis)
+    {
+        pThis->u32Magic = RTSEMEVENT_MAGIC;
+        pThis->cRefs    = 1;
+        KeInitializeEvent(&pThis->Event, SynchronizationEvent, FALSE);
+
+        *phEventSem = pThis;
+        return VINF_SUCCESS;
+    }
+    return VERR_NO_MEMORY;
+}
+
+
+/**
+ * Retains a reference to the semaphore.
+ *
+ * @param   pThis       The semaphore to retain.
+ */
+DECLINLINE(void) rtR0SemEventNtRetain(PRTSEMEVENTINTERNAL pThis)
+{
+    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+    Assert(cRefs < 100000); NOREF(cRefs);
+}
+
+
+/**
+ * Releases a reference to the semaphore.
+ *
+ * @param   pThis       The semaphore to release
+ */
+DECLINLINE(void) rtR0SemEventNtRelease(PRTSEMEVENTINTERNAL pThis)
+{
+    if (ASMAtomicDecU32(&pThis->cRefs) == 0)
+        RTMemFree(pThis);
 }
 
@@ -94,10 +124,10 @@
     ASMAtomicIncU32(&pThis->u32Magic);
     KeSetEvent(&pThis->Event, 0xfff, FALSE);
-    RTMemFree(pThis);
+    rtR0SemEventNtRelease(pThis);
     return VINF_SUCCESS;
 }
 
 
-RTDECL(int)  RTSemEventSignal(RTSEMEVENT hEventSem)
+RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
 {
     /*
@@ -107,4 +137,5 @@
     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+    rtR0SemEventNtRetain(pThis);
 
     /*
@@ -112,16 +143,59 @@
      */
     KeSetEvent(&pThis->Event, 1, FALSE);
+
+    rtR0SemEventNtRelease(pThis);
     return VINF_SUCCESS;
 }
 
 
-static int rtSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies, bool fInterruptible)
+
+/**
+ * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug.
+ *
+ * @returns VBox status code.
+ * @param   pThis           The event semaphore.
+ * @param   fFlags          See RTSemEventWaitEx.
+ * @param   uTimeout        See RTSemEventWaitEx.
+ * @param   pSrcPos         The source code position of the wait.
+ */
+DECLINLINE(int) rtR0SemEventNtWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
+                                   PCRTLOCKVALSRCPOS pSrcPos)
 {
     /*
      * Validate input.
      */
-    PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
-    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
-    AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+    if (!pThis)
+        return VERR_INVALID_PARAMETER;
+    AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+    AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+    rtR0SemEventNtRetain(pThis);
+
+    /*
+     * Convert the timeout to a relative one because KeWaitForSingleObject
+     * takes system time instead of interrupt time as input for absolute
+     * timeout specifications.  So, we're best of by giving it relative time.
+     *
+     * Lazy bird converts uTimeout to relative nanoseconds and then to Nt time.
+     */
+    if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
+    {
+        if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
+            uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
+                     ? uTimeout * UINT32_C(1000000)
+                     : UINT64_MAX;
+        if (uTimeout == UINT64_MAX)
+            fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
+        else
+        {
+            if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)
+            {
+                uint64_t u64Now = RTTimeSystemNanoTS();
+                uTimeout = u64Now < uTimeout
+                         ? uTimeout - u64Now
+                         : 0;
+            }
+        }
+    }
+
 
     /*
@@ -130,42 +204,63 @@
      */
     NTSTATUS        rcNt;
+    BOOLEAN         fInterruptible = !!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE);
     KPROCESSOR_MODE WaitMode   = fInterruptible ? UserMode : KernelMode;
-    if (cMillies == RT_INDEFINITE_WAIT)
+    if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
         rcNt = KeWaitForSingleObject(&pThis->Event, Executive, WaitMode, fInterruptible, NULL);
     else
     {
         LARGE_INTEGER Timeout;
-        Timeout.QuadPart = -(int64_t)cMillies * 10000;
+        Timeout.QuadPart = -(int64_t)(uTimeout / 100);
         rcNt = KeWaitForSingleObject(&pThis->Event, Executive, WaitMode, fInterruptible, &Timeout);
     }
-    switch (rcNt)
-    {
-        case STATUS_SUCCESS:
-            if (pThis->u32Magic == RTSEMEVENT_MAGIC)
-                return VINF_SUCCESS;
-            return VERR_SEM_DESTROYED;
-        case STATUS_ALERTED:
-            return VERR_INTERRUPTED;
-        case STATUS_USER_APC:
-            return VERR_INTERRUPTED;
-        case STATUS_TIMEOUT:
-            return VERR_TIMEOUT;
-        default:
-            AssertMsgFailed(("pThis->u32Magic=%RX32 pThis=%p: wait returned %lx!\n",
-                             pThis->u32Magic, pThis, (long)rcNt));
-            return VERR_INTERNAL_ERROR;
-    }
-}
-
-
-RTDECL(int)  RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
-{
-    return rtSemEventWait(hEventSem, cMillies, false /* fInterruptible */);
-}
-
-
-RTDECL(int)  RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
-{
-    return rtSemEventWait(hEventSem, cMillies, true /* fInterruptible */);
-}
-
+    int rc;
+    if (pThis->u32Magic == RTSEMEVENT_MAGIC)
+    {
+        switch (rcNt)
+        {
+            case STATUS_SUCCESS:
+                rc = VINF_SUCCESS;
+                break;
+            case STATUS_ALERTED:
+                rc = VERR_INTERRUPTED;
+                break;
+            case STATUS_USER_APC:
+                rc = VERR_INTERRUPTED;
+                break;
+            case STATUS_TIMEOUT:
+                rc = VERR_TIMEOUT;
+                break;
+            default:
+                AssertMsgFailed(("pThis->u32Magic=%RX32 pThis=%p: wait returned %lx!\n",
+                                 pThis->u32Magic, pThis, (long)rcNt));
+                rc = VERR_INTERNAL_ERROR_4;
+                break;
+        }
+    }
+    else
+        rc = VERR_SEM_DESTROYED;
+
+    rtR0SemEventNtRelease(pThis);
+    return rc;
+}
+
+
+#undef RTSemEventWaitEx
+RTDECL(int)  RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout)
+{
+#ifndef RTSEMEVENT_STRICT
+    return rtR0SemEventNtWait(hEventSem, fFlags, uTimeout, NULL);
+#else
+    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+    return rtR0SemEventNtWait(hEventSem, fFlags, uTimeout, &SrcPos);
+#endif
+}
+
+
+RTDECL(int)  RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout,
+                                   RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
+    return rtR0SemEventNtWait(hEventSem, fFlags, uTimeout, &SrcPos);
+}
+
Index: trunk/src/VBox/Runtime/r0drv/nt/semeventmulti-r0drv-nt.cpp
===================================================================
--- trunk/src/VBox/Runtime/r0drv/nt/semeventmulti-r0drv-nt.cpp	(revision 32708)
+++ trunk/src/VBox/Runtime/r0drv/nt/semeventmulti-r0drv-nt.cpp	(revision 33038)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -31,8 +31,11 @@
 #include "the-nt-kernel.h"
 #include <iprt/semaphore.h>
-#include <iprt/alloc.h>
+
+#include <iprt/asm.h>
 #include <iprt/assert.h>
-#include <iprt/asm.h>
 #include <iprt/err.h>
+#include <iprt/lockvalidator.h>
+#include <iprt/mem.h>
+#include <iprt/time.h>
 
 #include "internal/magics.h"
@@ -49,4 +52,6 @@
     /** Magic value (RTSEMEVENTMULTI_MAGIC). */
     uint32_t volatile   u32Magic;
+    /** Reference counter. */
+    uint32_t volatile   cRefs;
     /** The NT Event object. */
     KEVENT              Event;
@@ -70,4 +75,5 @@
     {
         pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
+        pThis->cRefs    = 1;
         KeInitializeEvent(&pThis->Event, NotificationEvent, FALSE /* not signalled */);
 
@@ -76,4 +82,28 @@
     }
     return VERR_NO_MEMORY;
+}
+
+
+/**
+ * Retains a reference to the semaphore.
+ *
+ * @param   pThis       The semaphore to retain.
+ */
+DECLINLINE(void) rtR0SemEventMultiNtRetain(PRTSEMEVENTMULTIINTERNAL pThis)
+{
+    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+    Assert(cRefs < 100000); NOREF(cRefs);
+}
+
+
+/**
+ * Releases a reference to the semaphore.
+ *
+ * @param   pThis       The semaphore to release
+ */
+DECLINLINE(void) rtR0SemEventMultiNtRelease(PRTSEMEVENTMULTIINTERNAL pThis)
+{
+    if (ASMAtomicDecU32(&pThis->cRefs) == 0)
+        RTMemFree(pThis);
 }
 
@@ -95,5 +125,5 @@
     ASMAtomicIncU32(&pThis->u32Magic);
     KeSetEvent(&pThis->Event, 0xfff, FALSE);
-    RTMemFree(pThis);
+    rtR0SemEventMultiNtRelease(pThis);
     return VINF_SUCCESS;
 }
@@ -110,4 +140,5 @@
     AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+    rtR0SemEventMultiNtRetain(pThis);
 
     /*
@@ -115,4 +146,6 @@
      */
     KeSetEvent(&pThis->Event, 1, FALSE);
+
+    rtR0SemEventMultiNtRelease(pThis);
     return VINF_SUCCESS;
 }
@@ -129,4 +162,5 @@
     AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+    rtR0SemEventMultiNtRetain(pThis);
 
     /*
@@ -134,18 +168,58 @@
      */
     KeResetEvent(&pThis->Event);
+
+    rtR0SemEventMultiNtRelease(pThis);
     return VINF_SUCCESS;
 }
 
 
-static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies, bool fInterruptible)
-{
-    /*
-     * Validate input.
-     */
-    PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
+/**
+ * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
+ *
+ * @returns VBox status code.
+ * @param   pThis           The event semaphore.
+ * @param   fFlags          See RTSemEventMultiWaitEx.
+ * @param   uTimeout        See RTSemEventMultiWaitEx.
+ * @param   pSrcPos         The source code position of the wait.
+ */
+DECLINLINE(int) rtR0SemEventMultiNtWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
+                                        PCRTLOCKVALSRCPOS pSrcPos)
+{
+    /*
+     * Validate input.
+     */
     if (!pThis)
         return VERR_INVALID_PARAMETER;
     AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+    rtR0SemEventMultiNtRetain(pThis);
+
+    /*
+     * Convert the timeout to a relative one because KeWaitForSingleObject
+     * takes system time instead of interrupt time as input for absolute
+     * timeout specifications.  So, we're best of by giving it relative time.
+     *
+     * Lazy bird converts uTimeout to relative nanoseconds and then to Nt time.
+     */
+    if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
+    {
+        if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
+            uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
+                     ? uTimeout * UINT32_C(1000000)
+                     : UINT64_MAX;
+        if (uTimeout == UINT64_MAX)
+            fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
+        else
+        {
+            if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)
+            {
+                uint64_t u64Now = RTTimeSystemNanoTS();
+                uTimeout = u64Now < uTimeout
+                         ? uTimeout - u64Now
+                         : 0;
+            }
+        }
+    }
+
 
     /*
@@ -154,42 +228,63 @@
      */
     NTSTATUS        rcNt;
+    BOOLEAN         fInterruptible = !!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE);
     KPROCESSOR_MODE WaitMode   = fInterruptible ? UserMode : KernelMode;
-    if (cMillies == RT_INDEFINITE_WAIT)
+    if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
         rcNt = KeWaitForSingleObject(&pThis->Event, Executive, WaitMode, fInterruptible, NULL);
     else
     {
         LARGE_INTEGER Timeout;
-        Timeout.QuadPart = -(int64_t)cMillies * 10000;
+        Timeout.QuadPart = -(int64_t)(uTimeout / 100);
         rcNt = KeWaitForSingleObject(&pThis->Event, Executive, WaitMode, fInterruptible, &Timeout);
     }
-    switch (rcNt)
-    {
-        case STATUS_SUCCESS:
-            if (pThis->u32Magic == RTSEMEVENTMULTI_MAGIC)
-                return VINF_SUCCESS;
-            return VERR_SEM_DESTROYED;
-        case STATUS_ALERTED:
-            return VERR_INTERRUPTED;
-        case STATUS_USER_APC:
-            return VERR_INTERRUPTED;
-        case STATUS_TIMEOUT:
-            return VERR_TIMEOUT;
-        default:
-            AssertMsgFailed(("pThis->u32Magic=%RX32 pThis=%p: wait returned %lx!\n",
-                             pThis->u32Magic, pThis, (long)rcNt));
-            return VERR_INTERNAL_ERROR;
-    }
-}
-
-
-RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
-{
-    return rtSemEventMultiWait(hEventMultiSem, cMillies, false /* fInterruptible */);
-}
-
-
-RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
-{
-    return rtSemEventMultiWait(hEventMultiSem, cMillies, true /* fInterruptible */);
-}
-
+    int rc;
+    if (pThis->u32Magic == RTSEMEVENTMULTI_MAGIC)
+    {
+        switch (rcNt)
+        {
+            case STATUS_SUCCESS:
+                rc = VINF_SUCCESS;
+                break;
+            case STATUS_ALERTED:
+                rc = VERR_INTERRUPTED;
+                break;
+            case STATUS_USER_APC:
+                rc = VERR_INTERRUPTED;
+                break;
+            case STATUS_TIMEOUT:
+                rc = VERR_TIMEOUT;
+                break;
+            default:
+                AssertMsgFailed(("pThis->u32Magic=%RX32 pThis=%p: wait returned %lx!\n",
+                                 pThis->u32Magic, pThis, (long)rcNt));
+                rc = VERR_INTERNAL_ERROR_4;
+                break;
+        }
+    }
+    else
+        rc = VERR_SEM_DESTROYED;
+
+    rtR0SemEventMultiNtRelease(pThis);
+    return rc;
+}
+
+
+#undef RTSemEventMultiWaitEx
+RTDECL(int)  RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
+{
+#ifndef RTSEMEVENT_STRICT
+    return rtR0SemEventMultiNtWait(hEventMultiSem, fFlags, uTimeout, NULL);
+#else
+    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+    return rtR0SemEventMultiNtWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
+#endif
+}
+
+
+RTDECL(int)  RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
+                                        RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
+    return rtR0SemEventMultiNtWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
+}
+
