Index: /trunk/include/iprt/lockvalidator.h
===================================================================
--- /trunk/include/iprt/lockvalidator.h	(revision 25702)
+++ /trunk/include/iprt/lockvalidator.h	(revision 25703)
@@ -822,5 +822,6 @@
  * Releases a reference to a lock validator class.
  *
- * @returns New reference count; UINT32_MAX if the handle is invalid.
+ * @returns New reference count. 0 if hClass is NIL_RTLOCKVALCLASS. UINT32_MAX
+ *          if the handle is invalid.
  * @param   hClass              Handle to the class.
  */
@@ -840,4 +841,13 @@
 
 /**
+ * Enables or disables the strict release order enforcing.
+ *
+ * @returns IPRT status.
+ * @param   hClass              Handle to the class to change.
+ * @param   fEnable             Enable it (true) or disable it (false).
+ */
+RTDECL(int) RTLockValidatorClassEnforceStrictReleaseOrder(RTLOCKVALCLASS hClass, bool fEnabled);
+
+/**
  * Enables / disables the lock validator for new locks.
  *
@@ -867,5 +877,5 @@
  * @returns True if it is quiet, false if noisy.
  */
-RTDECL(bool) RTLockValidatorAreQuiet(void);
+RTDECL(bool) RTLockValidatorIsQuiet(void);
 
 /**
Index: /trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp	(revision 25702)
+++ /trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp	(revision 25703)
@@ -62,5 +62,5 @@
 /** Hashes the class handle (pointer) into an apPriorLocksHash index. */
 #define RTLOCKVALCLASS_HASH(hClass) \
-    (   (uintptr_t)(hClass) \
+    (   ((uintptr_t)(hClass) >> 6 ) \
       % (  RT_SIZEOFMEMB(RTLOCKVALCLASSINT, apPriorLocksHash) \
          / sizeof(PRTLOCKVALCLASSREF)) )
@@ -202,5 +202,13 @@
     RTLOCKVALCLASSREFCHUNK  PriorLocks;
     /** Hash table containing frequently encountered prior locks. */
-    PRTLOCKVALCLASSREF      apPriorLocksHash[11];
+    PRTLOCKVALCLASSREF      apPriorLocksHash[17];
+    /** Class name. (Allocated after the end of the block as usual.) */
+    char const             *pszName;
+    /** Where this class was created.
+     *  This is mainly used for finding automatically created lock classes.
+     *  @remarks The strings are stored after this structure so we won't crash
+     *           if the class lives longer than the module (dll/so/dylib) that
+     *           spawned it. */
+    RTLOCKVALSRCPOS         CreatePos;
 #ifdef RTLOCKVAL_WITH_CLASS_HASH_STATS
     /** Hash hits. */
@@ -209,12 +217,4 @@
     uint32_t volatile       cHashMisses;
 #endif
-    /** Where this class was created.
-     *  This is mainly used for finding automatically created lock classes.
-     *  @remarks The strings are stored after this structure so we won't crash
-     *           if the class lives longer than the module (dll/so/dylib) that
-     *           spawned it. */
-    RTLOCKVALSRCPOS         CreatePos;
-    /** Class name. (Allocated after the end of the block as usual.) */
-    char const             *pszName;
 } RTLOCKVALCLASSINT;
 AssertCompileSize(AVLLU32NODECORE, ARCH_BITS == 32 ? 20 : 32);
@@ -251,7 +251,7 @@
 #endif
 /** Serializing class tree insert and lookups. */
-static RTSEMRW          g_hLockValClassTreeRWLock = NIL_RTSEMRW;
+static RTSEMRW          g_hLockValClassTreeRWLock= NIL_RTSEMRW;
 /** Class tree. */
-static PAVLLU32NODECORE g_LockValClassTree = NULL;
+static PAVLLU32NODECORE g_LockValClassTree       = NULL;
 /** Critical section serializing the teaching new rules to the classes. */
 static RTCRITSECT       g_LockValClassTeachCS;
@@ -1006,12 +1006,16 @@
     for (unsigned i = 0; i < RT_ELEMENTS(pThis->apPriorLocksHash); i++)
         pThis->apPriorLocksHash[i] = NULL;
+    char *pszDst = (char *)(pThis + 1);
+    pThis->pszName              = (char *)memcpy(pszDst, szName, cbName);
+    pszDst += cbName;
     rtLockValidatorSrcPosCopy(&pThis->CreatePos, pSrcPos);
-    char *pszDst = (char *)(pThis + 1);
     pThis->CreatePos.pszFile    = pSrcPos->pszFile     ? (char *)memcpy(pszDst, pSrcPos->pszFile,     cbFile)     : NULL;
     pszDst += cbFile;
     pThis->CreatePos.pszFunction= pSrcPos->pszFunction ? (char *)memcpy(pszDst, pSrcPos->pszFunction, cbFunction) : NULL;
-    pszDst += cbFunction;
     Assert(rtLockValidatorSrcPosHash(&pThis->CreatePos) == pThis->Core.Key);
-    pThis->pszName              = (char *)memcpy(pszDst, szName, cbName);
+#ifdef RTLOCKVAL_WITH_CLASS_HASH_STATS
+    pThis->cHashHits            = 0;
+    pThis->cHashMisses          = 0;
+#endif
 
     *phClass = pThis;
@@ -1084,5 +1088,5 @@
 static void rtLockValidatorClassDestroy(RTLOCKVALCLASSINT *pClass)
 {
-    AssertReturnVoid(pClass->fInTree);
+    AssertReturnVoid(!pClass->fInTree);
     ASMAtomicWriteU32(&pClass->u32Magic, RTLOCKVALCLASS_MAGIC_DEAD);
 
@@ -1104,5 +1108,5 @@
         if (pChunk != &pClass->PriorLocks)
             RTMemFree(pChunk);
-        pNext = pChunk;
+        pChunk = pNext;
     }
 
@@ -1122,8 +1126,5 @@
     {
         if (rtLockValidatorSrcPosCompare(&pClass->CreatePos, pSrcPos) == 0)
-        {
-            rtLockValidatorClassRetain(pClass);
             break;
-        }
         pClass = (RTLOCKVALCLASSINT *)pClass->Core.pList;
     }
@@ -1179,4 +1180,6 @@
 {
     RTLOCKVALCLASSINT *pClass = hClass;
+    if (pClass == NIL_RTLOCKVALCLASS)
+        return 0;
     AssertPtrReturn(pClass, UINT32_MAX);
     AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, UINT32_MAX);
@@ -1349,4 +1352,15 @@
 
     return rtLockValidatorClassAddPriorClass(pClass, pPriorClass, false /*fAutodidacticism*/, NULL);
+}
+
+
+RTDECL(int) RTLockValidatorClassEnforceStrictReleaseOrder(RTLOCKVALCLASS hClass, bool fEnabled)
+{
+    RTLOCKVALCLASSINT *pClass = hClass;
+    AssertPtrReturn(pClass, VERR_INVALID_HANDLE);
+    AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, VERR_INVALID_HANDLE);
+
+    ASMAtomicWriteBool(&pClass->fStrictReleaseOrder, fEnabled);
+    return VINF_SUCCESS;
 }
 
@@ -2076,5 +2090,6 @@
      * Something went wrong, pCur is pointing to where.
      */
-    if (rtLockValidatorClassIsPriorClass(pFirstBadClass, pClass))
+    if (   pClass == pFirstBadClass
+        || rtLockValidatorClassIsPriorClass(pFirstBadClass, pClass))
         return rtLockValidatorStackWrongOrder("Wrong locking order!", pSrcPos, pThreadSelf,
                                               pRec, pFirstBadRec, pClass, pFirstBadClass);
@@ -2285,10 +2300,32 @@
                   || (   pTop
                       && pTop->Core.u32Magic == RTLOCKVALRECNEST_MAGIC
-                      && pTop->Nest.pRec == pRec)))
+                      && pTop->Nest.pRec == pRec) ))
         return VINF_SUCCESS;
+
+#ifdef RTLOCKVAL_WITH_RECURSION_RECORDS
+    /* Look for a recursion record so the right frame is dumped and marked. */
+    while (pTop)
+    {
+        if (pTop->Core.u32Magic == RTLOCKVALRECNEST_MAGIC)
+        {
+            if (pTop->Nest.pRec == pRec)
+            {
+                pRec = pTop;
+                break;
+            }
+            pTop = pTop->Nest.pDown;
+        }
+        else if (pTop->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC)
+            pTop = pTop->Excl.pDown;
+        else if (pTop->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC)
+            pTop = pTop->ShrdOwner.pDown;
+        else
+            break;
+    }
+#endif
 
     rtLockValComplainFirst("Wrong release order!", NULL, pThreadSelf, pRec, true);
     rtLockValComplainPanic();
-    return VERR_SEM_LV_WRONG_ORDER;
+    return VERR_SEM_LV_WRONG_RELEASE_ORDER;
 }
 
@@ -2810,8 +2847,11 @@
     ASMAtomicWriteU32(&pRec->Core.u32Magic, RTLOCKVALRECEXCL_MAGIC_DEAD);
     ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD);
-    ASMAtomicWriteHandle(&pRec->hClass, NIL_RTLOCKVALCLASS);
+    RTLOCKVALCLASS hClass;
+    ASMAtomicXchgHandle(&pRec->hClass, NIL_RTLOCKVALCLASS, &hClass);
     if (pRec->pSibling)
         rtLockValidatorUnlinkAllSiblings(&pRec->Core);
     rtLockValidatorSerializeDestructLeave();
+    if (hClass != NIL_RTLOCKVALCLASS)
+        RTLockValidatorClassRelease(hClass);
 }
 
@@ -3019,4 +3059,7 @@
                                              PCRTLOCKVALSRCPOS pSrcPos, RTMSINTERVAL cMillies)
 {
+    /*
+     * Validate and adjust input.  Quit early if order validation is disabled.
+     */
     PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
     AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
@@ -3034,4 +3077,10 @@
     AssertReturn(hThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     Assert(hThreadSelf == RTThreadSelf());
+
+    /*
+     * Detect recursion as it isn't subject to order restrictions.
+     */
+    if (pRec->hThread == hThreadSelf)
+        return VINF_SUCCESS;
 
     return rtLockValidatorStackCheckLockingOrder(pRecU->Excl.hClass, pRecU->Excl.uSubClass, hThreadSelf, pRecU, pSrcPos);
@@ -3234,4 +3283,7 @@
                                                PCRTLOCKVALSRCPOS pSrcPos, RTMSINTERVAL cMillies)
 {
+    /*
+     * Validate and adjust input.  Quit early if order validation is disabled.
+     */
     PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
     AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
@@ -3250,4 +3302,11 @@
     AssertReturn(hThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     Assert(hThreadSelf == RTThreadSelf());
+
+    /*
+     * Detect recursion as it isn't subject to order restrictions.
+     */
+    PRTLOCKVALRECUNION pEntry = rtLockValidatorRecSharedFindOwner(&pRecU->Shared, hThreadSelf, NULL);
+    if (pEntry)
+        return VINF_SUCCESS;
 
     return rtLockValidatorStackCheckLockingOrder(pRecU->Shared.hClass, pRecU->Shared.uSubClass, hThreadSelf, pRecU, pSrcPos);
@@ -3960,9 +4019,9 @@
 
 
-RTDECL(bool) RTLockValidatorAreQuiet(void)
+RTDECL(bool) RTLockValidatorIsQuiet(void)
 {
     return ASMAtomicUoReadBool(&g_fLockValidatorQuiet);
 }
-RT_EXPORT_SYMBOL(RTLockValidatorAreQuiet);
+RT_EXPORT_SYMBOL(RTLockValidatorIsQuiet);
 
 
Index: /trunk/src/VBox/Runtime/testcase/tstRTLockValidator.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTLockValidator.cpp	(revision 25702)
+++ /trunk/src/VBox/Runtime/testcase/tstRTLockValidator.cpp	(revision 25703)
@@ -768,13 +768,31 @@
 static void testLo1(void)
 {
-    RTTestSub(g_hTest, "locking order, automatic");
-
-    /* init, each critsect has its own class now. */
+    RTTestSub(g_hTest, "locking order basics");
+
+    /* Initialize the critsections, the first 4 has their own classes, the rest
+       use the same class and relies on the sub-class mechanism for ordering.  */
     for (unsigned i = 0; i < RT_ELEMENTS(g_ahClasses); i++)
     {
-        RTTEST_CHECK_RC_RETV(g_hTest, RTLockValidatorClassCreate(&g_ahClasses[i], true /*fAutodidact*/, RT_SRC_POS), VINF_SUCCESS);
-        RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE, "RTCritSectLO"), VINF_SUCCESS);
-        RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 3);
-        RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 2);
+        if (i <= 3)
+        {
+            RTTEST_CHECK_RC_RETV(g_hTest, RTLockValidatorClassCreate(&g_ahClasses[i], true /*fAutodidact*/, RT_SRC_POS), VINF_SUCCESS);
+            RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE, "RTCritSectLO-Auto"), VINF_SUCCESS);
+            RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 3);
+            RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 2);
+        }
+        else
+        {
+            g_ahClasses[i] = RTLockValidatorClassForSrcPos(RT_SRC_POS);
+            RTTEST_CHECK_RETV(g_hTest, g_ahClasses[i] != NIL_RTLOCKVALCLASS);
+            RTTEST_CHECK_RETV(g_hTest, i == 4 || g_ahClasses[i] == g_ahClasses[i - 1]);
+            if (i == 4)
+                RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_NONE,     "RTCritSectLO-None"), VINF_SUCCESS);
+            else if (i == 5)
+                RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_ANY,      "RTCritSectLO-Any"), VINF_SUCCESS);
+            else
+                RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInitEx(&g_aCritSects[i], 0, g_ahClasses[i], RTLOCKVAL_SUB_CLASS_USER + i, "RTCritSectLO-User"), VINF_SUCCESS);
+
+            RTTEST_CHECK_RETV(g_hTest, RTLockValidatorClassRetain(g_ahClasses[i]) == 1 + (i - 4 + 1) * 2); /* released in cleanup. */
+        }
     }
 
@@ -807,14 +825,138 @@
 
     /* Check that recursion isn't subject to order checks. */
-
+    RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
+    if (RT_SUCCESS(rc))
+    {
+        RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
+
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
+    }
+    RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
 
     /* Enable strict release order for class 2 and check that violations
        are caught. */
-
+    RTTEST_CHECK_RC(g_hTest, RTLockValidatorClassEnforceStrictReleaseOrder(g_ahClasses[2], true), VINF_SUCCESS);
+
+    RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
+
+    RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
+    if (RT_FAILURE(rc))
+    {
+        /* applies to recursions as well */
+        RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VERR_SEM_LV_WRONG_RELEASE_ORDER);
+    }
+    RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
+    if (RT_FAILURE(rc))
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
+
+    /* Test that sub-class order works (4 = NONE, 5 = ANY, 6+ = USER). */
+    uint32_t cErrorsBefore = RTTestErrorCount(g_hTest);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[7]), VINF_SUCCESS);
+
+    RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[4]), VERR_SEM_LV_WRONG_ORDER);
+    if (RT_SUCCESS(rc))
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[4]), VINF_SUCCESS);
+
+    RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[5]), VINF_SUCCESS);
+    if (RT_SUCCESS(rc))
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
+
+    RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[8]), VINF_SUCCESS);
+    if (RT_SUCCESS(rc))
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[8]), VINF_SUCCESS);
+
+    RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[6]), VERR_SEM_LV_WRONG_ORDER);
+    if (RT_SUCCESS(rc))
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[6]), VINF_SUCCESS);
+
+    RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[7]), VINF_SUCCESS);
+    if (RT_SUCCESS(rc))
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[7]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[7]), VINF_SUCCESS);
+
+    /* Check that NONE trumps both ANY and USER. */
+    RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[4]), VINF_SUCCESS);
+
+    RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[5]), VERR_SEM_LV_WRONG_ORDER);
+    if (RT_SUCCESS(rc))
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
+
+    RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(&g_aCritSects[6]), VERR_SEM_LV_WRONG_ORDER);
+    if (RT_SUCCESS(rc))
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[6]), VINF_SUCCESS);
+
+    RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[4]), VINF_SUCCESS);
+
+    /* Take all the locks using sub-classes. */
+    if (cErrorsBefore == RTTestErrorCount(g_hTest))
+    {
+        bool fSavedQuiet = RTLockValidatorSetQuiet(true);
+        for (uint32_t i = 6; i < RT_ELEMENTS(g_aCritSects); i++)
+        {
+            RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[i]), VINF_SUCCESS);
+            RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[4]), VERR_SEM_LV_WRONG_ORDER);
+            RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[5]), VINF_SUCCESS);
+        }
+        for (uint32_t i = 6; i < RT_ELEMENTS(g_aCritSects); i++)
+        {
+            RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[i]), VINF_SUCCESS);
+            RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
+        }
+        RTLockValidatorSetQuiet(fSavedQuiet);
+    }
+
+    /* Work up some hash statistics and trigger a violation to show them. */
+    for (uint32_t i = 0; i < 10240; i++)
+    {
+        RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[0]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[1]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[2]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[5]), VINF_SUCCESS);
+
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[3]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[2]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[1]), VINF_SUCCESS);
+        RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[0]), VINF_SUCCESS);
+    }
+    RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[5]), VINF_SUCCESS);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectEnter(&g_aCritSects[3]), VERR_SEM_LV_WRONG_ORDER);
+    RTTEST_CHECK_RC(g_hTest, RTCritSectLeave(&g_aCritSects[5]), VINF_SUCCESS);
 
     /* clean up */
     for (unsigned i = 0; i < RT_ELEMENTS(g_ahClasses); i++)
     {
-        RTTEST_CHECK(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 1);
+        if (i <= 3)
+            RTTEST_CHECK(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == 1);
+        else
+        {
+            uint32_t cExpect = 1 + (RT_ELEMENTS(g_ahClasses) - i) * 2 - 1;
+            RTTEST_CHECK(g_hTest, RTLockValidatorClassRelease(g_ahClasses[i]) == cExpect);
+        }
         g_ahClasses[i] = NIL_RTLOCKVALCLASS;
         RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectDelete(&g_aCritSects[i]), VINF_SUCCESS);
