VirtualBox

Changeset 25614 in vbox for trunk/src/VBox/Runtime/common


Ignore:
Timestamp:
Jan 1, 2010 2:19:06 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
56305
Message:

iprt,pdmcritsect: More lock validator refactoring and debugging. Added hooks to semrw-generic.cpp. (Everything is still disabled.)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp

    r25611 r25614  
    254254    if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
    255255    {
    256         RTAssertMsg1Weak("RTLockValidator", pSrcPos->uLine, pSrcPos->pszFile, pSrcPos->pszFunction);
    257         if (pSrcPos->uId)
     256        RTAssertMsg1Weak("RTLockValidator", pSrcPos ? pSrcPos->uLine : 0, pSrcPos ? pSrcPos->pszFile : NULL, pSrcPos ? pSrcPos->pszFunction : NULL);
     257        if (pSrcPos && pSrcPos->uId)
    258258            RTAssertMsg2Weak("%s  [uId=%p  thrd=%s]\n", pszWhat, pSrcPos->uId, VALID_PTR(pThreadSelf) ? pThreadSelf->szName : "<NIL>");
    259259        else
    260             RTAssertMsg2Weak("%s\n", pszWhat, pSrcPos->uId);
     260            RTAssertMsg2Weak("%s  [thrd=%s]\n", pszWhat, VALID_PTR(pThreadSelf) ? pThreadSelf->szName : "<NIL>");
    261261        rtLockValidatorComplainAboutLock("Lock: ", pRec, "\n");
    262262    }
     
    296296 *
    297297 * @param   pDst                The destination.
    298  * @param   pSrc                The source.
     298 * @param   pSrc                The source.  Can be NULL.
    299299 */
    300300DECL_FORCE_INLINE(void) rtLockValidatorCopySrcPos(PRTLOCKVALSRCPOS pDst, PCRTLOCKVALSRCPOS pSrc)
    301301{
    302     ASMAtomicUoWriteU32(&pDst->uLine,                           pSrc->uLine);
    303     ASMAtomicUoWritePtr((void * volatile *)&pDst->pszFile,      pSrc->pszFile);
    304     ASMAtomicUoWritePtr((void * volatile *)&pDst->pszFunction,  pSrc->pszFunction);
    305     ASMAtomicUoWritePtr((void * volatile *)&pDst->uId,          (void *)pSrc->uId);
     302    if (pSrc)
     303    {
     304        ASMAtomicUoWriteU32(&pDst->uLine,                           pSrc->uLine);
     305        ASMAtomicUoWritePtr((void * volatile *)&pDst->pszFile,      pSrc->pszFile);
     306        ASMAtomicUoWritePtr((void * volatile *)&pDst->pszFunction,  pSrc->pszFunction);
     307        ASMAtomicUoWritePtr((void * volatile *)&pDst->uId,          (void *)pSrc->uId);
     308    }
     309    else
     310    {
     311        ASMAtomicUoWriteU32(&pDst->uLine,                           0);
     312        ASMAtomicUoWritePtr((void * volatile *)&pDst->pszFile,      NULL);
     313        ASMAtomicUoWritePtr((void * volatile *)&pDst->pszFunction,  NULL);
     314        ASMAtomicUoWritePtr((void * volatile *)&pDst->uId,          0);
     315    }
    306316}
    307317
     
    382392    Assert(pPerThread->cWriteLocks == 0);
    383393    Assert(pPerThread->cReadLocks == 0);
     394}
     395
     396
     397/**
     398 * Verifies the deadlock stack before calling it a deadlock.
     399 *
     400 * @retval  VERR_SEM_LV_DEADLOCK if it's a deadlock.
     401 * @retval  VERR_SEM_LV_ILLEGAL_UPGRADE if it's a deadlock on the same lock.
     402 * @retval  VERR_TRY_AGAIN if something changed.
     403 *
     404 * @param   pStack              The deadlock detection stack.
     405 */
     406static int rtLockValidatorDdVerifyDeadlock(PRTLOCKVALDDSTACK pStack)
     407{
     408    uint32_t const c = pStack->c;
     409    for (uint32_t iPass = 0; iPass < 3; iPass++)
     410    {
     411        for (uint32_t i = 1; i < c; i++)
     412        {
     413            PRTTHREADINT pThread = pStack->a[i].pThread;
     414            if (pThread->u32Magic != RTTHREADINT_MAGIC)
     415                return VERR_TRY_AGAIN;
     416            if (rtThreadGetState(pThread) != pStack->a[i].enmState)
     417                return VERR_TRY_AGAIN;
     418            if (rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pRec) != pStack->a[i].pFirstSibling)
     419                return VERR_TRY_AGAIN;
     420        }
     421        RTThreadYield();
     422    }
     423
     424    if (c == 1)
     425        return VERR_SEM_LV_ILLEGAL_UPGRADE;
     426    return VERR_SEM_LV_DEADLOCK;
     427}
     428
     429
     430/**
     431 * Checks for stack cycles caused by another deadlock before returning.
     432 *
     433 * @retval  VINF_SUCCESS if the stack is simply too small.
     434 * @retval  VERR_SEM_LV_EXISTING_DEADLOCK if a cycle was detected.
     435 *
     436 * @param   pStack              The deadlock detection stack.
     437 */
     438static int rtLockValidatorDdHandleStackOverflow(PRTLOCKVALDDSTACK pStack)
     439{
     440    for (size_t i = 0; i < RT_ELEMENTS(pStack->a) - 1; i++)
     441    {
     442        PRTTHREADINT pThread = pStack->a[i].pThread;
     443        for (size_t j = i + 1; j < RT_ELEMENTS(pStack->a); j++)
     444            if (pStack->a[j].pThread == pThread)
     445                return VERR_SEM_LV_EXISTING_DEADLOCK;
     446    }
     447    static bool volatile s_fComplained = false;
     448    if (!s_fComplained)
     449    {
     450        s_fComplained = true;
     451        rtLockValidatorComplain(RT_SRC_POS, "lock validator stack is too small! (%zu entries)\n", RT_ELEMENTS(pStack->a));
     452    }
     453    return VINF_SUCCESS;
     454}
     455
     456
     457/**
     458 * Worker for rtLockValidatorDoDeadlockCheck that checks if there is more work
     459 * to be done during unwind.
     460 *
     461 * @returns true if there is more work left for this lock, false if not.
     462 * @param   pRec            The current record.
     463 * @param   iEntry          The current index.
     464 * @param   pFirstSibling   The first record we examined.
     465 */
     466DECL_FORCE_INLINE(bool) rtLockValidatorDdMoreWorkLeft(PRTLOCKVALRECUNION pRec, uint32_t iEntry, PRTLOCKVALRECUNION pFirstSibling)
     467{
     468    PRTLOCKVALRECUNION pSibling;
     469
     470    switch (pRec->Core.u32Magic)
     471    {
     472        case RTLOCKVALRECEXCL_MAGIC:
     473            pSibling = pRec->Excl.pSibling;
     474            break;
     475
     476        case RTLOCKVALRECSHRD_MAGIC:
     477            if (iEntry + 1 < pRec->Shared.cAllocated)
     478                return true;
     479            pSibling = pRec->Excl.pSibling;
     480            break;
     481
     482        default:
     483            return false;
     484    }
     485    return pSibling != NULL
     486        && pSibling != pFirstSibling;
     487}
     488
     489
     490/**
     491 * Worker for rtLockValidatorDeadlockDetection that does the actual deadlock
     492 * detection.
     493 *
     494 * @retval  VINF_SUCCESS
     495 * @retval  VERR_SEM_LV_DEADLOCK
     496 * @retval  VERR_SEM_LV_EXISTING_DEADLOCK
     497 * @retval  VERR_SEM_LV_ILLEGAL_UPGRADE
     498 * @retval  VERR_TRY_AGAIN
     499 *
     500 * @param   pStack          The stack to use.
     501 * @param   pOriginalRec    The original record.
     502 * @param   pThreadSelf     The calling thread.
     503 */
     504static int rtLockValidatorDdDoDetection(PRTLOCKVALDDSTACK pStack, PRTLOCKVALRECUNION const pOriginalRec,
     505                                        PRTTHREADINT const pThreadSelf)
     506{
     507    pStack->c = 0;
     508
     509    /* We could use a single RTLOCKVALDDENTRY variable here, but the
     510       compiler may make a better job of it when using individual variables. */
     511    PRTLOCKVALRECUNION  pRec            = pOriginalRec;
     512    PRTLOCKVALRECUNION  pFirstSibling   = pOriginalRec;
     513    uint32_t            iEntry          = UINT32_MAX;
     514    PRTTHREADINT        pThread         = NIL_RTTHREAD;
     515    RTTHREADSTATE       enmState        = RTTHREADSTATE_RUNNING;
     516    for (;;)
     517    {
     518        /*
     519         * Process the current record.
     520         */
     521        /* Find the next relevant owner thread. */
     522        PRTTHREADINT pNextThread;
     523        switch (pRec->Core.u32Magic)
     524        {
     525            case RTLOCKVALRECEXCL_MAGIC:
     526                Assert(iEntry == UINT32_MAX);
     527                pNextThread = rtLockValidatorReadThreadHandle(&pRec->Excl.hThread);
     528                if (    pNextThread
     529                    &&  pNextThread->u32Magic == RTTHREADINT_MAGIC
     530                    &&  !RTTHREAD_IS_SLEEPING(pNextThread->enmState)
     531                    &&  pNextThread != pThreadSelf)
     532                    pNextThread = NIL_RTTHREAD;
     533
     534                if (    pNextThread == NIL_RTTHREAD
     535                    &&  pRec->Excl.pSibling
     536                    &&  pRec->Excl.pSibling != pFirstSibling)
     537                {
     538                    pRec = pRec->Excl.pSibling;
     539                    continue;
     540                }
     541                break;
     542
     543            case RTLOCKVALRECSHRD_MAGIC:
     544                /* Skip to the next sibling if same side.  ASSUMES reader priority. */
     545                /** @todo The read side of a read-write lock is problematic if
     546                 * the implementation prioritizes writers over readers because
     547                 * that means we should could deadlock against current readers
     548                 * if a writer showed up.  If the RW sem implementation is
     549                 * wrapping some native API, it's not so easy to detect when we
     550                 * should do this and when we shouldn't.  Checking when we
     551                 * shouldn't is subject to wakeup scheduling and cannot easily
     552                 * be made reliable.
     553                 *
     554                 * At the moment we circumvent all this mess by declaring that
     555                 * readers has priority.  This is TRUE on linux, but probably
     556                 * isn't on Solaris and FreeBSD. */
     557                if (   pRec == pFirstSibling
     558                    && pRec->Shared.pSibling != NULL
     559                    && pRec->Shared.pSibling != pFirstSibling)
     560                {
     561                    pRec = pRec->Shared.pSibling;
     562                    Assert(iEntry == UINT32_MAX);
     563                    continue;
     564                }
     565
     566                /* Scan the owner table for blocked owners. */
     567                pNextThread = NIL_RTTHREAD;
     568                if (ASMAtomicUoReadU32(&pRec->Shared.cEntries) > 0)
     569                {
     570                    uint32_t                        cAllocated = ASMAtomicUoReadU32(&pRec->Shared.cAllocated);
     571                    PRTLOCKVALRECSHRDOWN volatile  *papOwners  = pRec->Shared.papOwners;
     572                    while (++iEntry < cAllocated)
     573                    {
     574                        PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorUoReadSharedOwner(&papOwners[iEntry]);
     575                        if (   pEntry
     576                            && pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC)
     577                        {
     578                            pNextThread = rtLockValidatorReadThreadHandle(&pEntry->hThread);
     579                            if (pNextThread)
     580                            {
     581                                if (   pNextThread->u32Magic == RTTHREADINT_MAGIC
     582                                    && (   RTTHREAD_IS_SLEEPING(pNextThread->enmState)
     583                                        || pNextThread == pThreadSelf))
     584                                    break;
     585                                pNextThread = NIL_RTTHREAD;
     586                            }
     587                        }
     588                        else
     589                            Assert(!pEntry || pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC_DEAD);
     590                    }
     591                    if (pNextThread == NIL_RTTHREAD)
     592                        break;
     593                }
     594
     595                /* Advance to the next sibling, if any. */
     596                if (   pRec->Shared.pSibling != NULL
     597                    && pRec->Shared.pSibling != pFirstSibling)
     598                {
     599                    pRec = pRec->Shared.pSibling;
     600                    iEntry = UINT32_MAX;
     601                    continue;
     602                }
     603                break;
     604
     605            case RTLOCKVALRECEXCL_MAGIC_DEAD:
     606            case RTLOCKVALRECSHRD_MAGIC_DEAD:
     607                pNextThread = NIL_RTTHREAD;
     608                break;
     609
     610            case RTLOCKVALRECSHRDOWN_MAGIC:
     611            case RTLOCKVALRECSHRDOWN_MAGIC_DEAD:
     612            default:
     613                AssertMsgFailed(("%p: %#x\n", pRec, pRec->Core));
     614                pNextThread = NIL_RTTHREAD;
     615                break;
     616        }
     617
     618        /* If we found a thread, check if it is still waiting for something. */
     619        RTTHREADSTATE       enmNextState = RTTHREADSTATE_RUNNING;
     620        PRTLOCKVALRECUNION  pNextRec     = NULL;
     621        if (   pNextThread != NIL_RTTHREAD
     622            && RT_LIKELY(pNextThread->u32Magic == RTTHREADINT_MAGIC))
     623        {
     624            do
     625            {
     626                enmNextState = rtThreadGetState(pNextThread);
     627                if (    !RTTHREAD_IS_SLEEPING(enmNextState)
     628                    &&  pNextThread != pThreadSelf)
     629                    break;
     630                pNextRec = rtLockValidatorReadRecUnionPtr(&pNextThread->LockValidator.pRec);
     631                if (RT_LIKELY(   !pNextRec
     632                              || enmNextState == rtThreadGetState(pNextThread)))
     633                    break;
     634                pNextRec = NULL;
     635            } while (pNextThread->u32Magic == RTTHREADINT_MAGIC);
     636        }
     637        if (pNextRec)
     638        {
     639            /*
     640             * Recurse and check for deadlock.
     641             */
     642            uint32_t i = pStack->c;
     643            if (RT_UNLIKELY(i >= RT_ELEMENTS(pStack->a)))
     644                return rtLockValidatorDdHandleStackOverflow(pStack);
     645
     646            pStack->c++;
     647            pStack->a[i].pRec           = pRec;
     648            pStack->a[i].iEntry         = iEntry;
     649            pStack->a[i].enmState       = enmState;
     650            pStack->a[i].pThread        = pThread;
     651            pStack->a[i].pFirstSibling  = pFirstSibling;
     652
     653            if (RT_UNLIKELY(pNextThread == pThreadSelf))
     654                return rtLockValidatorDdVerifyDeadlock(pStack);
     655
     656            pRec            = pNextRec;
     657            pFirstSibling   = pNextRec;
     658            iEntry          = UINT32_MAX;
     659            enmState        = enmNextState;
     660            pThread         = pNextThread;
     661        }
     662        else if (RT_LIKELY(!pNextThread))
     663        {
     664            /*
     665             * No deadlock here, unwind the stack and deal with any unfinished
     666             * business there.
     667             */
     668            uint32_t i = pStack->c;
     669            for (;;)
     670            {
     671                /* pop */
     672                if (i == 0)
     673                    return VINF_SUCCESS;
     674                i--;
     675
     676                /* examine it. */
     677                pRec            = pStack->a[i].pRec;
     678                pFirstSibling   = pStack->a[i].pFirstSibling;
     679                iEntry          = pStack->a[i].iEntry;
     680                if (rtLockValidatorDdMoreWorkLeft(pRec, iEntry, pFirstSibling))
     681                {
     682                    enmState    = pStack->a[i].enmState;
     683                    pThread     = pStack->a[i].pThread;
     684                    pStack->c   = i;
     685                    break;
     686                }
     687            }
     688        }
     689        /* else: see if there is another thread to check for this lock. */
     690    }
     691}
     692
     693
     694/**
     695 * Check for the simple no-deadlock case.
     696 *
     697 * @returns true if no deadlock, false if further investigation is required.
     698 *
     699 * @param   pOriginalRec    The original record.
     700 */
     701DECLINLINE(int) rtLockValidatorIsSimpleNoDeadlockCase(PRTLOCKVALRECUNION pOriginalRec)
     702{
     703    if (    pOriginalRec->Excl.Core.u32Magic == RTLOCKVALRECEXCL_MAGIC
     704        &&  !pOriginalRec->Excl.pSibling)
     705    {
     706        PRTTHREADINT pThread = rtLockValidatorReadThreadHandle(&pOriginalRec->Excl.hThread);
     707        if (   !pThread
     708            || pThread->u32Magic != RTTHREADINT_MAGIC)
     709            return true;
     710        RTTHREADSTATE enmState = rtThreadGetState(pThread);
     711        if (!RTTHREAD_IS_SLEEPING(enmState))
     712            return true;
     713    }
     714    return false;
     715}
     716
     717
     718/**
     719 * Worker for rtLockValidatorDeadlockDetection that bitches about a deadlock.
     720 *
     721 * @param   pStack          The chain of locks causing the deadlock.
     722 * @param   pRec            The record relating to the current thread's lock
     723 *                          operation.
     724 * @param   pThreadSelf     This thread.
     725 * @param   pSrcPos         Where we are going to deadlock.
     726 * @param   rc              The return code.
     727 */
     728static void rcLockValidatorDoDeadlockComplaining(PRTLOCKVALDDSTACK pStack, PRTLOCKVALRECUNION pRec,
     729                                                 PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos, int rc)
     730{
     731    if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
     732    {
     733        const char *pszWhat;
     734        switch (rc)
     735        {
     736            case VERR_SEM_LV_DEADLOCK:          pszWhat = "Detected deadlock!"; break;
     737            case VERR_SEM_LV_EXISTING_DEADLOCK: pszWhat = "Found existing deadlock!"; break;
     738            case VERR_SEM_LV_ILLEGAL_UPGRADE:   pszWhat = "Illegal lock upgrade!"; break;
     739            default:            AssertFailed(); pszWhat = "!unexpected rc!"; break;
     740        }
     741        rtLockValidatorComplainFirst(pszWhat, pSrcPos, pThreadSelf, pStack->a[0].pRec != pRec ? pRec : NULL);
     742        rtLockValidatorComplainMore("---- start of deadlock chain - %u entries ----\n", pStack->c);
     743        for (uint32_t i = 0; i < pStack->c; i++)
     744        {
     745            char szPrefix[24];
     746            RTStrPrintf(szPrefix, sizeof(szPrefix), "#%02u: ", i);
     747            PRTLOCKVALRECSHRDOWN pShrdOwner = NULL;
     748            if (pStack->a[i].pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC)
     749                pShrdOwner = pStack->a[i].pRec->Shared.papOwners[pStack->a[i].iEntry];
     750            if (VALID_PTR(pShrdOwner) && pShrdOwner->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC)
     751                rtLockValidatorComplainAboutLock(szPrefix, (PRTLOCKVALRECUNION)pShrdOwner, "\n");
     752            else
     753                rtLockValidatorComplainAboutLock(szPrefix, pStack->a[i].pRec, "\n");
     754        }
     755        rtLockValidatorComplainMore("---- end of deadlock chain ----\n");
     756    }
     757
     758    rtLockValidatorComplainPanic();
     759}
     760
     761
     762/**
     763 * Perform deadlock detection.
     764 *
     765 * @retval  VINF_SUCCESS
     766 * @retval  VERR_SEM_LV_DEADLOCK
     767 * @retval  VERR_SEM_LV_EXISTING_DEADLOCK
     768 * @retval  VERR_SEM_LV_ILLEGAL_UPGRADE
     769 *
     770 * @param   pRec            The record relating to the current thread's lock
     771 *                          operation.
     772 * @param   pThreadSelf     The current thread.
     773 * @param   pSrcPos         The position of the current lock operation.
     774 */
     775static int rtLockValidatorDeadlockDetection(PRTLOCKVALRECUNION pRec, PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos)
     776{
     777#ifdef DEBUG_bird
     778    RTLOCKVALDDSTACK Stack;
     779    int rc = rtLockValidatorDdDoDetection(&Stack, pRec, pThreadSelf);
     780    if (RT_SUCCESS(rc))
     781        return VINF_SUCCESS;
     782
     783    if (rc == VERR_TRY_AGAIN)
     784    {
     785        for (uint32_t iLoop = 0; ; iLoop++)
     786        {
     787            rc = rtLockValidatorDdDoDetection(&Stack, pRec, pThreadSelf);
     788            if (RT_SUCCESS_NP(rc))
     789                return VINF_SUCCESS;
     790            if (rc != VERR_TRY_AGAIN)
     791                break;
     792            RTThreadYield();
     793            if (iLoop >= 3)
     794                return VINF_SUCCESS;
     795        }
     796    }
     797
     798    rcLockValidatorDoDeadlockComplaining(&Stack, pRec, pThreadSelf, pSrcPos, rc);
     799    return rc;
     800#else
     801    return VINF_SUCCESS;
     802#endif
    384803}
    385804
     
    539958
    540959
     960RTDECL(void) RTLockValidatorRecExclSetOwner(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf,
     961                                            PCRTLOCKVALSRCPOS pSrcPos, bool fFirstRecursion)
     962{
     963    AssertReturnVoid(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC);
     964    if (!pRec->fEnabled)
     965        return;
     966    if (hThreadSelf == NIL_RTTHREAD)
     967    {
     968        hThreadSelf = RTThreadSelfAutoAdopt();
     969        AssertReturnVoid(hThreadSelf != NIL_RTTHREAD);
     970    }
     971    Assert(hThreadSelf == RTThreadSelf());
     972
     973    ASMAtomicIncS32(&hThreadSelf->LockValidator.cWriteLocks);
     974
     975    if (pRec->hThread == hThreadSelf)
     976    {
     977        Assert(!fFirstRecursion);
     978        pRec->cRecursion++;
     979    }
     980    else
     981    {
     982        Assert(pRec->hThread == NIL_RTTHREAD);
     983
     984        /*
     985         * Update the record.
     986         */
     987        rtLockValidatorCopySrcPos(&pRec->SrcPos, pSrcPos);
     988        ASMAtomicUoWriteU32(&pRec->cRecursion, 1);
     989        ASMAtomicWriteHandle(&pRec->hThread, hThreadSelf);
     990
     991        /*
     992         * Push the lock onto the lock stack.
     993         */
     994        /** @todo push it onto the per-thread lock stack. */
     995    }
     996}
     997
     998
     999RTDECL(int)  RTLockValidatorRecExclReleaseOwner(PRTLOCKVALRECEXCL pRec, bool fFinalRecursion)
     1000{
     1001    AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1002    if (!pRec->fEnabled)
     1003        return VINF_SUCCESS;
     1004    AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
     1005
     1006    RTLockValidatorRecExclReleaseOwnerUnchecked(pRec);
     1007    return VINF_SUCCESS;
     1008}
     1009
     1010
     1011RTDECL(void) RTLockValidatorRecExclReleaseOwnerUnchecked(PRTLOCKVALRECEXCL pRec)
     1012{
     1013    AssertReturnVoid(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC);
     1014    if (!pRec->fEnabled)
     1015        return;
     1016    RTTHREADINT *pThread = pRec->hThread;
     1017    AssertReturnVoid(pThread != NIL_RTTHREAD);
     1018    Assert(pThread == RTThreadSelf());
     1019
     1020    ASMAtomicDecS32(&pThread->LockValidator.cWriteLocks);
     1021
     1022    if (ASMAtomicDecU32(&pRec->cRecursion) == 0)
     1023    {
     1024        /*
     1025         * Pop (remove) the lock.
     1026         */
     1027        /** @todo remove it from the per-thread stack/whatever. */
     1028
     1029        /*
     1030         * Update the record.
     1031         */
     1032        ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD);
     1033    }
     1034}
     1035
     1036
     1037RTDECL(int) RTLockValidatorRecExclRecursion(PRTLOCKVALRECEXCL pRec, PCRTLOCKVALSRCPOS pSrcPos)
     1038{
     1039    AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1040    if (!pRec->fEnabled)
     1041        return VINF_SUCCESS;
     1042    AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
     1043
     1044    Assert(pRec->cRecursion < _1M);
     1045    pRec->cRecursion++;
     1046
     1047    return VINF_SUCCESS;
     1048}
     1049
     1050
     1051RTDECL(int) RTLockValidatorRecExclUnwind(PRTLOCKVALRECEXCL pRec)
     1052{
     1053    AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1054    if (!pRec->fEnabled)
     1055        return VINF_SUCCESS;
     1056    AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
     1057    AssertReturn(pRec->cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER);
     1058
     1059    Assert(pRec->cRecursion);
     1060    pRec->cRecursion--;
     1061    return VINF_SUCCESS;
     1062}
     1063
     1064
     1065RTDECL(int) RTLockValidatorRecExclRecursionMixed(PRTLOCKVALRECEXCL pRec, PRTLOCKVALRECCORE pRecMixed, PCRTLOCKVALSRCPOS pSrcPos)
     1066{
     1067    AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1068    PRTLOCKVALRECUNION pRecMixedU = (PRTLOCKVALRECUNION)pRecMixed;
     1069    AssertReturn(   pRecMixedU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC
     1070                 || pRecMixedU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC
     1071                 , VERR_SEM_LV_INVALID_PARAMETER);
     1072    if (!pRec->fEnabled)
     1073        return VINF_SUCCESS;
     1074    AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
     1075    AssertReturn(pRec->cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER);
     1076
     1077    Assert(pRec->cRecursion < _1M);
     1078    pRec->cRecursion++;
     1079
     1080    return VINF_SUCCESS;
     1081}
     1082
     1083
     1084RTDECL(int) RTLockValidatorRecExclUnwindMixed(PRTLOCKVALRECEXCL pRec, PRTLOCKVALRECCORE pRecMixed)
     1085{
     1086    AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1087    PRTLOCKVALRECUNION pRecMixedU = (PRTLOCKVALRECUNION)pRecMixed;
     1088    AssertReturn(   pRecMixedU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC
     1089                 || pRecMixedU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC
     1090                 , VERR_SEM_LV_INVALID_PARAMETER);
     1091    if (!pRec->fEnabled)
     1092        return VINF_SUCCESS;
     1093    AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
     1094    AssertReturn(pRec->cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER);
     1095
     1096    Assert(pRec->cRecursion);
     1097    pRec->cRecursion--;
     1098    return VINF_SUCCESS;
     1099}
     1100
     1101
     1102RTDECL(int) RTLockValidatorRecExclCheckOrder(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, PCRTLOCKVALSRCPOS pSrcPos)
     1103{
     1104    AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1105    if (!pRec->fEnabled)
     1106        return VINF_SUCCESS;
     1107
     1108    /*
     1109     * Check it locks we're currently holding.
     1110     */
     1111    /** @todo later */
     1112
     1113    /*
     1114     * If missing order rules, add them.
     1115     */
     1116
     1117    return VINF_SUCCESS;
     1118}
     1119
     1120
     1121RTDECL(int) RTLockValidatorRecExclCheckBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf,
     1122                                                PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk)
     1123{
     1124    /*
     1125     * Fend off wild life.
     1126     */
     1127    PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
     1128    AssertPtrReturn(pRecU, VERR_SEM_LV_INVALID_PARAMETER);
     1129    AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1130    if (!pRecU->Excl.fEnabled)
     1131        return VINF_SUCCESS;
     1132
     1133    PRTTHREADINT pThreadSelf = hThreadSelf;
     1134    AssertPtrReturn(pThreadSelf, VERR_SEM_LV_INVALID_PARAMETER);
     1135    AssertReturn(pThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1136    Assert(pThreadSelf == RTThreadSelf());
     1137
     1138    RTTHREADSTATE enmThreadState = rtThreadGetState(pThreadSelf);
     1139    AssertReturn(   enmThreadState == RTTHREADSTATE_RUNNING
     1140                 || enmThreadState == RTTHREADSTATE_TERMINATED   /* rtThreadRemove uses locks too */
     1141                 || enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */
     1142                 , VERR_SEM_LV_INVALID_PARAMETER);
     1143
     1144    /*
     1145     * Record the location.
     1146     */
     1147    rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, pRecU);
     1148    rtLockValidatorCopySrcPos(&pThreadSelf->LockValidator.SrcPos, pSrcPos);
     1149
     1150    /*
     1151     * Don't do deadlock detection if we're recursing.
     1152     *
     1153     * On some hosts we don't do recursion accounting our selves and there
     1154     * isn't any other place to check for this.  semmutex-win.cpp for instance.
     1155     */
     1156    if (rtLockValidatorReadThreadHandle(&pRecU->Excl.hThread) == pThreadSelf)
     1157    {
     1158        if (fRecursiveOk)
     1159            return VINF_SUCCESS;
     1160        rtLockValidatorComplainFirst("Recursion not allowed", pSrcPos, pThreadSelf, pRecU);
     1161        rtLockValidatorComplainPanic();
     1162        return VERR_SEM_LV_NESTED;
     1163    }
     1164
     1165    /*
     1166     * Perform deadlock detection.
     1167     */
     1168    if (rtLockValidatorIsSimpleNoDeadlockCase(pRecU))
     1169        return VINF_SUCCESS;
     1170    return rtLockValidatorDeadlockDetection(pRecU, pThreadSelf, pSrcPos);
     1171}
     1172RT_EXPORT_SYMBOL(RTLockValidatorRecExclCheckBlocking);
     1173
     1174
     1175RTDECL(int) RTLockValidatorRecExclCheckOrderAndBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf,
     1176                                                        PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk)
     1177{
     1178    int rc = RTLockValidatorRecExclCheckOrder(pRec, hThreadSelf, pSrcPos);
     1179    if (RT_SUCCESS(rc))
     1180        rc = RTLockValidatorRecExclCheckBlocking(pRec, hThreadSelf, pSrcPos, fRecursiveOk);
     1181    return rc;
     1182}
     1183RT_EXPORT_SYMBOL(RTLockValidatorRecExclCheckOrderAndBlocking);
     1184
     1185
    5411186RTDECL(void) RTLockValidatorRecSharedInit(PRTLOCKVALRECSHRD pRec, RTLOCKVALIDATORCLASS hClass,
    5421187                                          uint32_t uSubClass, const char *pszName, void *hLock)
     
    6361281
    6371282
     1283RTDECL(int) RTLockValidatorRecSharedCheckOrder(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, PCRTLOCKVALSRCPOS pSrcPos)
     1284{
     1285    AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1286    if (!pRec->fEnabled)
     1287        return VINF_SUCCESS;
     1288    Assert(hThreadSelf == NIL_RTTHREAD || hThreadSelf == RTThreadSelf());
     1289
     1290    /*
     1291     * Check it locks we're currently holding.
     1292     */
     1293    /** @todo later */
     1294
     1295    /*
     1296     * If missing order rules, add them.
     1297     */
     1298
     1299    return VINF_SUCCESS;
     1300}
     1301
     1302
     1303RTDECL(int) RTLockValidatorRecSharedCheckBlocking(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf,
     1304                                                  PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk)
     1305{
     1306    /*
     1307     * Fend off wild life.
     1308     */
     1309    PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
     1310    AssertPtrReturn(pRecU, VERR_SEM_LV_INVALID_PARAMETER);
     1311    AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1312    if (!pRecU->Shared.fEnabled)
     1313        return VINF_SUCCESS;
     1314
     1315    PRTTHREADINT pThreadSelf = hThreadSelf;
     1316    AssertPtrReturn(pThreadSelf, VERR_SEM_LV_INVALID_PARAMETER);
     1317    AssertReturn(pThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1318    Assert(pThreadSelf == RTThreadSelf());
     1319
     1320    RTTHREADSTATE enmThreadState = rtThreadGetState(pThreadSelf);
     1321    AssertReturn(   enmThreadState == RTTHREADSTATE_RUNNING
     1322                 || enmThreadState == RTTHREADSTATE_TERMINATED   /* rtThreadRemove uses locks too */
     1323                 || enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */
     1324                 , VERR_SEM_LV_INVALID_PARAMETER);
     1325
     1326    /*
     1327     * Record the location.
     1328     */
     1329    rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, pRecU);
     1330    rtLockValidatorCopySrcPos(&pThreadSelf->LockValidator.SrcPos, pSrcPos);
     1331
     1332    /*
     1333     * Don't do deadlock detection if we're recursing.
     1334     */
     1335    PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(&pRecU->Shared, pThreadSelf, NULL);
     1336    if (pEntry)
     1337    {
     1338        if (fRecursiveOk)
     1339            return VINF_SUCCESS;
     1340        rtLockValidatorComplainFirst("Recursion not allowed", pSrcPos, pThreadSelf, pRecU);
     1341        rtLockValidatorComplainPanic();
     1342        return VERR_SEM_LV_NESTED;
     1343    }
     1344
     1345    /*
     1346     * Perform deadlock detection.
     1347     */
     1348    if (rtLockValidatorIsSimpleNoDeadlockCase(pRecU))
     1349        return VINF_SUCCESS;
     1350    return rtLockValidatorDeadlockDetection(pRecU, pThreadSelf, pSrcPos);
     1351}
     1352RT_EXPORT_SYMBOL(RTLockValidatorRecSharedCheckBlocking);
     1353
     1354
     1355RTDECL(int) RTLockValidatorRecSharedCheckOrderAndBlocking(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk)
     1356{
     1357    int rc = RTLockValidatorRecSharedCheckOrder(pRec, hThreadSelf, pSrcPos);
     1358    if (RT_SUCCESS(rc))
     1359        rc = RTLockValidatorRecSharedCheckBlocking(pRec, hThreadSelf, pSrcPos, fRecursiveOk);
     1360    return rc;
     1361}
     1362RT_EXPORT_SYMBOL(RTLockValidatorRecSharedCheckOrderAndBlocking);
     1363
     1364
    6381365/**
    6391366 * Allocates and initializes an owner entry for the shared lock record.
     
    6571384    {
    6581385        iEntry--;
    659         pThreadSelf->LockValidator.bmFreeShrdOwners |= RT_BIT_32(iEntry);
     1386        pThreadSelf->LockValidator.bmFreeShrdOwners &= ~RT_BIT_32(iEntry);
    6601387        pEntry = &pThreadSelf->LockValidator.aShrdOwners[iEntry];
    6611388        Assert(!pEntry->fReserved);
     
    7021429        Assert(pThreadSelf == RTThreadSelf());
    7031430
     1431        Assert(pEntry->fReserved);
    7041432        pEntry->fReserved = false;
    7051433
    706         Assert(pEntry->fReserved);
    7071434        if (pEntry->fStaticAlloc)
    7081435        {
    7091436            uintptr_t iEntry = pEntry - &pThreadSelf->LockValidator.aShrdOwners[0];
    7101437            AssertReleaseReturnVoid(iEntry < RT_ELEMENTS(pThreadSelf->LockValidator.aShrdOwners));
    711             pThreadSelf->LockValidator.bmFreeShrdOwners &= ~RT_BIT_32(iEntry);
     1438            pThreadSelf->LockValidator.bmFreeShrdOwners |= RT_BIT_32(iEntry);
    7121439        }
    7131440        else
     
    8761603
    8771604
    878 RTDECL(int) RTLockValidatorCheckOrder(PRTLOCKVALRECEXCL pRec, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos)
    879 {
    880     AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1605RTDECL(void) RTLockValidatorSharedRecAddOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, PCRTLOCKVALSRCPOS pSrcPos)
     1606{
     1607    AssertReturnVoid(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC);
    8811608    if (!pRec->fEnabled)
    882         return VINF_SUCCESS;
    883 
    884     /*
    885      * Check it locks we're currently holding.
    886      */
    887     /** @todo later */
    888 
    889     /*
    890      * If missing order rules, add them.
    891      */
    892 
    893     return VINF_SUCCESS;
    894 }
    895 
    896 
    897 RTDECL(int)  RTLockValidatorCheckAndRelease(PRTLOCKVALRECEXCL pRec)
    898 {
    899     AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1609        return;
     1610    AssertReturnVoid(hThreadSelf != NIL_RTTHREAD);
     1611    AssertReturnVoid(hThreadSelf->u32Magic == RTTHREADINT_MAGIC);
     1612    Assert(hThreadSelf == RTThreadSelf());
     1613
     1614    /*
     1615     * Recursive?
     1616     *
     1617     * Note! This code can be optimized to try avoid scanning the table on
     1618     *       insert.  However, that's annoying work that makes the code big,
     1619     *       so it can wait til later sometime.
     1620     */
     1621    PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(pRec, hThreadSelf, NULL);
     1622    if (pEntry)
     1623    {
     1624        pEntry->cRecursion++;
     1625        return;
     1626    }
     1627
     1628    /*
     1629     * Allocate a new owner entry and insert it into the table.
     1630     */
     1631    pEntry = rtLockValidatorRecSharedAllocOwner(pRec, hThreadSelf, pSrcPos);
     1632    if (    pEntry
     1633        &&  !rtLockValidatorRecSharedAddOwner(pRec, pEntry))
     1634        rtLockValidatorRecSharedFreeOwner(pEntry);
     1635}
     1636RT_EXPORT_SYMBOL(RTLockValidatorSharedRecAddOwner);
     1637
     1638
     1639RTDECL(void) RTLockValidatorSharedRecRemoveOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf)
     1640{
     1641    AssertReturnVoid(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC);
    9001642    if (!pRec->fEnabled)
    901         return VINF_SUCCESS;
    902     AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
    903 
    904     RTLockValidatorUnsetOwner(pRec);
    905     return VINF_SUCCESS;
    906 }
    907 
    908 
    909 RTDECL(int)  RTLockValidatorCheckAndReleaseReadOwner(PRTLOCKVALRECSHRD pRead, RTTHREAD hThread)
     1643        return;
     1644    AssertReturnVoid(hThreadSelf != NIL_RTTHREAD);
     1645    AssertReturnVoid(hThreadSelf->u32Magic == RTTHREADINT_MAGIC);
     1646    Assert(hThreadSelf == RTThreadSelf());
     1647
     1648    /*
     1649     * Find the entry hope it's a recursive one.
     1650     */
     1651    uint32_t iEntry = UINT32_MAX; /* shuts up gcc */
     1652    PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(pRec, hThreadSelf, &iEntry);
     1653    AssertReturnVoid(pEntry);
     1654    if (pEntry->cRecursion > 1)
     1655        pEntry->cRecursion--;
     1656    else
     1657        rtLockValidatorRecSharedRemoveAndFreeOwner(pRec, pEntry, iEntry);
     1658}
     1659RT_EXPORT_SYMBOL(RTLockValidatorSharedRecRemoveOwner);
     1660
     1661
     1662RTDECL(int) RTLockValidatorRecSharedCheckAndRelease(PRTLOCKVALRECSHRD pRead, RTTHREAD hThreadSelf)
    9101663{
    9111664    AssertReturn(pRead->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    9121665    if (!pRead->fEnabled)
    9131666        return VINF_SUCCESS;
    914     AssertReturn(hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
     1667    if (hThreadSelf == NIL_RTTHREAD)
     1668    {
     1669        hThreadSelf = RTThreadSelfAutoAdopt();
     1670        AssertReturn(hThreadSelf != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
     1671    }
     1672    Assert(hThreadSelf == RTThreadSelf());
    9151673
    9161674    /*
     
    9181676     */
    9191677    uint32_t                iEntry = 0;
    920     PRTLOCKVALRECSHRDOWN    pEntry = rtLockValidatorRecSharedFindOwner(pRead, hThread, &iEntry);
     1678    PRTLOCKVALRECSHRDOWN    pEntry = rtLockValidatorRecSharedFindOwner(pRead, hThreadSelf, &iEntry);
    9211679    AssertReturn(pEntry, VERR_SEM_LV_NOT_OWNER);
    9221680
     
    9391697
    9401698    return VINF_SUCCESS;
    941 }
    942 
    943 
    944 RTDECL(int) RTLockValidatorRecordRecursion(PRTLOCKVALRECEXCL pRec, PCRTLOCKVALSRCPOS pSrcPos)
    945 {
    946     AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    947     if (!pRec->fEnabled)
    948         return VINF_SUCCESS;
    949     AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
    950 
    951     Assert(pRec->cRecursion < _1M);
    952     pRec->cRecursion++;
    953 
    954     return VINF_SUCCESS;
    955 }
    956 
    957 
    958 RTDECL(int) RTLockValidatorUnwindRecursion(PRTLOCKVALRECEXCL pRec)
    959 {
    960     AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    961     if (!pRec->fEnabled)
    962         return VINF_SUCCESS;
    963     AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
    964     AssertReturn(pRec->cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER);
    965 
    966     Assert(pRec->cRecursion);
    967     pRec->cRecursion--;
    968     return VINF_SUCCESS;
    969 }
    970 
    971 
    972 RTDECL(int) RTLockValidatorRecordReadWriteRecursion(PRTLOCKVALRECEXCL pWrite, PRTLOCKVALRECSHRD pRead, PCRTLOCKVALSRCPOS pSrcPos)
    973 {
    974     AssertReturn(pWrite->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    975     AssertReturn(pRead->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    976     AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER);
    977     if (!pWrite->fEnabled)
    978         return VINF_SUCCESS;
    979     AssertReturn(pWrite->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
    980     AssertReturn(pWrite->cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER);
    981 
    982     Assert(pWrite->cRecursion < _1M);
    983     pWrite->cRecursion++;
    984 
    985     return VINF_SUCCESS;
    986 }
    987 
    988 
    989 RTDECL(int) RTLockValidatorUnwindReadWriteRecursion(PRTLOCKVALRECEXCL pWrite, PRTLOCKVALRECSHRD pRead)
    990 {
    991     AssertReturn(pWrite->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    992     AssertReturn(pRead->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    993     AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER);
    994     if (!pWrite->fEnabled)
    995         return VINF_SUCCESS;
    996     AssertReturn(pWrite->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
    997     AssertReturn(pWrite->cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER);
    998 
    999     Assert(pWrite->cRecursion);
    1000     pWrite->cRecursion--;
    1001     return VINF_SUCCESS;
    1002 }
    1003 
    1004 
    1005 RTDECL(RTTHREAD) RTLockValidatorSetOwner(PRTLOCKVALRECEXCL pRec, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos)
    1006 {
    1007     AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, NIL_RTTHREAD);
    1008     if (!pRec->fEnabled)
    1009         return VINF_SUCCESS;
    1010     if (hThread == NIL_RTTHREAD)
    1011     {
    1012         hThread = RTThreadSelfAutoAdopt();
    1013         AssertReturn(hThread != NIL_RTTHREAD, hThread);
    1014     }
    1015 
    1016     ASMAtomicIncS32(&hThread->LockValidator.cWriteLocks);
    1017 
    1018     if (pRec->hThread == hThread)
    1019         pRec->cRecursion++;
    1020     else
    1021     {
    1022         Assert(pRec->hThread == NIL_RTTHREAD);
    1023 
    1024         /*
    1025          * Update the record.
    1026          */
    1027         rtLockValidatorCopySrcPos(&pRec->SrcPos, pSrcPos);
    1028         ASMAtomicUoWriteU32(&pRec->cRecursion, 1);
    1029         ASMAtomicWriteHandle(&pRec->hThread, hThread);
    1030 
    1031         /*
    1032          * Push the lock onto the lock stack.
    1033          */
    1034         /** @todo push it onto the per-thread lock stack. */
    1035     }
    1036 
    1037     return hThread;
    1038 }
    1039 
    1040 
    1041 RTDECL(RTTHREAD) RTLockValidatorUnsetOwner(PRTLOCKVALRECEXCL pRec)
    1042 {
    1043     AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, NIL_RTTHREAD);
    1044     if (!pRec->fEnabled)
    1045         return VINF_SUCCESS;
    1046     RTTHREADINT *pThread = pRec->hThread;
    1047     AssertReturn(pThread != NIL_RTTHREAD, pThread);
    1048 
    1049     ASMAtomicDecS32(&pThread->LockValidator.cWriteLocks);
    1050 
    1051     if (ASMAtomicDecU32(&pRec->cRecursion) == 0)
    1052     {
    1053         /*
    1054          * Pop (remove) the lock.
    1055          */
    1056         /** @todo remove it from the per-thread stack/whatever. */
    1057 
    1058         /*
    1059          * Update the record.
    1060          */
    1061         ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD);
    1062     }
    1063 
    1064     return pThread;
    1065 }
    1066 
    1067 
    1068 RTDECL(void) RTLockValidatorAddReadOwner(PRTLOCKVALRECSHRD pRead, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos)
    1069 {
    1070     AssertReturnVoid(pRead->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC);
    1071     if (!pRead->fEnabled)
    1072         return;
    1073     AssertReturnVoid(hThread != NIL_RTTHREAD);
    1074     AssertReturnVoid(hThread->u32Magic == RTTHREADINT_MAGIC);
    1075 
    1076     /*
    1077      * Recursive?
    1078      *
    1079      * Note! This code can be optimized to try avoid scanning the table on
    1080      *       insert. However, that's annoying work that makes the code big,
    1081      *       so it can wait til later sometime.
    1082      */
    1083     PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(pRead, hThread, NULL);
    1084     if (pEntry)
    1085     {
    1086         pEntry->cRecursion++;
    1087         return;
    1088     }
    1089 
    1090     /*
    1091      * Allocate a new owner entry and insert it into the table.
    1092      */
    1093     pEntry = rtLockValidatorRecSharedAllocOwner(pRead, hThread, pSrcPos);
    1094     if (    pEntry
    1095         &&  !rtLockValidatorRecSharedAddOwner(pRead, pEntry))
    1096         rtLockValidatorRecSharedFreeOwner(pEntry);
    1097 }
    1098 
    1099 
    1100 RTDECL(void) RTLockValidatorRemoveReadOwner(PRTLOCKVALRECSHRD pRead, RTTHREAD hThread)
    1101 {
    1102     AssertReturnVoid(pRead->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC);
    1103     if (!pRead->fEnabled)
    1104         return;
    1105     AssertReturnVoid(hThread != NIL_RTTHREAD);
    1106 
    1107     /*
    1108      * Find the entry hope it's a recursive one.
    1109      */
    1110     uint32_t iEntry = UINT32_MAX; /* shuts up gcc */
    1111     PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(pRead, hThread, &iEntry);
    1112     AssertReturnVoid(pEntry);
    1113     if (pEntry->cRecursion > 1)
    1114         pEntry->cRecursion--;
    1115     else
    1116         rtLockValidatorRecSharedRemoveAndFreeOwner(pRead, pEntry, iEntry);
    11171699}
    11181700
     
    11881770
    11891771
    1190 /**
    1191  * Verifies the deadlock stack before calling it a deadlock.
    1192  *
    1193  * @retval  VERR_SEM_LV_DEADLOCK if it's a deadlock.
    1194  * @retval  VERR_TRY_AGAIN if something changed.
    1195  *
    1196  * @param   pStack              The deadlock detection stack.
    1197  */
    1198 static int rtLockValidatorDdVerifyDeadlock(PRTLOCKVALDDSTACK pStack)
    1199 {
    1200     uint32_t const c = pStack->c;
    1201     for (uint32_t iPass = 0; iPass < 3; iPass++)
    1202     {
    1203         for (uint32_t i = 1; i < c; i++)
    1204         {
    1205             PRTTHREADINT pThread = pStack->a[i].pThread;
    1206             if (pThread->u32Magic != RTTHREADINT_MAGIC)
    1207                 return VERR_TRY_AGAIN;
    1208             if (rtThreadGetState(pThread) != pStack->a[i].enmState)
    1209                 return VERR_TRY_AGAIN;
    1210             if (rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pRec) != pStack->a[i].pFirstSibling)
    1211                 return VERR_TRY_AGAIN;
    1212         }
    1213         RTThreadYield();
    1214     }
    1215 
    1216     return VERR_SEM_LV_DEADLOCK;
    1217 }
    1218 
    1219 
    1220 /**
    1221  * Checks for stack cycles caused by another deadlock before returning.
    1222  *
    1223  * @retval  VINF_SUCCESS if the stack is simply too small.
    1224  * @retval  VERR_SEM_LV_EXISTING_DEADLOCK if a cycle was detected.
    1225  *
    1226  * @param   pStack              The deadlock detection stack.
    1227  */
    1228 static int rtLockValidatorDdHandleStackOverflow(PRTLOCKVALDDSTACK pStack)
    1229 {
    1230     for (size_t i = 0; i < RT_ELEMENTS(pStack->a) - 1; i++)
    1231     {
    1232         PRTTHREADINT pThread = pStack->a[i].pThread;
    1233         for (size_t j = i + 1; j < RT_ELEMENTS(pStack->a); j++)
    1234             if (pStack->a[j].pThread == pThread)
    1235                 return VERR_SEM_LV_EXISTING_DEADLOCK;
    1236     }
    1237     static bool volatile s_fComplained = false;
    1238     if (!s_fComplained)
    1239     {
    1240         s_fComplained = true;
    1241         rtLockValidatorComplain(RT_SRC_POS, "lock validator stack is too small! (%zu entries)\n", RT_ELEMENTS(pStack->a));
    1242     }
    1243     return VINF_SUCCESS;
    1244 }
    1245 
    1246 
    1247 /**
    1248  * Worker for rtLockValidatorDoDeadlockCheck that checks if there is more work
    1249  * to be done during unwind.
    1250  *
    1251  * @returns true if there is more work left for this lock, false if not.
    1252  * @param   pRec            The current record.
    1253  * @param   iEntry          The current index.
    1254  * @param   pFirstSibling   The first record we examined.
    1255  */
    1256 DECL_FORCE_INLINE(bool) rtLockValidatorDdMoreWorkLeft(PRTLOCKVALRECUNION pRec, uint32_t iEntry, PRTLOCKVALRECUNION pFirstSibling)
    1257 {
    1258     PRTLOCKVALRECUNION pSibling;
    1259 
    1260     switch (pRec->Core.u32Magic)
    1261     {
    1262         case RTLOCKVALRECEXCL_MAGIC:
    1263             pSibling = pRec->Excl.pSibling;
    1264             break;
    1265 
    1266         case RTLOCKVALRECSHRD_MAGIC:
    1267             if (iEntry + 1 < pRec->Shared.cAllocated)
    1268                 return true;
    1269             pSibling = pRec->Excl.pSibling;
    1270             break;
    1271 
    1272         default:
    1273             return false;
    1274     }
    1275     return pSibling != NULL
    1276         && pSibling != pFirstSibling;
    1277 }
    1278 
    1279 
    1280 /**
    1281  * Worker for rtLockValidatorDeadlockDetection that does the actual deadlock
    1282  * detection.
    1283  *
    1284  * @retval  VINF_SUCCESS
    1285  * @retval  VERR_SEM_LV_DEADLOCK
    1286  * @retval  VERR_SEM_LV_EXISTING_DEADLOCK
    1287  * @retval  VERR_TRY_AGAIN
    1288  *
    1289  * @param   pStack          The stack to use.
    1290  * @param   pOriginalRec    The original record.
    1291  * @param   pThreadSelf     The calling thread.
    1292  */
    1293 static int rtLockValidatorDdDoDetection(PRTLOCKVALDDSTACK pStack, PRTLOCKVALRECUNION const pOriginalRec,
    1294                                         PRTTHREADINT const pThreadSelf)
    1295 {
    1296     pStack->c = 0;
    1297 
    1298     /* We could use a single RTLOCKVALDDENTRY variable here, but the
    1299        compiler may make a better job of it when using individual variables. */
    1300     PRTLOCKVALRECUNION  pRec            = pOriginalRec;
    1301     PRTLOCKVALRECUNION  pFirstSibling   = pOriginalRec;
    1302     uint32_t            iEntry          = UINT32_MAX;
    1303     PRTTHREADINT        pThread         = NIL_RTTHREAD;
    1304     RTTHREADSTATE       enmState        = RTTHREADSTATE_RUNNING;
    1305     for (;;)
    1306     {
    1307         /*
    1308          * Process the current record.
    1309          */
    1310         /* Find the next relevant owner thread. */
    1311         PRTTHREADINT pNextThread;
    1312         switch (pRec->Core.u32Magic)
    1313         {
    1314             case RTLOCKVALRECEXCL_MAGIC:
    1315                 Assert(iEntry == UINT32_MAX);
    1316                 pNextThread = rtLockValidatorReadThreadHandle(&pRec->Excl.hThread);
    1317                 if (    pNextThread
    1318                     &&  !RTTHREAD_IS_SLEEPING(pNextThread->enmState)
    1319                     &&  pNextThread != pThreadSelf)
    1320                     pNextThread = NIL_RTTHREAD;
    1321 
    1322                 if (    pNextThread == NIL_RTTHREAD
    1323                     &&  pRec->Excl.pSibling
    1324                     &&  pRec->Excl.pSibling != pFirstSibling)
    1325                 {
    1326                     pRec = pRec->Excl.pSibling;
    1327                     continue;
    1328                 }
    1329                 break;
    1330 
    1331             case RTLOCKVALRECSHRD_MAGIC:
    1332                 /* Skip to the next sibling if same side.  ASSUMES reader priority. */
    1333                 /** @todo The read side of a read-write lock is problematic if
    1334                  * the implementation prioritizes writers over readers because
    1335                  * that means we should could deadlock against current readers
    1336                  * if a writer showed up.  If the RW sem implementation is
    1337                  * wrapping some native API, it's not so easy to detect when we
    1338                  * should do this and when we shouldn't.  Checking when we
    1339                  * shouldn't is subject to wakeup scheduling and cannot easily
    1340                  * be made reliable.
    1341                  *
    1342                  * At the moment we circumvent all this mess by declaring that
    1343                  * readers has priority.  This is TRUE on linux, but probably
    1344                  * isn't on Solaris and FreeBSD. */
    1345                 if (   pRec == pFirstSibling
    1346                     && pRec->Shared.pSibling != NULL
    1347                     && pRec->Shared.pSibling != pFirstSibling)
    1348                 {
    1349                     pRec = pRec->Shared.pSibling;
    1350                     Assert(iEntry == UINT32_MAX);
    1351                     continue;
    1352                 }
    1353 
    1354                 /* Scan the owner table for blocked owners. */
    1355                 pNextThread = NIL_RTTHREAD;
    1356                 if (ASMAtomicUoReadU32(&pRec->Shared.cEntries) > 0)
    1357                 {
    1358                     uint32_t                        cAllocated = ASMAtomicUoReadU32(&pRec->Shared.cAllocated);
    1359                     PRTLOCKVALRECSHRDOWN volatile  *papOwners  = pRec->Shared.papOwners;
    1360                     while (++iEntry < cAllocated)
    1361                     {
    1362                         PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorUoReadSharedOwner(&papOwners[iEntry]);
    1363                         if (   pEntry
    1364                             && pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC)
    1365                         {
    1366                             pNextThread = rtLockValidatorReadThreadHandle(&pEntry->hThread);
    1367                             if (pNextThread)
    1368                             {
    1369                                 if (   pNextThread->u32Magic == RTTHREADINT_MAGIC
    1370                                     && RTTHREAD_IS_SLEEPING(pNextThread->enmState))
    1371                                     break;
    1372                                 pNextThread = NIL_RTTHREAD;
    1373                             }
    1374                         }
    1375                         else
    1376                             Assert(!pEntry || pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC_DEAD);
    1377                     }
    1378                     if (pNextThread == NIL_RTTHREAD)
    1379                         break;
    1380                 }
    1381 
    1382                 /* Advance to the next sibling, if any. */
    1383                 if (   pRec->Shared.pSibling != NULL
    1384                     && pRec->Shared.pSibling != pFirstSibling)
    1385                 {
    1386                     pRec = pRec->Shared.pSibling;
    1387                     iEntry = UINT32_MAX;
    1388                     continue;
    1389                 }
    1390                 break;
    1391 
    1392             case RTLOCKVALRECEXCL_MAGIC_DEAD:
    1393             case RTLOCKVALRECSHRD_MAGIC_DEAD:
    1394                 pNextThread = NIL_RTTHREAD;
    1395                 break;
    1396 
    1397             case RTLOCKVALRECSHRDOWN_MAGIC:
    1398             case RTLOCKVALRECSHRDOWN_MAGIC_DEAD:
    1399             default:
    1400                 AssertMsgFailed(("%p: %#x\n", pRec, pRec->Core));
    1401                 pNextThread = NIL_RTTHREAD;
    1402                 break;
    1403         }
    1404 
    1405         /* If we found a thread, check if it is still waiting for something. */
    1406         RTTHREADSTATE       enmNextState = RTTHREADSTATE_RUNNING;
    1407         PRTLOCKVALRECUNION  pNextRec     = NULL;
    1408         if (   pNextThread != NIL_RTTHREAD
    1409             && RT_LIKELY(pNextThread->u32Magic == RTTHREADINT_MAGIC))
    1410         {
    1411             do
    1412             {
    1413                 enmNextState = rtThreadGetState(pNextThread);
    1414                 if (    !RTTHREAD_IS_SLEEPING(enmNextState)
    1415                     &&  pNextThread != pThreadSelf)
    1416                     break;
    1417                 pNextRec = rtLockValidatorReadRecUnionPtr(&pNextThread->LockValidator.pRec);
    1418                 if (RT_LIKELY(   !pNextRec
    1419                               || enmNextState == rtThreadGetState(pNextThread)))
    1420                     break;
    1421                 pNextRec = NULL;
    1422             } while (pNextThread->u32Magic == RTTHREADINT_MAGIC);
    1423         }
    1424         if (pNextRec)
    1425         {
    1426             /*
    1427              * Recurse and check for deadlock.
    1428              */
    1429             uint32_t i = pStack->c;
    1430             if (RT_UNLIKELY(i >= RT_ELEMENTS(pStack->a)))
    1431                 return rtLockValidatorDdHandleStackOverflow(pStack);
    1432 
    1433             pStack->c++;
    1434             pStack->a[i].pRec           = pRec;
    1435             pStack->a[i].iEntry         = iEntry;
    1436             pStack->a[i].enmState       = enmState;
    1437             pStack->a[i].pThread        = pThread;
    1438             pStack->a[i].pFirstSibling  = pFirstSibling;
    1439 
    1440             if (RT_UNLIKELY(pNextThread == pThreadSelf))
    1441                 return rtLockValidatorDdVerifyDeadlock(pStack);
    1442 
    1443             pRec            = pNextRec;
    1444             pFirstSibling   = pNextRec;
    1445             iEntry          = UINT32_MAX;
    1446             enmState        = enmNextState;
    1447             pThread         = pNextThread;
    1448         }
    1449         else if (RT_LIKELY(!pNextThread))
    1450         {
    1451             /*
    1452              * No deadlock here, unwind the stack and deal with any unfinished
    1453              * business there.
    1454              */
    1455             uint32_t i = pStack->c;
    1456             for (;;)
    1457             {
    1458                 /* pop */
    1459                 if (i == 0)
    1460                     return VINF_SUCCESS;
    1461                 i--;
    1462 
    1463                 /* examine it. */
    1464                 pRec            = pStack->a[i].pRec;
    1465                 pFirstSibling   = pStack->a[i].pFirstSibling;
    1466                 iEntry          = pStack->a[i].iEntry;
    1467                 if (rtLockValidatorDdMoreWorkLeft(pRec, iEntry, pFirstSibling))
    1468                 {
    1469                     enmState    = pStack->a[i].enmState;
    1470                     pThread     = pStack->a[i].pThread;
    1471                     break;
    1472                 }
    1473             }
    1474         }
    1475         /* else: see if there is another thread to check for this lock. */
    1476     }
    1477 }
    1478 
    1479 
    1480 /**
    1481  * Check for the simple no-deadlock case.
    1482  *
    1483  * @returns true if no deadlock, false if further investigation is required.
    1484  *
    1485  * @param   pOriginalRec    The original record.
    1486  */
    1487 DECLINLINE(int) rtLockValidatorIsSimpleNoDeadlockCase(PRTLOCKVALRECUNION pOriginalRec)
    1488 {
    1489     if (    pOriginalRec->Excl.Core.u32Magic == RTLOCKVALRECEXCL_MAGIC
    1490         &&  !pOriginalRec->Excl.pSibling)
    1491     {
    1492         PRTTHREADINT pThread = rtLockValidatorReadThreadHandle(&pOriginalRec->Excl.hThread);
    1493         if (   !pThread
    1494             || pThread->u32Magic != RTTHREADINT_MAGIC)
    1495             return true;
    1496         RTTHREADSTATE enmState = rtThreadGetState(pThread);
    1497         if (!RTTHREAD_IS_SLEEPING(enmState))
    1498             return true;
    1499     }
    1500     return false;
    1501 }
    1502 
    1503 
    1504 /**
    1505  * Worker for rtLockValidatorDeadlockDetection that bitches about a deadlock.
    1506  *
    1507  * @param   pStack          The chain of locks causing the deadlock.
    1508  * @param   pRec            The record relating to the current thread's lock
    1509  *                          operation.
    1510  * @param   pThreadSelf     This thread.
    1511  * @param   pSrcPos         Where we are going to deadlock.
    1512  * @param   rc              The return code.
    1513  */
    1514 static void rcLockValidatorDoDeadlockComplaining(PRTLOCKVALDDSTACK pStack, PRTLOCKVALRECUNION pRec,
    1515                                                  PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos, int rc)
    1516 {
    1517     if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
    1518     {
    1519         rtLockValidatorComplainFirst(  rc == VERR_SEM_LV_DEADLOCK
    1520                                      ? "Detected deadlock!"
    1521                                      : rc == VERR_SEM_LV_EXISTING_DEADLOCK
    1522                                      ? "Found existing deadlock!"
    1523                                      : "!unexpected rc!",
    1524                                      pSrcPos,
    1525                                      pThreadSelf,
    1526                                      pStack->a[0].pRec != pRec ? pRec : NULL);
    1527         rtLockValidatorComplainMore("---- start of deadlock chain - %u entries ----\n", pStack->c);
    1528         for (uint32_t i = 0; i < pStack->c; i++)
    1529         {
    1530             char szPrefix[24];
    1531             RTStrPrintf(szPrefix, sizeof(szPrefix), "#%02u: ", i);
    1532             PRTLOCKVALRECSHRDOWN pShrdOwner = NULL;
    1533             if (pStack->a[i].pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC)
    1534                 pShrdOwner = pStack->a[i].pRec->Shared.papOwners[pStack->a[i].iEntry];
    1535             if (VALID_PTR(pShrdOwner) && pShrdOwner->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC)
    1536                 rtLockValidatorComplainAboutLock(szPrefix, (PRTLOCKVALRECUNION)pShrdOwner, "\n");
    1537             else
    1538                 rtLockValidatorComplainAboutLock(szPrefix, pStack->a[i].pRec, "\n");
    1539         }
    1540         rtLockValidatorComplainMore("---- end of deadlock chain ----\n");
    1541     }
    1542 
    1543     rtLockValidatorComplainPanic();
    1544 }
    1545 
    1546 
    1547 /**
    1548  * Perform deadlock detection.
    1549  *
    1550  * @retval  VINF_SUCCESS
    1551  * @retval  VERR_SEM_LV_DEADLOCK
    1552  * @retval  VERR_SEM_LV_EXISTING_DEADLOCK
    1553  *
    1554  * @param   pRec            The record relating to the current thread's lock
    1555  *                          operation.
    1556  * @param   pThreadSelf     The current thread.
    1557  * @param   pSrcPos         The position of the current lock operation.
    1558  */
    1559 static int rtLockValidatorDeadlockDetection(PRTLOCKVALRECUNION pRec, PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos)
    1560 {
    1561 #ifdef DEBUG_bird
    1562     RTLOCKVALDDSTACK Stack;
    1563     int rc = rtLockValidatorDdDoDetection(&Stack, pRec, pThreadSelf);
    1564     if (RT_SUCCESS(rc))
    1565         return VINF_SUCCESS;
    1566 
    1567     if (rc == VERR_TRY_AGAIN)
    1568     {
    1569         for (uint32_t iLoop = 0; ; iLoop++)
    1570         {
    1571             rc = rtLockValidatorDdDoDetection(&Stack, pRec, pThreadSelf);
    1572             if (RT_SUCCESS_NP(rc))
    1573                 return VINF_SUCCESS;
    1574             if (rc != VERR_TRY_AGAIN)
    1575                 break;
    1576             RTThreadYield();
    1577             if (iLoop >= 3)
    1578                 return VINF_SUCCESS;
    1579         }
    1580     }
    1581 
    1582     rcLockValidatorDoDeadlockComplaining(&Stack, pRec, pThreadSelf, pSrcPos, rc);
    1583     return rc;
    1584 #else
    1585     return VINF_SUCCESS;
    1586 #endif
    1587 }
    1588 
    1589 
    1590 
    1591 RTDECL(int) RTLockValidatorCheckWriteOrderBlocking(PRTLOCKVALRECEXCL pWrite, PRTLOCKVALRECSHRD pRead,
    1592                                                    RTTHREAD hThread, RTTHREADSTATE enmState, bool fRecursiveOk,
    1593                                                    PCRTLOCKVALSRCPOS pSrcPos)
    1594 {
    1595     /*
    1596      * Fend off wild life.
    1597      */
    1598     PRTLOCKVALRECUNION pWriteU = (PRTLOCKVALRECUNION)pWrite; /* (avoid break aliasing rules) */
    1599     AssertPtrReturn(pWriteU, VERR_SEM_LV_INVALID_PARAMETER);
    1600     AssertReturn(pWriteU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    1601 
    1602     PRTLOCKVALRECUNION pReadU = (PRTLOCKVALRECUNION)pRead;
    1603     AssertPtrReturn(pRead, VERR_SEM_LV_INVALID_PARAMETER);
    1604     AssertReturn(pReadU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    1605 
    1606     AssertReturn(pReadU->Shared.fEnabled == pWriteU->Excl.fEnabled, VERR_SEM_LV_INVALID_PARAMETER);
    1607     if (!pWriteU->Excl.fEnabled)
    1608         return VINF_SUCCESS;
    1609 
    1610     AssertReturn(RTTHREAD_IS_SLEEPING(enmState), VERR_SEM_LV_INVALID_PARAMETER);
    1611 
    1612     PRTTHREADINT pThread = hThread;
    1613     AssertPtrReturn(pThread, VERR_SEM_LV_INVALID_PARAMETER);
    1614     AssertReturn(pThread->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    1615     RTTHREADSTATE enmThreadState = rtThreadGetState(pThread);
    1616     AssertReturn(   enmThreadState == RTTHREADSTATE_RUNNING
    1617                  || enmThreadState == RTTHREADSTATE_TERMINATED   /* rtThreadRemove uses locks too */
    1618                  || enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */
    1619                  , VERR_SEM_LV_INVALID_PARAMETER);
    1620 
    1621     /*
    1622      * Check for attempts at doing a read upgrade.
    1623      */
    1624     PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(&pReadU->Shared, hThread, NULL);
    1625     if (pEntry)
    1626     {
    1627         rtLockValidatorComplainFirst("Read lock upgrade", pSrcPos, pThread, (PRTLOCKVALRECUNION)pEntry);
    1628         rtLockValidatorComplainPanic();
    1629         return VERR_SEM_LV_UPGRADE;
    1630     }
    1631 
    1632 
    1633 
    1634     return VINF_SUCCESS;
    1635 }
    1636 
    1637 
    1638 RTDECL(int) RTLockValidatorCheckReadOrderBlocking(PRTLOCKVALRECSHRD pRead, PRTLOCKVALRECEXCL pWrite,
    1639                                                   RTTHREAD hThread, RTTHREADSTATE enmState, bool fRecursiveOk,
    1640                                                   PCRTLOCKVALSRCPOS pSrcPos)
    1641 {
    1642     /*
    1643      * Fend off wild life.
    1644      */
    1645     AssertPtrReturn(pRead, VERR_SEM_LV_INVALID_PARAMETER);
    1646     AssertReturn(pRead->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    1647     AssertPtrReturn(pWrite, VERR_SEM_LV_INVALID_PARAMETER);
    1648     AssertReturn(pWrite->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    1649     AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER);
    1650     if (!pRead->fEnabled)
    1651         return VINF_SUCCESS;
    1652     AssertReturn(RTTHREAD_IS_SLEEPING(enmState), VERR_SEM_LV_INVALID_PARAMETER);
    1653     PRTTHREADINT pThread = hThread;
    1654     AssertPtrReturn(pThread, VERR_SEM_LV_INVALID_PARAMETER);
    1655     AssertReturn(pThread->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    1656     RTTHREADSTATE enmThreadState = rtThreadGetState(pThread);
    1657     AssertReturn(   enmThreadState == RTTHREADSTATE_RUNNING
    1658                  || enmThreadState == RTTHREADSTATE_TERMINATED   /* rtThreadRemove uses locks too */
    1659                  || enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */
    1660                  , VERR_SEM_LV_INVALID_PARAMETER);
    1661     Assert(pWrite->hThread != pThread);
    1662 
    1663 
    1664     return VINF_SUCCESS;
    1665 }
    1666 
    1667 
    1668 RTDECL(int) RTLockValidatorCheckBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThread,
    1669                                          RTTHREADSTATE enmState, bool fRecursiveOk,
    1670                                          PCRTLOCKVALSRCPOS pSrcPos)
    1671 {
    1672     /*
    1673      * Fend off wild life.
    1674      */
    1675     PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
    1676     AssertPtrReturn(pRecU, VERR_SEM_LV_INVALID_PARAMETER);
    1677     AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    1678     if (!pRecU->Excl.fEnabled)
    1679         return VINF_SUCCESS;
    1680 
    1681     AssertReturn(RTTHREAD_IS_SLEEPING(enmState), VERR_SEM_LV_INVALID_PARAMETER);
    1682 
    1683     PRTTHREADINT pThreadSelf = hThread;
    1684     AssertPtrReturn(pThreadSelf, VERR_SEM_LV_INVALID_PARAMETER);
    1685     AssertReturn(pThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    1686 
    1687     RTTHREADSTATE enmThreadState = rtThreadGetState(pThreadSelf);
    1688     AssertReturn(   enmThreadState == RTTHREADSTATE_RUNNING
    1689                  || enmThreadState == RTTHREADSTATE_TERMINATED   /* rtThreadRemove uses locks too */
    1690                  || enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */
    1691                  , VERR_SEM_LV_INVALID_PARAMETER);
    1692 
    1693     /*
    1694      * Record the location and everything before changing the state and
    1695      * performing deadlock detection.
    1696      */
    1697     rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, pRecU);
    1698     rtLockValidatorCopySrcPos(&pThreadSelf->LockValidator.SrcPos, pSrcPos);
    1699 
    1700     /*
    1701      * Don't do deadlock detection if we're recursing.
    1702      *
    1703      * On some hosts we don't do recursion accounting our selves and there
    1704      * isn't any other place to check for this.  semmutex-win.cpp for instance.
    1705      */
    1706     if (rtLockValidatorReadThreadHandle(&pRecU->Excl.hThread) == pThreadSelf)
    1707     {
    1708         if (fRecursiveOk)
    1709             return VINF_SUCCESS;
    1710         rtLockValidatorComplainFirst("Recursion not allowed", pSrcPos, pThreadSelf, pRecU);
    1711         rtLockValidatorComplainPanic();
    1712         return VERR_SEM_LV_NESTED;
    1713     }
    1714 
    1715     /*
    1716      * Perform deadlock detection.
    1717      */
    1718     if (rtLockValidatorIsSimpleNoDeadlockCase(pRecU))
    1719         return VINF_SUCCESS;
    1720     return rtLockValidatorDeadlockDetection(pRecU, pThreadSelf, pSrcPos);
    1721 }
    1722 RT_EXPORT_SYMBOL(RTLockValidatorCheckBlocking);
    1723 
    1724 
    17251772RTDECL(bool) RTLockValidatorSetEnabled(bool fEnabled)
    17261773{
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette