Index: /trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp	(revision 25688)
+++ /trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp	(revision 25689)
@@ -241,5 +241,6 @@
 *   Internal Functions                                                         *
 *******************************************************************************/
-static void rtLockValidatorClassDestroy(RTLOCKVALCLASSINT *pClass);
+static void     rtLockValidatorClassDestroy(RTLOCKVALCLASSINT *pClass);
+static uint32_t rtLockValidatorStackDepth(PRTTHREADINT pThread);
 
 
@@ -342,5 +343,5 @@
  * @param   ...                 Format arguments.
  */
-static void rtLockValidatorComplain(RT_SRC_POS_DECL, const char *pszWhat, ...)
+static void rtLockValComplain(RT_SRC_POS_DECL, const char *pszWhat, ...)
 {
     if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
@@ -364,5 +365,5 @@
  * @param   pszSuffix           Message suffix.
  */
-static void rtLockValidatorComplainAboutLock(const char *pszPrefix, PRTLOCKVALRECUNION pRec, const char *pszSuffix)
+static void rtLockValComplainAboutLock(const char *pszPrefix, PRTLOCKVALRECUNION pRec, const char *pszSuffix)
 {
     if (    VALID_PTR(pRec)
@@ -413,4 +414,46 @@
 
 /**
+ * Dump the lock stack.
+ *
+ * @param   pThread             The thread which lock stack we're gonna dump.
+ * @param   cchIndent           The indentation in chars.
+ * @param   cMinFrames          The minimum number of frames to consider
+ *                              dumping.
+ */
+static void rtLockValComplainAboutLockStack(PRTTHREADINT pThread, unsigned cchIndent, uint32_t cMinFrames)
+{
+    if (    VALID_PTR(pThread)
+        &&  !ASMAtomicUoReadBool(&g_fLockValidatorQuiet)
+        &&  pThread->u32Magic == RTTHREADINT_MAGIC
+       )
+    {
+        uint32_t cEntries = rtLockValidatorStackDepth(pThread);
+        if (cEntries >= cMinFrames)
+        {
+            RTAssertMsg2AddWeak("%*s---- start of lock stack - %u entr%s ----\n", cchIndent, "", cEntries,
+                                cEntries == 1 ? "y" : "ies");
+            PRTLOCKVALRECUNION pCur = rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pStackTop);
+            for (uint32_t i = 0; pCur; i++)
+            {
+                char szPrefix[80];
+                RTStrPrintf(szPrefix, sizeof(szPrefix), "%*s#%02u: ", cchIndent, "", i);
+                rtLockValComplainAboutLock(szPrefix, pCur, "\n");
+                switch (pCur->Core.u32Magic)
+                {
+                    case RTLOCKVALRECEXCL_MAGIC:    pCur = rtLockValidatorReadRecUnionPtr(&pCur->Excl.pDown);      break;
+                    case RTLOCKVALRECSHRDOWN_MAGIC: pCur = rtLockValidatorReadRecUnionPtr(&pCur->ShrdOwner.pDown); break;
+                    default:
+                        RTAssertMsg2AddWeak("%*s<bad stack frame>\n", cchIndent, "");
+                        pCur = NULL;
+                        break;
+                }
+            }
+            RTAssertMsg2AddWeak("%*s---- end of lock stack ----\n", cchIndent, "");
+        }
+    }
+}
+
+
+/**
  * Launch the initial complaint.
  *
@@ -420,5 +463,5 @@
  * @param   pRec                The main lock involved. Can be NULL.
  */
-static void rtLockValidatorComplainFirst(const char *pszWhat, PCRTLOCKVALSRCPOS pSrcPos, PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
+static void rtLockValComplainFirst(const char *pszWhat, PCRTLOCKVALSRCPOS pSrcPos, PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
 {
     if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
@@ -430,5 +473,6 @@
         else
             RTAssertMsg2Weak("%s  [thrd=%s]\n", pszWhat, VALID_PTR(pThreadSelf) ? pThreadSelf->szName : "<NIL>");
-        rtLockValidatorComplainAboutLock("Lock: ", pRec, "\n");
+        rtLockValComplainAboutLock("Lock: ", pRec, "\n");
+        rtLockValComplainAboutLockStack(pThreadSelf, 0, 1);
     }
 }
@@ -441,5 +485,5 @@
  * @param   ...                 Format arguments.
  */
-static void rtLockValidatorComplainMore(const char *pszFormat, ...)
+static void rtLockValComplainMore(const char *pszFormat, ...)
 {
     if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
@@ -456,5 +500,5 @@
  * Raise a panic if enabled.
  */
-static void rtLockValidatorComplainPanic(void)
+static void rtLockValComplainPanic(void)
 {
     if (ASMAtomicUoReadBool(&g_fLockValidatorMayPanic))
@@ -645,4 +689,5 @@
     Assert(pPerThread->cReadLocks == 0);
     Assert(pPerThread->fInValidator == false);
+    Assert(pPerThread->pStackTop == NULL);
 }
 
@@ -1029,15 +1074,168 @@
 
 
-static void rtLockValidatorStackPush(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec, PCRTLOCKVALSRCPOS pSrcPos)
+/**
+ * Calculates the depth of a lock stack.
+ *
+ * @returns Number of stack frames.
+ * @param   pThread         The thread.
+ */
+static uint32_t rtLockValidatorStackDepth(PRTTHREADINT pThread)
+{
+    uint32_t            cEntries = 0;
+    PRTLOCKVALRECUNION  pCur = rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pStackTop);
+    while (pCur)
+    {
+        switch (pCur->Core.u32Magic)
+        {
+            case RTLOCKVALRECEXCL_MAGIC:
+                pCur = rtLockValidatorReadRecUnionPtr(&pCur->Excl.pDown);
+                break;
+
+            case RTLOCKVALRECSHRDOWN_MAGIC:
+                pCur = rtLockValidatorReadRecUnionPtr(&pCur->ShrdOwner.pDown);
+                break;
+
+            default:
+                AssertMsgFailedReturn(("%#x\n", pCur->Core.u32Magic), cEntries);
+        }
+        cEntries++;
+    }
+    return cEntries;
+}
+
+
+/**
+ * Checks if the stack contains @a pRec.
+ *
+ * @returns true / false.
+ * @param   pThreadSelf         The curren thread.
+ * @param   pRec                The lock record.
+ */
+static bool rtLockValidatorStackContainsRec(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
+{
+    PRTLOCKVALRECUNION pCur = pThreadSelf->LockValidator.pStackTop;
+    while (pCur)
+    {
+        switch (pCur->Core.u32Magic)
+        {
+            case RTLOCKVALRECEXCL_MAGIC:
+                Assert(pRec->Excl.cRecursion >= 1);
+                if (pCur->Excl.pDown == pRec)
+                    return true;
+                pCur = pCur->Excl.pDown;
+                break;
+
+            case RTLOCKVALRECSHRDOWN_MAGIC:
+                Assert(pCur->ShrdOwner.cRecursion >= 1);
+                if (pCur->ShrdOwner.pDown == pRec)
+                    return true;
+                pCur = pCur->ShrdOwner.pDown;
+                break;
+
+            default:
+                AssertMsgFailedReturn(("%#x\n", pCur->Core.u32Magic), false);
+        }
+    }
+    return false;
+}
+
+
+/**
+ * Pushes a lock onto the stack.
+ *
+ * @param   pThreadSelf         The current thread.
+ * @param   pRec                The lock record.
+ */
+static void rtLockValidatorStackPush(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
 {
     Assert(pThreadSelf == RTThreadSelf());
-
-}
-
-
+    Assert(!rtLockValidatorStackContainsRec(pThreadSelf, pRec));
+
+    switch (pRec->Core.u32Magic)
+    {
+        case RTLOCKVALRECEXCL_MAGIC:
+            Assert(pRec->Excl.cRecursion == 1);
+            Assert(pRec->Excl.pDown == NULL);
+            pRec->Excl.pDown = pThreadSelf->LockValidator.pStackTop;
+            break;
+
+        case RTLOCKVALRECSHRDOWN_MAGIC:
+            Assert(pRec->ShrdOwner.cRecursion == 1);
+            Assert(pRec->ShrdOwner.pDown == NULL);
+            pRec->ShrdOwner.pDown = pThreadSelf->LockValidator.pStackTop;
+            break;
+
+        case RTLOCKVALRECSHRD_MAGIC:
+        default:
+            AssertMsgFailedReturnVoid(("%#x\n",  pRec->Core.u32Magic));
+    }
+    pThreadSelf->LockValidator.pStackTop = pRec;
+}
+
+
+/**
+ * Pops a lock off the stack.
+ *
+ * @param   pThreadSelf         The current thread.
+ * @param   pRec                The lock.
+ */
 static void rtLockValidatorStackPop(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
 {
     Assert(pThreadSelf == RTThreadSelf());
 
+    PRTLOCKVALRECUNION pDown;
+    switch (pRec->Core.u32Magic)
+    {
+        case RTLOCKVALRECEXCL_MAGIC:
+            Assert(pRec->Excl.cRecursion == 0);
+            pDown = pRec->Excl.pDown;
+            pRec->Excl.pDown = NULL;
+            break;
+
+        case RTLOCKVALRECSHRDOWN_MAGIC:
+            Assert(pRec->ShrdOwner.cRecursion == 0);
+            pDown = pRec->ShrdOwner.pDown;
+            pRec->ShrdOwner.pDown = NULL;
+            break;
+
+        default:
+            AssertMsgFailedReturnVoid(("%#x\n",  pRec->Core.u32Magic));
+    }
+    if (pThreadSelf->LockValidator.pStackTop == pRec)
+        pThreadSelf->LockValidator.pStackTop = pDown;
+    else
+    {
+        /* find the record on top of ours */
+        PRTLOCKVALRECUNION pAbove = pThreadSelf->LockValidator.pStackTop;
+        while (pAbove)
+        {
+            switch (pAbove->Core.u32Magic)
+            {
+                case RTLOCKVALRECEXCL_MAGIC:
+                    Assert(pRec->Excl.cRecursion >= 1);
+                    if (pAbove->Excl.pDown == pRec)
+                    {
+                        pAbove->Excl.pDown = pDown;
+                        return;
+                    }
+                    pAbove = pAbove->Excl.pDown;
+                    break;
+
+                case RTLOCKVALRECSHRDOWN_MAGIC:
+                    Assert(pAbove->ShrdOwner.cRecursion >= 1);
+                    if (pAbove->ShrdOwner.pDown == pRec)
+                    {
+                        pAbove->ShrdOwner.pDown = pDown;
+                        return;
+                    }
+                    pAbove = pAbove->ShrdOwner.pDown;
+                    break;
+
+                default:
+                    AssertMsgFailedReturnVoid(("%#x\n", pAbove->Core.u32Magic));
+            }
+        }
+        AssertMsgFailed(("%p %p\n", pRec, pThreadSelf));
+    }
 }
 
@@ -1046,6 +1244,19 @@
 {
     Assert(pThreadSelf == RTThreadSelf());
-    /** @todo insert a recursion record onto the stack. Keep a reasonally big pool
+    /** @todo insert a recursion record onto the stack.  Keep a reasonally big pool
      *        of them associated with each thread. */
+    switch (pRec->Core.u32Magic)
+    {
+        case RTLOCKVALRECEXCL_MAGIC:
+            Assert(pRec->Excl.cRecursion > 1);
+            break;
+
+        case RTLOCKVALRECSHRDOWN_MAGIC:
+            Assert(pRec->ShrdOwner.cRecursion > 1);
+            break;
+
+        default:
+            AssertMsgFailedReturnVoid(("%#x\n",  pRec->Core.u32Magic));
+    }
 }
 
@@ -1054,5 +1265,17 @@
 {
     Assert(pThreadSelf == RTThreadSelf());
-
+    switch (pRec->Core.u32Magic)
+    {
+        case RTLOCKVALRECEXCL_MAGIC:
+            Assert(pRec->Excl.cRecursion >= 1);
+            break;
+
+        case RTLOCKVALRECSHRDOWN_MAGIC:
+            Assert(pRec->ShrdOwner.cRecursion >= 1);
+            break;
+
+        default:
+            AssertMsgFailedReturnVoid(("%#x\n",  pRec->Core.u32Magic));
+    }
 }
 
@@ -1175,5 +1398,5 @@
     {
         s_fComplained = true;
-        rtLockValidatorComplain(RT_SRC_POS, "lock validator stack is too small! (%zu entries)\n", RT_ELEMENTS(pStack->a));
+        rtLockValComplain(RT_SRC_POS, "lock validator stack is too small! (%zu entries)\n", RT_ELEMENTS(pStack->a));
     }
     return VINF_SUCCESS;
@@ -1469,6 +1692,6 @@
             default:            AssertFailed(); pszWhat = "!unexpected rc!"; break;
         }
-        rtLockValidatorComplainFirst(pszWhat, pSrcPos, pThreadSelf, pStack->a[0].pRec != pRec ? pRec : NULL);
-        rtLockValidatorComplainMore("---- start of deadlock chain - %u entries ----\n", pStack->c);
+        rtLockValComplainFirst(pszWhat, pSrcPos, pThreadSelf, pStack->a[0].pRec != pRec ? pRec : NULL);
+        rtLockValComplainMore("---- start of deadlock chain - %u entries ----\n", pStack->c);
         for (uint32_t i = 0; i < pStack->c; i++)
         {
@@ -1479,12 +1702,12 @@
                 pShrdOwner = pStack->a[i].pRec->Shared.papOwners[pStack->a[i].iEntry];
             if (VALID_PTR(pShrdOwner) && pShrdOwner->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC)
-                rtLockValidatorComplainAboutLock(szPrefix, (PRTLOCKVALRECUNION)pShrdOwner, "\n");
+                rtLockValComplainAboutLock(szPrefix, (PRTLOCKVALRECUNION)pShrdOwner, "\n");
             else
-                rtLockValidatorComplainAboutLock(szPrefix, pStack->a[i].pRec, "\n");
-        }
-        rtLockValidatorComplainMore("---- end of deadlock chain ----\n");
-    }
-
-    rtLockValidatorComplainPanic();
+                rtLockValComplainAboutLock(szPrefix, pStack->a[i].pRec, "\n");
+        }
+        rtLockValComplainMore("---- end of deadlock chain ----\n");
+    }
+
+    rtLockValComplainPanic();
 }
 
@@ -1610,4 +1833,26 @@
 
     return VINF_SUCCESS;
+}
+
+
+/**
+ * Gets the lock name for the given record.
+ *
+ * @returns Read-only lock name.
+ * @param   pRec                The lock record.
+ */
+DECL_FORCE_INLINE(const char *) rtLockValidatorRecName(PRTLOCKVALRECUNION pRec)
+{
+    switch (pRec->Core.u32Magic)
+    {
+        case RTLOCKVALRECEXCL_MAGIC:
+            return pRec->Excl.pszName;
+        case RTLOCKVALRECSHRD_MAGIC:
+            return pRec->Shared.pszName;
+        case RTLOCKVALRECSHRDOWN_MAGIC:
+            return pRec->ShrdOwner.pSharedRec ? pRec->ShrdOwner.pSharedRec->pszName : "orphaned";
+        default:
+            return "unknown";
+    }
 }
 
@@ -1711,5 +1956,5 @@
         ASMAtomicWriteHandle(&pRecU->Excl.hThread, hThreadSelf);
 
-        rtLockValidatorStackPush(hThreadSelf, pRecU, pSrcPos);
+        rtLockValidatorStackPush(hThreadSelf, pRecU);
     }
 }
@@ -1730,5 +1975,5 @@
     if (c == 0)
     {
-        rtLockValidatorStackPopRecursion(pThread, pRec);
+        rtLockValidatorStackPop(pThread, pRec);
         ASMAtomicWriteHandle(&pRec->Excl.hThread, NIL_RTTHREAD);
     }
@@ -1772,7 +2017,7 @@
         && !pRecU->Excl.hClass->fRecursionOk)
     {
-        rtLockValidatorComplainFirst("Recursion not allowed by the class",
+        rtLockValComplainFirst("Recursion not allowed by the class",
                                      pSrcPos, pRecU->Excl.hThread, (PRTLOCKVALRECUNION)pRec);
-        rtLockValidatorComplainPanic();
+        rtLockValComplainPanic();
         return VERR_SEM_LV_NESTED;
     }
@@ -1780,5 +2025,5 @@
     Assert(pRecU->Excl.cRecursion < _1M);
     pRecU->Excl.cRecursion++;
-    rtLockValidatorStackPush(pRecU->Excl.hThread, pRecU, pSrcPos);
+    rtLockValidatorStackPushRecursion(pRecU->Excl.hThread, pRecU, pSrcPos);
     return VINF_SUCCESS;
 }
@@ -1794,6 +2039,6 @@
     AssertReturn(pRecU->Excl.cRecursion > 1, VERR_SEM_LV_INVALID_PARAMETER);
 
-    rtLockValidatorStackPop(pRecU->Excl.hThread, pRecU);
     pRecU->Excl.cRecursion--;
+    rtLockValidatorStackPopRecursion(pRecU->Excl.hThread, pRecU);
     return VINF_SUCCESS;
 }
@@ -1816,7 +2061,7 @@
         && !pRecU->Excl.hClass->fRecursionOk)
     {
-        rtLockValidatorComplainFirst("Mixed recursion not allowed by the class",
+        rtLockValComplainFirst("Mixed recursion not allowed by the class",
                                      pSrcPos, pRecU->Excl.hThread, (PRTLOCKVALRECUNION)pRec);
-        rtLockValidatorComplainPanic();
+        rtLockValComplainPanic();
         return VERR_SEM_LV_NESTED;
     }
@@ -1843,6 +2088,6 @@
     AssertReturn(pRecU->Excl.cRecursion > 1, VERR_SEM_LV_INVALID_PARAMETER);
 
+    pRecU->Excl.cRecursion--;
     rtLockValidatorStackPopRecursion(pRecU->Excl.hThread, pRecU);
-    pRecU->Excl.cRecursion--;
     return VINF_SUCCESS;
 }
@@ -1915,6 +2160,6 @@
                 && !pRecU->Excl.hClass->fRecursionOk))
         {
-            rtLockValidatorComplainFirst("Recursion not allowed", pSrcPos, pThreadSelf, pRecU);
-            rtLockValidatorComplainPanic();
+            rtLockValComplainFirst("Recursion not allowed", pSrcPos, pThreadSelf, pRecU);
+            rtLockValComplainPanic();
             rc = VERR_SEM_LV_NESTED;
         }
@@ -2124,6 +2369,6 @@
             )
         {
-            rtLockValidatorComplainFirst("Recursion not allowed", pSrcPos, pThreadSelf, pRecU);
-            rtLockValidatorComplainPanic();
+            rtLockValComplainFirst("Recursion not allowed", pSrcPos, pThreadSelf, pRecU);
+            rtLockValComplainPanic();
             rc =  VERR_SEM_LV_NESTED;
         }
@@ -2504,5 +2749,5 @@
         {
             if (!pRec->fSignaller)
-                rtLockValidatorStackPush(hThread, pEntry, pSrcPos);
+                rtLockValidatorStackPush(hThread, pEntry);
         }
         else
@@ -2527,15 +2772,17 @@
     PRTLOCKVALRECUNION pEntry = rtLockValidatorRecSharedFindOwner(pRec, hThread, &iEntry);
     AssertReturnVoid(pEntry);
-    if (pEntry->ShrdOwner.cRecursion > 1)
-    {
-        Assert(!pRec->fSignaller);
-        rtLockValidatorStackPopRecursion(hThread, pEntry);
-        pEntry->ShrdOwner.cRecursion--;
-    }
-    else
+    AssertReturnVoid(pEntry->ShrdOwner.cRecursion > 0);
+
+    uint32_t c = --pEntry->ShrdOwner.cRecursion;
+    if (c == 0)
     {
         if (!pRec->fSignaller)
             rtLockValidatorStackPop(hThread, (PRTLOCKVALRECUNION)pEntry);
         rtLockValidatorRecSharedRemoveAndFreeOwner(pRec, &pEntry->ShrdOwner, iEntry);
+    }
+    else
+    {
+        Assert(!pRec->fSignaller);
+        rtLockValidatorStackPopRecursion(hThread, pEntry);
     }
 }
@@ -2562,6 +2809,6 @@
     if (RT_UNLIKELY(!pEntry))
     {
-        rtLockValidatorComplainFirst("Not owner (shared)", NULL, hThreadSelf, (PRTLOCKVALRECUNION)pRec);
-        rtLockValidatorComplainPanic();
+        rtLockValComplainFirst("Not owner (shared)", NULL, hThreadSelf, (PRTLOCKVALRECUNION)pRec);
+        rtLockValComplainPanic();
         return VERR_SEM_LV_NOT_OWNER;
     }
@@ -2583,14 +2830,12 @@
      */
     Assert(pEntry->ShrdOwner.cRecursion > 0);
-    if (pEntry->ShrdOwner.cRecursion > 1)
-    {
-        rtLockValidatorStackPopRecursion(hThreadSelf, pEntry);
-        pEntry->ShrdOwner.cRecursion--;
-    }
-    else
+    uint32_t c = --pEntry->ShrdOwner.cRecursion;
+    if (c == 0)
     {
         rtLockValidatorStackPop(hThreadSelf, pEntry);
         rtLockValidatorRecSharedRemoveAndFreeOwner(pRec, &pEntry->ShrdOwner, iEntry);
     }
+    else
+        rtLockValidatorStackPopRecursion(hThreadSelf, pEntry);
 
     return VINF_SUCCESS;
@@ -2617,6 +2862,6 @@
     if (RT_UNLIKELY(!pEntry))
     {
-        rtLockValidatorComplainFirst("Invalid signaller", NULL, hThreadSelf, (PRTLOCKVALRECUNION)pRec);
-        rtLockValidatorComplainPanic();
+        rtLockValComplainFirst("Invalid signaller", NULL, hThreadSelf, (PRTLOCKVALRECUNION)pRec);
+        rtLockValComplainPanic();
         return VERR_SEM_LV_NOT_SIGNALLER;
     }
Index: /trunk/src/VBox/Runtime/include/internal/lockvalidator.h
===================================================================
--- /trunk/src/VBox/Runtime/include/internal/lockvalidator.h	(revision 25688)
+++ /trunk/src/VBox/Runtime/include/internal/lockvalidator.h	(revision 25689)
@@ -65,4 +65,6 @@
      * RTThreadUnblocking uses this to figure out when to clear pRec. */
     RTTHREADSTATE volatile          enmRecState;
+    /** Top of the lock stack. */
+    PRTLOCKVALRECUNION volatile     pStackTop;
     /** The thread is running inside the lock validator. */
     bool volatile                   fInValidator;
