Index: /trunk/include/iprt/semaphore.h
===================================================================
--- /trunk/include/iprt/semaphore.h	(revision 32945)
+++ /trunk/include/iprt/semaphore.h	(revision 32946)
@@ -46,4 +46,53 @@
  * @{
  */
+
+
+/** @name Generic Semaphore Wait Flags.
+ *
+ * @remarks Exactly one of RTSEMWAIT_FLAGS_RELATIVE and
+ *          RTSEMWAIT_FLAGS_ABSOLUTE must be set, unless
+ *          RTSEMWAIT_FLAGS_INDEFINITE is used.
+ *
+ *          Exactly one of RTSEMWAIT_FLAGS_NANOSECS and
+ *          RTSEMWAIT_FLAGS_MILLISECS must be set, unless
+ *          RTSEMWAIT_FLAGS_INDEFINITE is used.
+ *
+ *          Exactly one of RTSEMWAIT_FLAGS_RESUME and RTSEMWAIT_FLAGS_NORESUME
+ *          must be set.
+ *
+ *          The interruptible vs resume stuff is ring-0 vs ring-3 semantics.
+ *
+ * @{ */
+/** The timeout is relative. */
+#define RTSEMWAIT_FLAGS_RELATIVE            RT_BIT_32(0)
+/** The timeout is absolute. */
+#define RTSEMWAIT_FLAGS_ABSOLUTE            RT_BIT_32(1)
+/** The timeout is specified in nanoseconds. */
+#define RTSEMWAIT_FLAGS_NANOSECS            RT_BIT_32(2)
+/** The timeout is specified in milliseconds. */
+#define RTSEMWAIT_FLAGS_MILLISECS           RT_BIT_32(3)
+/** Indefinite wait.
+ * The relative/absolute and nano-/millisecond flags are ignored. */
+#define RTSEMWAIT_FLAGS_INDEFINITE          RT_BIT_32(4)
+/** Mask covering the time related bits. */
+#define RTSEMWAIT_FLAGS_TIME_MASK           UINT32_C(0x0000001f)
+
+/** Interruptible wait. */
+#define RTSEMWAIT_FLAGS_INTERRUPTIBLE       RT_BIT_32(5)
+/** No automatic resume, same as interruptible. */
+#define RTSEMWAIT_FLAGS_NORESUME            RTSEMWAIT_FLAGS_INTERRUPTIBLE
+/** Uninterruptible wait. */
+#define RTSEMWAIT_FLAGS_UNINTERRUPTIBLE     RT_BIT_32(6)
+/** Resume on interrupt, same as uninterruptible. */
+#define RTSEMWAIT_FLAGS_RESUME              RTSEMWAIT_FLAGS_UNINTERRUPTIBLE
+
+/** Macro for validate the flags. */
+#define RTSEMWAIT_FLAGS_ARE_VALID(fFlags) \
+    (   !((fFlags) & UINT32_C(0xffffff80)) \
+     &&  (  ((fFlags) & RTSEMWAIT_FLAGS_INDEFINITE) \
+          ? ( (((fFlags) & UINT32_C(0x20))) ^ (((fFlags) >> 1) & UINT32_C(0x20)) ) == UINT32_C(0x20) \
+          : ( (((fFlags) & UINT32_C(0x25))) ^ (((fFlags) >> 1) & UINT32_C(0x25)) ) == UINT32_C(0x25) ))
+/** @}  */
+
 
 
@@ -94,5 +143,5 @@
  *
  * @returns iprt status code.
- * @param   hEventSem           Handle of the event sempahore.  NIL_RTSEMEVENT
+ * @param   hEventSem           Handle of the event semaphore.  NIL_RTSEMEVENT
  *                              is quitely ignored (VINF_SUCCESS).
  */
@@ -138,4 +187,37 @@
  */
 RTDECL(int)  RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies);
+
+/**
+ * Extended API for waiting on an event semaphore to be signaled.
+ *
+ * @returns IPRT status code.
+ * @param   hEventSem           The event semaphore to wait on.
+ * @param   fFlags              Combination of RTSEMWAIT_FLAGS_XXX.
+ * @param   uTimeout            The timeout, ignored if
+ *                              RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags.
+ *                              Whether this is absolute or relative,
+ *                              milliseconds or nanoseconds depends on the @a
+ *                              fFlags value.  Do not pass RT_INDEFINITE_WAIT
+ *                              here, use RTSEMWAIT_FLAGS_INDEFINITE instead.
+ */
+RTDECL(int)  RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout);
+
+/**
+ * Debug version of RTSemEventWaitEx that tracks the location.
+ *
+ * @returns IPRT status code, see RTSemEventWaitEx.
+ * @param   hEventSem           The event semaphore to wait on.
+ * @param   fFlags              See RTSemEventWaitEx.
+ * @param   uTimeout            See RTSemEventWaitEx.
+ * @param   uId                 Some kind of locking location ID.  Typically a
+ *                              return address up the stack.  Optional (0).
+ * @param   pszFile             The file where the lock is being acquired from.
+ *                              Optional.
+ * @param   iLine               The line number in that file.  Optional (0).
+ * @param   pszFunction         The function where the lock is being acquired
+ *                              from.  Optional.
+ */
+RTDECL(int)  RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout,
+                                   RTHCUINTPTR uId, RT_SRC_POS_DECL);
 
 /**
@@ -222,5 +304,5 @@
  *
  * @returns iprt status code.
- * @param   hEventMultiSem      The multiple release event sempahore.  NIL is
+ * @param   hEventMultiSem      The multiple release event semaphore.  NIL is
  *                              quietly ignored (VINF_SUCCESS).
  */
@@ -231,5 +313,5 @@
  *
  * @returns iprt status code.
- * @param   hEventMultiSem      The multiple release event sempahore.
+ * @param   hEventMultiSem      The multiple release event semaphore.
  *
  * @remarks ring-0: This works when preemption is disabled.  However it is
@@ -243,5 +325,5 @@
  *
  * @returns iprt status code.
- * @param   hEventMultiSem      The multiple release event sempahore.
+ * @param   hEventMultiSem      The multiple release event semaphore.
  */
 RTDECL(int)  RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem);
@@ -255,10 +337,9 @@
  * @returns iprt status code.
  *          Will not return VERR_INTERRUPTED.
- * @param   hEventMultiSem      The multiple release event sempahore.
+ * @param   hEventMultiSem      The multiple release event semaphore.
  * @param   cMillies            Number of milliseconds to wait.
  */
 RTDECL(int)  RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies);
 
-
 /**
  * Wait for the event multi semaphore to be signaled, return on interruption.
@@ -267,8 +348,42 @@
  *
  * @returns iprt status code.
- * @param   hEventMultiSem      The multiple release event sempahore.
+ * @param   hEventMultiSem      The multiple release event semaphore.
  * @param   cMillies            Number of milliseconds to wait.
  */
 RTDECL(int)  RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies);
+
+/**
+ * Extended API for waiting on an event semaphore to be signaled.
+ *
+ * @returns IPRT status code.
+ * @param   hEventMultiSem      The multiple release event semaphore to wait
+ *                              on.
+ * @param   fFlags              Combination of the RTSEMWAIT_FLAGS_XXX.
+ * @param   uTimeout            The timeout, ignored if
+ *                              RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags.
+ *                              Whether this is absolute or relative,
+ *                              milliseconds or nanoseconds depends on the @a
+ *                              fFlags value.  Do not pass RT_INDEFINITE_WAIT
+ *                              here, use RTSEMWAIT_FLAGS_INDEFINITE instead.
+ */
+RTDECL(int)  RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout);
+
+/**
+ * Debug version of RTSemEventMultiWaitEx that tracks the location.
+
+ * @returns IPRT status code, see RTSemEventMultiWaitEx.
+ * @param   hEventMultiSem      The multiple release event semaphore handle.
+ * @param   fFlags              See RTSemEventMultiWaitEx.
+ * @param   uTimeout            See RTSemEventMultiWaitEx.
+ * @param   uId                 Some kind of locking location ID.  Typically a
+ *                              return address up the stack.  Optional (0).
+ * @param   pszFile             The file where the lock is being acquired from.
+ *                              Optional.
+ * @param   iLine               The line number in that file.  Optional (0).
+ * @param   pszFunction         The function where the lock is being acquired
+ *                              from.  Optional.
+ */
+RTDECL(int)  RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
+                                        RTHCUINTPTR uId, RT_SRC_POS_DECL);
 
 /**
@@ -370,5 +485,5 @@
  * Changes the lock validator sub-class of the mutex semaphore.
  *
- * It is recommended to try make sure that nobody is using this sempahore while
+ * It is recommended to try make sure that nobody is using this semaphore while
  * changing the value.
  *
@@ -425,5 +540,5 @@
  *                              Optional.
  * @param   iLine               The line number in that file.  Optional (0).
- * @param   pszFunction         The functionn where the lock is being acquired
+ * @param   pszFunction         The function where the lock is being acquired
  *                              from.  Optional.
  */
@@ -441,8 +556,45 @@
  *                              Optional.
  * @param   iLine               The line number in that file.  Optional (0).
- * @param   pszFunction         The functionn where the lock is being acquired
+ * @param   pszFunction         The function where the lock is being acquired
  *                              from.  Optional.
  */
 RTDECL(int)  RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL);
+
+/**
+ * Request ownership of a mutex semaphore, extended edition.
+ *
+ * The same thread may request a mutex semaphore multiple times,
+ * a nested counter is kept to make sure it's released on the right
+ * RTSemMutexRelease() call.
+ *
+ * @returns iprt status code.
+ * @param   hMutexSem           The mutex semaphore to request ownership over.
+ * @param   fFlags              Combination of the RTSEMWAIT_FLAGS_XXX.
+ * @param   uTimeout            The timeout, ignored if
+ *                              RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags.
+ *                              Whether this is absolute or relative,
+ *                              milliseconds or nanoseconds depends on the @a
+ *                              fFlags value.  Do not pass RT_INDEFINITE_WAIT
+ *                              here, use RTSEMWAIT_FLAGS_INDEFINITE instead.
+ */
+RTDECL(int)  RTSemMutexRequestEx(RTSEMMUTEX hMutexSem, uint32_t fFlags, uint64_t uTimeout);
+
+/**
+ * Debug version of RTSemMutexRequestEx that tracks the location.
+ *
+ * @returns iprt status code.
+ * @param   hMutexSem           The mutex semaphore to request ownership over.
+ * @param   fFlags              See RTSemMutexRequestEx.
+ * @param   uTimeout            See RTSemMutexRequestEx.
+ * @param   uId                 Some kind of locking location ID.  Typically a
+ *                              return address up the stack.  Optional (0).
+ * @param   pszFile             The file where the lock is being acquired from.
+ *                              Optional.
+ * @param   iLine               The line number in that file.  Optional (0).
+ * @param   pszFunction         The function where the lock is being acquired
+ *                              from.  Optional.
+ */
+RTDECL(int)  RTSemMutexRequestExDebug(RTSEMMUTEX hMutexSem, uint32_t fFlags, uint64_t uTimeout,
+                                      RTHCUINTPTR uId, RT_SRC_POS_DECL);
 
 /**
@@ -467,9 +619,11 @@
 #ifdef RT_STRICT
 # ifdef ___iprt_asm_h
-#  define RTSemMutexRequest(pCritSect, cMillies)            RTSemMutexRequestDebug((pCritSect), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
-#  define RTSemMutexRequestNoResume(pCritSect, cMillies)    RTSemMutexRequestNoResumeDebug((pCritSect), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
+#  define RTSemMutexRequest(hMutexSem, cMillies)            RTSemMutexRequestDebug((hMutexSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
+#  define RTSemMutexRequestNoResume(hMutexSem, cMillies)    RTSemMutexRequestNoResumeDebug((hMutexSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
+#  define RTSemMutexRequestEx(hMutexSem, fFlags, uTimeout)  RTSemMutexRequestExDebug((hMutexSem), (fFlags), (uTimeout), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
 # else
-#  define RTSemMutexRequest(pCritSect, cMillies)            RTSemMutexRequestDebug((pCritSect), (cMillies), 0, RT_SRC_POS)
-#  define RTSemMutexRequestNoResume(pCritSect, cMillies)    RTSemMutexRequestNoResumeDebug((pCritSect), (cMillies), 0, RT_SRC_POS)
+#  define RTSemMutexRequest(hMutexSem, cMillies)            RTSemMutexRequestDebug((hMutexSem), (cMillies), 0, RT_SRC_POS)
+#  define RTSemMutexRequestNoResume(hMutexSem, cMillies)    RTSemMutexRequestNoResumeDebug((hMutexSem), (cMillies), 0, RT_SRC_POS)
+#  define RTSemMutexRequestEx(hMutexSem, fFlags, uTimeout)  RTSemMutexRequestExDebug((hMutexSem), (fFlags), (uTimeout), 0, RT_SRC_POS)
 # endif
 #endif
@@ -691,5 +845,5 @@
  * Changes the lock validator sub-class of the read/write semaphore.
  *
- * It is recommended to try make sure that nobody is using this sempahore while
+ * It is recommended to try make sure that nobody is using this semaphore while
  * changing the value.
  *
@@ -743,5 +897,5 @@
  *                              Optional.
  * @param   iLine               The line number in that file.  Optional (0).
- * @param   pszFunction         The functionn where the lock is being acquired
+ * @param   pszFunction         The function where the lock is being acquired
  *                              from.  Optional.
  */
@@ -763,8 +917,52 @@
  *                              Optional.
  * @param   iLine               The line number in that file.  Optional (0).
- * @param   pszFunction         The functionn where the lock is being acquired
+ * @param   pszFunction         The function where the lock is being acquired
  *                              from.  Optional.
  */
 RTDECL(int)   RTSemRWRequestReadNoResumeDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL);
+
+/**
+ * Request read access to a read/write semaphore, extended edition.
+ *
+ * @returns iprt status code.
+ * @retval  VINF_SUCCESS on success.
+ * @retval  VERR_INTERRUPT if the wait was interrupted.
+ * @retval  VERR_TIMEOUT if the wait timed out.
+ * @retval  VERR_INVALID_HANDLE if hRWSem is invalid.
+ *
+ * @param   hRWSem              Handle to the read/write semaphore.
+ * @param   fFlags              Combination of the RTSEMWAIT_FLAGS_XXX.
+ * @param   uTimeout            The timeout, ignored if
+ *                              RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags.
+ *                              Whether this is absolute or relative,
+ *                              milliseconds or nanoseconds depends on the @a
+ *                              fFlags value.  Do not pass RT_INDEFINITE_WAIT
+ *                              here, use RTSEMWAIT_FLAGS_INDEFINITE instead.
+ */
+RTDECL(int)   RTSemRWRequestReadEx(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout);
+
+
+/**
+ * Debug version of RTSemRWRequestReadEx that tracks the location.
+ *
+ * @returns iprt status code.
+ * @retval  VINF_SUCCESS on success.
+ * @retval  VERR_INTERRUPT if the wait was interrupted.
+ * @retval  VERR_TIMEOUT if the wait timed out.
+ * @retval  VERR_INVALID_HANDLE if hRWSem is invalid.
+ *
+ * @param   hRWSem              Handle to the read/write semaphore.
+ * @param   fFlags              See RTSemRWRequestReadEx.
+ * @param   uTimeout            See RTSemRWRequestReadEx.
+ * @param   uId                 Some kind of locking location ID.  Typically a
+ *                              return address up the stack.  Optional (0).
+ * @param   pszFile             The file where the lock is being acquired from.
+ *                              Optional.
+ * @param   iLine               The line number in that file.  Optional (0).
+ * @param   pszFunction         The function where the lock is being acquired
+ *                              from.  Optional.
+ */
+RTDECL(int)   RTSemRWRequestReadExDebug(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout,
+                                        RTHCUINTPTR uId, RT_SRC_POS_DECL);
 
 /**
@@ -816,5 +1014,5 @@
  *                              Optional.
  * @param   iLine               The line number in that file.  Optional (0).
- * @param   pszFunction         The functionn where the lock is being acquired
+ * @param   pszFunction         The function where the lock is being acquired
  *                              from.  Optional.
  */
@@ -832,8 +1030,48 @@
  *                              Optional.
  * @param   iLine               The line number in that file.  Optional (0).
- * @param   pszFunction         The functionn where the lock is being acquired
+ * @param   pszFunction         The function where the lock is being acquired
  *                              from.  Optional.
  */
 RTDECL(int)  RTSemRWRequestWriteNoResumeDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL);
+
+/**
+ * Request write access to a read/write semaphore, extended edition.
+ *
+ * @returns iprt status code.
+ * @retval  VINF_SUCCESS on success.
+ * @retval  VERR_INTERRUPTED if the wait was interrupted.
+ * @retval  VERR_TIMEOUT if the wait timed out.
+ * @retval  VERR_DEADLOCK if the caller owned the read lock.  Do not depend on
+ *          this as it is implementation specific.
+ * @retval  VERR_INVALID_HANDLE if hRWSem is invalid.
+ *
+ * @param   hRWSem              Handle to the read/write semaphore.
+ * @param   fFlags              Combination of the RTSEMWAIT_FLAGS_XXX.
+ * @param   uTimeout            The timeout, ignored if
+ *                              RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags.
+ *                              Whether this is absolute or relative,
+ *                              milliseconds or nanoseconds depends on the @a
+ *                              fFlags value.  Do not pass RT_INDEFINITE_WAIT
+ *                              here, use RTSEMWAIT_FLAGS_INDEFINITE instead.
+ */
+RTDECL(int)   RTSemRWRequestWriteEx(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout);
+
+/**
+ * Debug version of RTSemRWRequestWriteEx that tracks the location.
+ *
+ * @returns IPRT status code, see RTSemRWRequestWriteEx.
+ * @param   hRWSem              Handle to the read/write semaphore.
+ * @param   fFlags              See RTSemRWRequestWriteEx.
+ * @param   uTimeout            See RTSemRWRequestWriteEx.
+ * @param   uId                 Some kind of locking location ID.  Typically a
+ *                              return address up the stack.  Optional (0).
+ * @param   pszFile             The file where the lock is being acquired from.
+ *                              Optional.
+ * @param   iLine               The line number in that file.  Optional (0).
+ * @param   pszFunction         The function where the lock is being acquired
+ *                              from.  Optional.
+ */
+RTDECL(int)  RTSemRWRequestWriteExDebug(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout,
+                                        RTHCUINTPTR uId, RT_SRC_POS_DECL);
 
 /**
@@ -856,5 +1094,5 @@
 
 /**
- * Checks if the caller is one of the read owners of the sempahore.
+ * Checks if the caller is one of the read owners of the semaphore.
  *
  * @note    !CAUTION!  This API doesn't work reliably if lock validation isn't
@@ -906,13 +1144,15 @@
 #ifdef RT_STRICT
 # ifdef ___iprt_asm_h
-#  define RTSemRWRequestRead(pCritSect, cMillies)           RTSemRWRequestReadDebug((pCritSect), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
-#  define RTSemRWRequestReadNoResume(pCritSect, cMillies)   RTSemRWRequestReadNoResumeDebug((pCritSect), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
-#  define RTSemRWRequestWrite(pCritSect, cMillies)          RTSemRWRequestWriteDebug((pCritSect), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
-#  define RTSemRWRequestWriteNoResume(pCritSect, cMillies)  RTSemRWRequestWriteNoResumeDebug((pCritSect), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
+#  define RTSemRWRequestRead(hRWSem, cMillies)              RTSemRWRequestReadDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
+#  define RTSemRWRequestReadNoResume(hRWSem, cMillies)      RTSemRWRequestReadNoResumeDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
+#  define RTSemRWRequestWrite(hRWSem, cMillies)             RTSemRWRequestWriteDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
+#  define RTSemRWRequestWriteNoResume(hRWSem, cMillies)     RTSemRWRequestWriteNoResumeDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
+#  define RTSemRWRequestWriteEx(hRWSem, fFlags, uTimeout)   RTSemRWRequestWriteExDebug((hRWSem), (fFlags), (uTimeout), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
 # else
-#  define RTSemRWRequestRead(pCritSect, cMillies)           RTSemRWRequestReadDebug((pCritSect), (cMillies), 0, RT_SRC_POS)
-#  define RTSemRWRequestReadNoResume(pCritSect, cMillies)   RTSemRWRequestReadNoResumeDebug((pCritSect), (cMillies), 0, RT_SRC_POS)
-#  define RTSemRWRequestWrite(pCritSect, cMillies)          RTSemRWRequestWriteDebug((pCritSect), (cMillies), 0, RT_SRC_POS)
-#  define RTSemRWRequestWriteNoResume(pCritSect, cMillies)  RTSemRWRequestWriteNoResumeDebug((pCritSect), (cMillies), 0, RT_SRC_POS)
+#  define RTSemRWRequestRead(hRWSem, cMillies)              RTSemRWRequestReadDebug((hRWSem), (cMillies), 0, RT_SRC_POS)
+#  define RTSemRWRequestReadNoResume(hRWSem, cMillies)      RTSemRWRequestReadNoResumeDebug((hRWSem), (cMillies), 0, RT_SRC_POS)
+#  define RTSemRWRequestWrite(hRWSem, cMillies)             RTSemRWRequestWriteDebug((hRWSem), (cMillies), 0, RT_SRC_POS)
+#  define RTSemRWRequestWriteNoResume(hRWSem, cMillies)     RTSemRWRequestWriteNoResumeDebug((hRWSem), (cMillies), 0, RT_SRC_POS)
+#  define RTSemRWRequestWriteEx(hRWSem, fFlags, uTimeout)   RTSemRWRequestWriteExDebug((hRWSem), (fFlags), (uTimeout), 0, RT_SRC_POS)
 # endif
 #endif
Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 32945)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 32946)
@@ -545,4 +545,6 @@
  	r3/linux/semeventmulti-linux.cpp \
  	r3/linux/semmutex-linux.cpp
+# 	generic/RTSemEventMultiWait-2-ex-generic.cpp \
+# 	generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp
 else
  RuntimeR3_SOURCES.linux.x86 += \
@@ -553,4 +555,6 @@
  	r3/linux/semevent-linux.cpp \
  	r3/linux/semeventmulti-linux.cpp
+# 	generic/RTSemEventMultiWait-2-ex-generic.cpp \
+# 	generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp
  ifdef RT_NEW_LINUX_MUTEX_CODE
   RuntimeR3_SOURCES.linux.amd64 += \
Index: /trunk/src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp	(revision 32946)
+++ /trunk/src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp	(revision 32946)
@@ -0,0 +1,53 @@
+/* $Id$ */
+/** @file
+ * IPRT - RTSemEventMultiWait, implementation based on RTSemEventMultiWaitEx.
+ */
+
+/*
+ * Copyright (C) 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;
+ * 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                                                               *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_SEM
+#include <iprt/semaphore.h>
+#include "internal/iprt.h"
+
+#include <iprt/err.h>
+#include <iprt/assert.h>
+
+
+#undef RTSemEventMultiWait              /* undo debug mapping */
+RTDECL(int)  RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
+{
+    int rc;
+    if (cMillies == RT_INDEFINITE_WAIT)
+        rc = RTSemEventMultiWaitEx(hEventMultiSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0);
+    else
+        rc = RTSemEventMultiWaitEx(hEventMultiSem,
+                                   RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_MILLISECS,
+                                   cMillies);
+    Assert(rc != VERR_INTERRUPTED);
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiWait);
+
Index: /trunk/src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp	(revision 32946)
+++ /trunk/src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp	(revision 32946)
@@ -0,0 +1,54 @@
+/* $Id$ */
+/** @file
+ * IPRT - RTSemEventMultiWaitNoResume, generic implementation based
+ *        on RTSemEventMultiWaitEx.
+ */
+
+/*
+ * Copyright (C) 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;
+ * 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                                                               *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_SEM
+#include <iprt/semaphore.h>
+#include "internal/iprt.h"
+
+#include <iprt/err.h>
+#include <iprt/assert.h>
+
+
+#undef RTSemEventMultiWaitNoResume          /* undo debug mapping */
+RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
+{
+    int rc;
+    if (cMillies == RT_INDEFINITE_WAIT)
+        rc = RTSemEventMultiWaitEx(hEventMultiSem, RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0);
+    else
+        rc = RTSemEventMultiWaitEx(hEventMultiSem,
+                                   RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_MILLISECS,
+                                   cMillies);
+    Assert(rc != VERR_INTERRUPTED);
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiWaitNoResume);
+
Index: /trunk/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp	(revision 32945)
+++ /trunk/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp	(revision 32946)
@@ -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
@@ -248,14 +248,14 @@
 
 
-static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies, bool fAutoResume)
-{
-    PCRTLOCKVALSRCPOS pSrcPos = NULL;
-
+
+DECLINLINE(int) rtSemEventLnxMultiWait(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, uint64_t uTimeout,
+                                       PCRTLOCKVALSRCPOS pSrcPos)
+{
     /*
      * Validate input.
      */
-    struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
-    AssertReturn(VALID_PTR(pThis) && pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
-                 VERR_INVALID_HANDLE);
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
+    AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
 
     /*
@@ -268,18 +268,40 @@
 
     /*
-     * Convert the timeout value.
+     * Check and convert the timeout value.
      */
     struct timespec ts;
     struct timespec *pTimeout = NULL;
-    uint64_t u64End = 0; /* shut up gcc */
-    if (cMillies != RT_INDEFINITE_WAIT)
+    uint64_t u64Deadline = 0; /* shut up gcc */
+    if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
     {
         /* If the timeout is zero, then we're done. */
-        if (!cMillies)
+        if (!uTimeout)
             return VERR_TIMEOUT;
-        ts.tv_sec  = cMillies / 1000;
-        ts.tv_nsec = (cMillies % 1000) * UINT32_C(1000000);
-        u64End = RTTimeSystemNanoTS() + cMillies * UINT64_C(1000000);
-        pTimeout = &ts;
+
+        /* Convert it to a deadline + interval timespec. */
+        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) /* unofficial way of indicating an indefinite wait */
+        {
+            if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
+                u64Deadline = RTTimeSystemNanoTS();
+            else
+            {
+                uint64_t u64Now = RTTimeSystemNanoTS();
+                if (uTimeout <= u64Now)
+                    return VERR_TIMEOUT;
+                u64Deadline = uTimeout;
+                uTimeout   -= u64Now;
+            }
+            if (   sizeof(ts.tv_sec) >= sizeof(uint64_t)
+                || uTimeout <= UINT64_C(1000000000) * UINT32_MAX)
+            {
+                ts.tv_nsec = uTimeout % UINT32_C(1000000000);
+                ts.tv_sec  = uTimeout / UINT32_C(1000000000);
+                pTimeout = &ts;
+            }
+        }
     }
 
@@ -306,5 +328,5 @@
             if (pTimeout)
             {
-                int64_t i64Diff = u64End - RTTimeSystemNanoTS();
+                int64_t i64Diff = u64Deadline - RTTimeSystemNanoTS();
                 if (i64Diff < 1000)
                     return VERR_TIMEOUT;
@@ -316,5 +338,5 @@
             {
                 int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
-                                                                cMillies, RTTHREADSTATE_EVENT_MULTI, true);
+                                                                uTimeout / UINT32_C(1000000), RTTHREADSTATE_EVENT_MULTI, true);
                 if (RT_FAILURE(rc9))
                     return rc9;
@@ -344,5 +366,5 @@
             else if (rc == -EINTR)
             {
-                if (!fAutoResume)
+                if (fFlags & RTSEMWAIT_FLAGS_NORESUME)
                     return VERR_INTERRUPTED;
             }
@@ -360,15 +382,21 @@
 
 
-RTDECL(int)  RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
-{
-    int rc = rtSemEventMultiWait(hEventMultiSem, cMillies, true);
-    Assert(rc != VERR_INTERRUPTED);
-    return rc;
-}
-
-
-RTDECL(int)  RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
-{
-    return rtSemEventMultiWait(hEventMultiSem, cMillies, false);
+#undef RTSemEventMultiWaitEx
+RTDECL(int)  RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
+{
+#ifndef RTSEMEVENT_STRICT
+    return rtSemEventLnxMultiWait(hEventMultiSem, fFlags, uTimeout, NULL);
+#else
+    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+    return rtSemEventLnxMultiWait(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 rtSemEventLnxMultiWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
 }
 
@@ -411,4 +439,7 @@
 }
 
+#include "../../generic/RTSemEventMultiWait-2-ex-generic.cpp"
+#include "../../generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp"
+
 #endif /* glibc < 2.6 || IPRT_WITH_FUTEX_BASED_SEMS */
 
Index: /trunk/src/VBox/Runtime/testcase/tstSemEvent.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstSemEvent.cpp	(revision 32945)
+++ /trunk/src/VBox/Runtime/testcase/tstSemEvent.cpp	(revision 32946)
@@ -25,16 +25,18 @@
  */
 
+
 /*******************************************************************************
 *   Header Files                                                               *
 *******************************************************************************/
 #include <iprt/semaphore.h>
-#include <iprt/string.h>
-#include <iprt/thread.h>
-#include <iprt/stream.h>
-#include <iprt/time.h>
-#include <iprt/initterm.h>
-#include <iprt/rand.h>
+
 #include <iprt/asm.h>
 #include <iprt/assert.h>
+#include <iprt/rand.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
 
 
@@ -42,106 +44,201 @@
 *   Global Variables                                                           *
 *******************************************************************************/
-static RTSEMEVENTMULTI      g_hSemEM = NIL_RTSEMEVENTMULTI;
-static uint32_t volatile    g_cErrors;
-
-
-int PrintError(const char *pszFormat, ...)
-{
-    ASMAtomicIncU32(&g_cErrors);
-
-    RTPrintf("tstSemEvent: FAILURE - ");
-    va_list va;
-    va_start(va, pszFormat);
-    RTPrintfV(pszFormat, va);
-    va_end(va);
-
-    return 1;
-}
-
-
-int ThreadTest1(RTTHREAD ThreadSelf, void *pvUser)
-{
-    int rc;
-    rc = RTSemEventMultiWait(g_hSemEM, 1000);
-    if (rc != VERR_TIMEOUT)
-    {
-        PrintError("Thread 1: unexpected result of first RTSemEventMultiWait %Rrc\n", rc);
-        return VINF_SUCCESS;
-    }
-
-    rc = RTSemEventMultiWait(g_hSemEM, 1000);
-    if (RT_FAILURE(rc))
-    {
-        PrintError("Thread 1: unexpected result of second RTSemEventMultiWait %Rrc\n", rc);
-        return VINF_SUCCESS;
-    }
-
-    RTPrintf("tstSemEvent: Thread 1 normal exit...\n");
+/** The test handle. */
+static RTTEST  g_hTest;
+
+
+static DECLCALLBACK(int) test1Thread1(RTTHREAD ThreadSelf, void *pvUser)
+{
+    RTSEMEVENTMULTI hSem = *(PRTSEMEVENTMULTI)pvUser;
+
+    uint64_t u64 = RTTimeSystemMilliTS();
+    RTTEST_CHECK_RC_RET(g_hTest, RTSemEventMultiWait(hSem, 1000), VERR_TIMEOUT, rcCheck);
+    u64 = RTTimeSystemMilliTS() - u64;
+    RTTEST_CHECK_MSG(g_hTest, u64 < 1500 && u64 > 950, (g_hTest, "u64=%llu\n", u64));
+
+    RTTEST_CHECK_RC_RET(g_hTest, RTSemEventMultiWait(hSem, 2000), VINF_SUCCESS, rcCheck);
     return VINF_SUCCESS;
 }
 
 
-int ThreadTest2(RTTHREAD ThreadSelf, void *pvUser)
-{
-    int rc;
-    rc = RTSemEventMultiWait(g_hSemEM, RT_INDEFINITE_WAIT);
-    if (RT_FAILURE(rc))
-    {
-        PrintError("Thread 2: unexpected result of RTSemEventMultiWait %Rrc\n", rc);
-        return VINF_SUCCESS;
-    }
-
-    RTPrintf("tstSemEvent: Thread 2 normal exit...\n");
+static DECLCALLBACK(int) test1Thread2(RTTHREAD ThreadSelf, void *pvUser)
+{
+    RTSEMEVENTMULTI hSem = *(PRTSEMEVENTMULTI)pvUser;
+    RTTEST_CHECK_RC_RET(g_hTest, RTSemEventMultiWait(hSem, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
     return VINF_SUCCESS;
 }
 
 
-static int Test1()
-{
-    int rc;
-    RTTHREAD Thread1, Thread2;
-
-    rc = RTSemEventMultiCreate(&g_hSemEM);
-    if (RT_FAILURE(rc))
-        return PrintError("RTSemEventMultiCreate failed (rc=%Rrc)\n", rc);
+static void test1(void)
+{
+    RTTestISub("Three threads");
 
     /*
      * Create the threads and let them block on the event multi semaphore.
      */
-    rc = RTSemEventMultiReset(g_hSemEM);
-    if (RT_FAILURE(rc))
-        return PrintError("RTSemEventMultiReset failed (rc=%Rrc)\n", rc);
-
-    rc = RTThreadCreate(&Thread2, ThreadTest2, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test2");
-    if (RT_FAILURE(rc))
-        return PrintError("RTThreadCreate failed for thread 2 (rc=%Rrc)\n", rc);
+    RTSEMEVENTMULTI hSem;
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiCreate(&hSem), VINF_SUCCESS);
+
+    RTTHREAD hThread2;
+    RTTESTI_CHECK_RC_RETV(RTThreadCreate(&hThread2, test1Thread2, &hSem, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test2"), VINF_SUCCESS);
     RTThreadSleep(100);
 
-    rc = RTThreadCreate(&Thread1, ThreadTest1, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test1");
-    if (RT_FAILURE(rc))
-        return PrintError("RTThreadCreate failed for thread 1 (rc=%Rrc)\n", rc);
+    RTTHREAD hThread1;
+    RTTESTI_CHECK_RC_RETV(RTThreadCreate(&hThread1, test1Thread1, &hSem, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test1"), VINF_SUCCESS);
 
     /* Force first thread (which has a timeout of 1 second) to timeout in the
      * first wait, and the second wait will succeed. */
-    RTThreadSleep(1500);
-    rc = RTSemEventMultiSignal(g_hSemEM);
-    if (RT_FAILURE(rc))
-        PrintError("RTSemEventMultiSignal failed (rc=%Rrc)\n", rc);
-
-    rc = RTThreadWait(Thread1, 5000, NULL);
-    if (RT_FAILURE(rc))
-        PrintError("RTThreadWait failed for thread 1 (rc=%Rrc)\n", rc);
-
-    rc = RTThreadWait(Thread2, 5000, NULL);
-    if (RT_FAILURE(rc))
-        PrintError("RTThreadWait failed for thread 2 (rc=%Rrc)\n", rc);
-
-    rc = RTSemEventMultiDestroy(g_hSemEM);
-    if (RT_FAILURE(rc))
-        PrintError("RTSemEventMultiDestroy failed - %Rrc\n", rc);
-    g_hSemEM = NIL_RTSEMEVENTMULTI;
-    if (g_cErrors)
-        RTThreadSleep(100);
-    return 0;
+    RTTESTI_CHECK_RC(RTThreadSleep(1500), VINF_SUCCESS);
+    RTTESTI_CHECK_RC(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
+    RTTESTI_CHECK_RC(RTThreadWait(hThread1, 5000, NULL), VINF_SUCCESS);
+    RTTESTI_CHECK_RC(RTThreadWait(hThread2, 5000, NULL), VINF_SUCCESS);
+    RTTESTI_CHECK_RC(RTSemEventMultiDestroy(hSem), VINF_SUCCESS);
+}
+
+
+static void testBasicsWaitTimeout(RTSEMEVENTMULTI hSem, unsigned i)
+{
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWait(hSem, 0), VERR_TIMEOUT);
+#if 1
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitNoResume(hSem, 0), VERR_TIMEOUT);
+#else
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_RELATIVE,
+                                                0),
+                          VERR_TIMEOUT);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
+                                                RTTimeSystemNanoTS() + 1000*i),
+                          VERR_TIMEOUT);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
+                                                RTTimeNanoTS() + 1000*i),
+                          VERR_TIMEOUT);
+
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_RELATIVE,
+                                                0),
+                          VERR_TIMEOUT);
+#endif
+}
+
+
+static void testBasicsWaitSuccess(RTSEMEVENTMULTI hSem, unsigned i)
+{
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWait(hSem, 0), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWait(hSem, RT_INDEFINITE_WAIT), VINF_SUCCESS);
+#if 1
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitNoResume(hSem, 0), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitNoResume(hSem, RT_INDEFINITE_WAIT), VINF_SUCCESS);
+#else
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_RELATIVE,
+                                                0),
+                          VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME   | RTSEMWAIT_FLAGS_INDEFINITE, 0), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
+                                                RTTimeSystemNanoTS() + 1000*i),
+                          VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
+                                                RTTimeNanoTS() + 1000*i),
+                          VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
+                                                0),
+                          VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
+                                                _1G),
+                          VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
+                                                UINT64_MAX),
+                          VINF_SUCCESS);
+
+
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
+                                                RTTimeSystemMilliTS() + 1000*i),
+                          VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
+                                                RTTimeMilliTS() + 1000*i),
+                          VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
+                                                0),
+                          VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
+                                                _1M),
+                          VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
+                                                RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
+                                                UINT64_MAX),
+                          VINF_SUCCESS);
+#endif
+}
+
+
+static void testBasics(void)
+{
+    RTTestISub("Basics");
+
+    RTSEMEVENTMULTI hSem;
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiCreate(&hSem), VINF_SUCCESS);
+
+    /* The semaphore is created in a reset state, calling reset explicitly
+       shouldn't make any difference. */
+    testBasicsWaitTimeout(hSem, 0);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS);
+    testBasicsWaitTimeout(hSem, 1);
+    if (RTTestIErrorCount())
+        return;
+
+    /* When signalling the semaphore all successive wait calls shall
+       succeed, signalling it again should make no difference. */
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
+    testBasicsWaitSuccess(hSem, 2);
+    if (RTTestIErrorCount())
+        return;
+
+    /* After resetting it we should time out again. */
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS);
+    testBasicsWaitTimeout(hSem, 3);
+    if (RTTestIErrorCount())
+        return;
+
+    /* The number of resets or signal calls shouldn't matter. */
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS);
+    testBasicsWaitTimeout(hSem, 4);
+
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
+    testBasicsWaitSuccess(hSem, 5);
+
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS);
+    testBasicsWaitTimeout(hSem, 6);
+
+    /* Destroy it. */
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiDestroy(hSem), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiDestroy(NIL_RTSEMEVENTMULTI), VINF_SUCCESS);
+
+    /* Whether it is reset (above), signalled or not used shouldn't matter.  */
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiCreate(&hSem), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiDestroy(hSem), VINF_SUCCESS);
+
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiCreate(&hSem), VINF_SUCCESS);
+    RTTESTI_CHECK_RC_RETV(RTSemEventMultiDestroy(hSem), VINF_SUCCESS);
+
+    RTTestISubDone();
 }
 
@@ -149,18 +246,15 @@
 int main(int argc, char **argv)
 {
-    int rc = RTR3Init();
-    if (RT_FAILURE(rc))
+    RTEXITCODE rcExit = RTTestInitAndCreate("tstSemEventMulti", &g_hTest);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
+
+    testBasics();
+    if (!RTTestErrorCount(g_hTest))
     {
-        RTPrintf("tstSemEvent: RTR3Init failed (rc=%Rrc)\n", rc);
-        return 1;
+        test1();
     }
-    RTPrintf("tstSemEvent: TESTING...\n");
-    Test1();
-
-    if (!g_cErrors)
-        RTPrintf("tstSemEvent: SUCCESS\n");
-    else
-        RTPrintf("tstSemEvent: FAILURE - %u errors\n", g_cErrors);
-    return g_cErrors != 0;
-}
-
+
+    return RTTestSummaryAndDestroy(g_hTest);
+}
+
