Index: /trunk/include/iprt/semaphore.h
===================================================================
--- /trunk/include/iprt/semaphore.h	(revision 7919)
+++ /trunk/include/iprt/semaphore.h	(revision 7920)
@@ -267,9 +267,9 @@
  * Request read access to a read/write semaphore, resume on interruption
  *
- * Read requests cannot be nested. A deadlock error will be returned
- * on such attempts.
- *
- * @returns iprt status code.
- *          Will not return VERR_INTERRUPTED.
+ * @returns iprt status code.
+ * @retval  VINF_SUCCESS on success.
+ * @retval  VERR_INTERRUPT if the wait was interrupted.
+ * @retval  VERR_INVALID_HANDLE if RWSem is invalid.
+ *
  * @param   RWSem       The Read/Write semaphore to request read access to.
  * @param   cMillies    The number of milliseconds to wait.
@@ -280,8 +280,9 @@
  * Request read access to a read/write semaphore, return on interruption
  *
- * Read requests cannot be nested. A deadlock error will be returned
- * on such attempts.
- *
- * @returns iprt status code.
+ * @returns iprt status code.
+ * @retval  VINF_SUCCESS on success.
+ * @retval  VERR_INTERRUPT if the wait was interrupted.
+ * @retval  VERR_INVALID_HANDLE if RWSem is invalid.
+ *
  * @param   RWSem       The Read/Write semaphore to request read access to.
  * @param   cMillies    The number of milliseconds to wait.
@@ -301,9 +302,9 @@
  * Request write access to a read/write semaphore, resume on interruption.
  *
- * Write requests cannot be nested. If called by the thread currently owning
- * the write lock the function returns an error code indicating deadlock.
- *
- * @returns iprt status code.
- *          Will not return VERR_INTERRUPTED.
+ * @returns iprt status code.
+ * @retval  VINF_SUCCESS on success.
+ * @retval  VERR_DEADLOCK if the caller owned the read lock.
+ * @retval  VERR_INVALID_HANDLE if RWSem is invalid.
+ *
  * @param   RWSem       The Read/Write semaphore to request write access to.
  * @param   cMillies    The number of milliseconds to wait.
@@ -314,8 +315,10 @@
  * Request write access to a read/write semaphore, return on interruption.
  *
- * Write requests cannot be nested. If called by the thread currently owning
- * the write lock the function returns an error code indicating deadlock.
- *
- * @returns iprt status code.
+ * @returns iprt status code.
+ * @retval  VINF_SUCCESS on success.
+ * @retval  VERR_INTERRUPT if the wait was interrupted.
+ * @retval  VERR_DEADLOCK if the caller owned the read lock.
+ * @retval  VERR_INVALID_HANDLE if RWSem is invalid.
+ *
  * @param   RWSem       The Read/Write semaphore to request write access to.
  * @param   cMillies    The number of milliseconds to wait.
Index: /trunk/src/VBox/Runtime/r3/posix/semrw-posix.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/posix/semrw-posix.cpp	(revision 7919)
+++ /trunk/src/VBox/Runtime/r3/posix/semrw-posix.cpp	(revision 7920)
@@ -39,4 +39,6 @@
 #include <sys/time.h>
 
+#include "internal/magics.h"
+
 
 /*******************************************************************************
@@ -46,35 +48,20 @@
 struct RTSEMRWINTERNAL
 {
+    /** The usual magic. (RTSEMRW_MAGIC) */
+    uint32_t            u32Magic;
+    /* Alignment padding. */
+    uint32_t            u32Padding;
+    /** Number of write recursions. */
+    uint32_t            cWrites;
+    /** Number of read recursions by the writer. */
+    uint32_t            cWriterReads;
+    /** The write owner of the lock. */
+    volatile pthread_t  Writer;
     /** pthread rwlock. */
     pthread_rwlock_t    RWLock;
-    /** Variable to check if initialized.
-     * 0 is uninitialized, ~0 is inititialized. */
-    volatile unsigned   uCheck;
-    /** The write owner of the lock. */
-    volatile pthread_t  WROwner;
 };
 
 
-
-/**
- * Validate a read-write semaphore handle passed to one of the interface.
- *
- * @returns true if valid.
- * @returns false if invalid.
- * @param   pIntRWSem   Pointer to the read-write semaphore to validate.
- */
-inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
-{
-    if ((uintptr_t)pIntRWSem < 0x10000)
-        return false;
-
-    if (pIntRWSem->uCheck != (unsigned)~0)
-        return false;
-
-    return true;
-}
-
-
-RTDECL(int)   RTSemRWCreate(PRTSEMRW pRWSem)
+RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)
 {
     int rc;
@@ -83,20 +70,23 @@
      * Allocate handle.
      */
-    struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
-    if (pIntRWSem)
+    struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
+    if (pThis)
     {
         /*
          * Create the rwlock.
          */
-        pthread_rwlockattr_t    Attr;
+        pthread_rwlockattr_t Attr;
         rc = pthread_rwlockattr_init(&Attr);
         if (!rc)
         {
-            rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);
+            rc = pthread_rwlock_init(&pThis->RWLock, &Attr);
             if (!rc)
             {
-                pIntRWSem->uCheck = ~0;
-                pIntRWSem->WROwner = (pthread_t)-1;
-                *pRWSem = pIntRWSem;
+                pThis->u32Magic = RTSEMRW_MAGIC;
+                pThis->u32Padding = 0;
+                pThis->cWrites = 0;
+                pThis->cWriterReads = 0;
+                pThis->Writer = (pthread_t)-1;
+                *pRWSem = pThis;
                 return VINF_SUCCESS;
             }
@@ -104,5 +94,5 @@
 
         rc = RTErrConvertFromErrno(rc);
-        RTMemFree(pIntRWSem);
+        RTMemFree(pThis);
     }
     else
@@ -113,24 +103,28 @@
 
 
-RTDECL(int)   RTSemRWDestroy(RTSEMRW RWSem)
-{
-    /*
-     * Validate input.
-     */
-    if (!rtsemRWValid(RWSem))
-    {
-        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
-        return VERR_INVALID_HANDLE;
-    }
+RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)
+{
+    /*
+     * Validate input, nil handle is fine.
+     */
+    if (RWSem == NIL_RTSEMRW)
+        return VINF_SUCCESS;
+    struct RTSEMRWINTERNAL *pThis = RWSem;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
+                    ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
+                    VERR_INVALID_HANDLE);
+    Assert(pThis->Writer == (pthread_t)-1);
+    Assert(!pThis->cWrites);
+    Assert(!pThis->cWriterReads);
 
     /*
      * Try destroy it.
      */
-    struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
-    int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);
+    int rc = pthread_rwlock_destroy(&pThis->RWLock);
     if (!rc)
     {
-        pIntRWSem->uCheck = 0;
-        RTMemFree(pIntRWSem);
+        pThis->u32Magic++;
+        RTMemFree(pThis);
         rc = VINF_SUCCESS;
     }
@@ -145,13 +139,26 @@
 
 
-RTDECL(int)   RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
+RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
 {
     /*
      * Validate input.
      */
-    if (!rtsemRWValid(RWSem))
-    {
-        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
-        return VERR_INVALID_HANDLE;
+    struct RTSEMRWINTERNAL *pThis = RWSem;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
+                    ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
+                    VERR_INVALID_HANDLE);
+
+    /*
+     * Check if it's the writer (implement write+read recursion).
+     */
+    pthread_t Self = pthread_self();
+    pthread_t Writer;
+    ASMAtomicReadSize(&pThis->Writer, &Writer);
+    if (Writer == Self)
+    {
+        Assert(pThis->cWriterReads < INT32_MAX);
+        pThis->cWriterReads++;
+        return VINF_SUCCESS;
     }
 
@@ -159,12 +166,131 @@
      * Try lock it.
      */
-    struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
     if (cMillies == RT_INDEFINITE_WAIT)
     {
         /* take rwlock */
-        int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);
+        int rc = pthread_rwlock_rdlock(&pThis->RWLock);
         if (rc)
         {
             AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
+            return RTErrConvertFromErrno(rc);
+        }
+    }
+    else
+    {
+#ifdef RT_OS_DARWIN
+        AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
+        return VERR_NOT_IMPLEMENTED;
+
+#else /* !RT_OS_DARWIN */
+        /*
+         * Get current time and calc end of wait time.
+         */
+        struct timespec     ts = {0,0};
+        clock_gettime(CLOCK_REALTIME, &ts);
+        if (cMillies != 0)
+        {
+            ts.tv_nsec += (cMillies % 1000) * 1000000;
+            ts.tv_sec  += cMillies / 1000;
+            if (ts.tv_nsec >= 1000000000)
+            {
+                ts.tv_nsec -= 1000000000;
+                ts.tv_sec++;
+            }
+        }
+
+        /* take rwlock */
+        int rc = pthread_rwlock_timedrdlock(&pThis->RWLock, &ts);
+        if (rc)
+        {
+            AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
+            return RTErrConvertFromErrno(rc);
+        }
+#endif /* !RT_OS_DARWIN */
+    }
+
+    return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
+{
+    /* EINTR isn't returned by the wait functions we're using. */
+    return RTSemRWRequestRead(RWSem, cMillies);
+}
+
+
+RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
+{
+    /*
+     * Validate input.
+     */
+    struct RTSEMRWINTERNAL *pThis = RWSem;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
+                    ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
+                    VERR_INVALID_HANDLE);
+
+    /*
+     * Check if it's the writer.
+     */
+    pthread_t Self = pthread_self();
+    pthread_t Writer;
+    ASMAtomicReadSize(&pThis->Writer, &Writer);
+    if (Writer == Self)
+    {
+        AssertMsgReturn(pThis->cWriterReads > 0,
+                        ("pThis=%p\n", pThis), VERR_NOT_OWNER);
+        pThis->cWriterReads--;
+        return VINF_SUCCESS;
+    }
+
+    /*
+     * Try unlock it.
+     */
+    int rc = pthread_rwlock_unlock(&pThis->RWLock);
+    if (rc)
+    {
+        AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
+        return RTErrConvertFromErrno(rc);
+    }
+
+    return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
+{
+    /*
+     * Validate input.
+     */
+    struct RTSEMRWINTERNAL *pThis = RWSem;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
+                    ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
+                    VERR_INVALID_HANDLE);
+
+    /*
+     * Recursion?
+     */
+    pthread_t Self = pthread_self();
+    pthread_t Writer;
+    ASMAtomicReadSize(&pThis->Writer, &Writer);
+    if (Writer == Self)
+    {
+        Assert(pThis->cWrites < INT32_MAX);
+        pThis->cWrites++;
+        return VINF_SUCCESS;
+    }
+
+    /*
+     * Try lock it.
+     */
+    if (cMillies == RT_INDEFINITE_WAIT)
+    {
+        /* take rwlock */
+        int rc = pthread_rwlock_wrlock(&pThis->RWLock);
+        if (rc)
+        {
+            AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
             return RTErrConvertFromErrno(rc);
         }
@@ -193,5 +319,5 @@
 
         /* take rwlock */
-        int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);
+        int rc = pthread_rwlock_timedwrlock(&pThis->RWLock, &ts);
         if (rc)
         {
@@ -202,114 +328,11 @@
     }
 
+    ASMAtomicWriteSize(&pThis->Writer, Self);
+    pThis->cWrites = 1;
     return VINF_SUCCESS;
 }
 
 
-RTDECL(int)   RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
-{
-    /* EINTR isn't returned by the wait functions we're using. */
-    return RTSemRWRequestRead(RWSem, cMillies);
-}
-
-
-RTDECL(int)   RTSemRWReleaseRead(RTSEMRW RWSem)
-{
-    /*
-     * Validate input.
-     */
-    if (!rtsemRWValid(RWSem))
-    {
-        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
-        return VERR_INVALID_HANDLE;
-    }
-
-    /*
-     * Try unlock it.
-     */
-    struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
-    if (pIntRWSem->WROwner == pthread_self())
-    {
-        AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));
-        return VERR_NOT_OWNER;
-    }
-    int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
-    if (rc)
-    {
-        AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
-        return RTErrConvertFromErrno(rc);
-    }
-
-    return VINF_SUCCESS;
-}
-
-
-RTDECL(int)   RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
-{
-    /*
-     * Validate input.
-     */
-    if (!rtsemRWValid(RWSem))
-    {
-        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
-        return VERR_INVALID_HANDLE;
-    }
-
-    /*
-     * Try lock it.
-     */
-    struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
-    if (cMillies == RT_INDEFINITE_WAIT)
-    {
-        /* take rwlock */
-        int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);
-        if (rc)
-        {
-            AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
-            return RTErrConvertFromErrno(rc);
-        }
-    }
-    else
-    {
-#ifdef RT_OS_DARWIN
-        AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
-        return VERR_NOT_IMPLEMENTED;
-#else /* !RT_OS_DARWIN */
-        /*
-         * Get current time and calc end of wait time.
-         */
-        struct timespec     ts = {0,0};
-        clock_gettime(CLOCK_REALTIME, &ts);
-        if (cMillies != 0)
-        {
-            ts.tv_nsec += (cMillies % 1000) * 1000000;
-            ts.tv_sec  += cMillies / 1000;
-            if (ts.tv_nsec >= 1000000000)
-            {
-                ts.tv_nsec -= 1000000000;
-                ts.tv_sec++;
-            }
-        }
-
-        /* take rwlock */
-        int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);
-        if (rc)
-        {
-            AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
-            return RTErrConvertFromErrno(rc);
-        }
-#endif /* !RT_OS_DARWIN */
-    }
-
-#ifdef RT_OS_SOLARIS
-    ASMAtomicXchgSize(&pIntRWSem->WROwner, pthread_self());
-#else
-    ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());
-#endif
-
-    return VINF_SUCCESS;
-}
-
-
-RTDECL(int)   RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
+RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
 {
     /* EINTR isn't returned by the wait functions we're using. */
@@ -318,36 +341,32 @@
 
 
-RTDECL(int)   RTSemRWReleaseWrite(RTSEMRW RWSem)
+RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
 {
     /*
      * Validate input.
      */
-    if (!rtsemRWValid(RWSem))
-    {
-        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
-        return VERR_INVALID_HANDLE;
-    }
+    struct RTSEMRWINTERNAL *pThis = RWSem;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
+                    ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
+                    VERR_INVALID_HANDLE);
+
+    /*
+     * Verify ownership and implement recursion.
+     */
+    pthread_t Self = pthread_self();
+    pthread_t Writer;
+    ASMAtomicReadSize(&pThis->Writer, &Writer);
+    AssertMsgReturn(Writer == Self, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
+    pThis->cWrites--;
+    if (pThis->cWrites)
+        return VINF_SUCCESS;
+    AssertReturn(!pThis->cWriterReads, VERR_WRONG_ORDER);
 
     /*
      * Try unlock it.
      */
-    pthread_t                 Self = pthread_self();
-    struct RTSEMRWINTERNAL   *pIntRWSem = RWSem;
-    if (pIntRWSem->WROwner != Self)
-    {
-        AssertMsgFailed(("Not Write owner!\n"));
-        return VERR_NOT_OWNER;
-    }
-
-    /*
-     * Try unlock it.
-     */
-#ifdef RT_OS_SOLARIS
-    ASMAtomicXchgSize(&pIntRWSem->WROwner, (pthread_t)-1);
-#else
-    AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));
-    ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(pthread_t)-1);
-#endif
-    int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
+    ASMAtomicWriteSize(&pThis->Writer, (pthread_t)-1);
+    int rc = pthread_rwlock_unlock(&pThis->RWLock);
     if (rc)
     {
