VirtualBox

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


Ignore:
Timestamp:
Dec 31, 2009 1:18:00 AM (15 years ago)
Author:
vboxsync
Message:

iprt: More lock validation code; rewrote tstDeadlock.

File:
1 edited

Legend:

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

    r25570 r25602  
    4141#include <iprt/once.h>
    4242#include <iprt/semaphore.h>
     43#include <iprt/string.h>
    4344#include <iprt/thread.h>
    4445
     
    5152*   Structures and Typedefs                                                    *
    5253*******************************************************************************/
     54/**
     55 * Deadlock detection stack entry.
     56 */
     57typedef struct RTLOCKVALIDATORDDENTRY
     58{
     59    /** The current record. */
     60    PRTLOCKVALIDATORRECUNION    pRec;
     61    /** The current entry number if pRec is a shared one. */
     62    uint32_t                    iEntry;
     63    /** The thread state of the thread we followed to get to pFirstSibling.
     64     * This is only used for validating a deadlock stack.  */
     65    RTTHREADSTATE               enmState;
     66    /** The thread we followed to get to pFirstSibling.
     67     * This is only used for validating a deadlock stack. */
     68    PRTTHREADINT                pThread;
     69    /** What pThread is waiting on, i.e. where we entered the circular list of
     70     * siblings.  This is used for validating a deadlock stack as well as
     71     * terminating the sibling walk. */
     72    PRTLOCKVALIDATORRECUNION    pFirstSibling;
     73} RTLOCKVALIDATORDDENTRY;
     74
     75
     76/**
     77 * Deadlock detection stack.
     78 */
     79typedef struct RTLOCKVALIDATORDDSTACK
     80{
     81    /** The number stack entries. */
     82    uint32_t                    c;
     83    /** The stack entries. */
     84    RTLOCKVALIDATORDDENTRY      a[32];
     85} RTLOCKVALIDATORDDSTACK;
     86/** Pointer to a deadlock detction stack. */
     87typedef RTLOCKVALIDATORDDSTACK *PRTLOCKVALIDATORDDSTACK;
    5388
    5489
     
    6095 * EW: Deadlock detection.
    6196 */
    62 static RTSEMXROADS g_hLockValidatorXRoads = NIL_RTSEMXROADS;
     97static RTSEMXROADS      g_hLockValidatorXRoads  = NIL_RTSEMXROADS;
    6398/** Whether the lock validator is enabled or disabled.
    6499 * Only applies to new locks.  */
    65 static bool volatile g_fLockValidatorEnabled = true;
     100static bool volatile    g_fLockValidatorEnabled  = true;
     101/** Set if the lock validator is quiet. */
     102#ifdef RT_STRICT
     103static bool volatile    g_fLockValidatorQuiet    = false;
     104#else
     105static bool volatile    g_fLockValidatorQuiet    = true;
     106#endif
     107/** Set if the lock validator may panic. */
     108#ifdef RT_STRICT
     109static bool volatile    g_fLockValidatorMayPanic = true;
     110#else
     111static bool volatile    g_fLockValidatorMayPanic = false;
     112#endif
     113
     114
     115/** Wrapper around ASMAtomicReadPtr. */
     116DECL_FORCE_INLINE(PRTLOCKVALIDATORRECUNION) rtLockValidatorReadRecUnionPtr(PRTLOCKVALIDATORRECUNION volatile *ppRec)
     117{
     118    return (PRTLOCKVALIDATORRECUNION)ASMAtomicReadPtr((void * volatile *)ppRec);
     119}
     120
     121
     122/** Wrapper around ASMAtomicWritePtr. */
     123DECL_FORCE_INLINE(void) rtLockValidatorWriteRecUnionPtr(PRTLOCKVALIDATORRECUNION volatile *ppRec, PRTLOCKVALIDATORRECUNION pRecNew)
     124{
     125    ASMAtomicWritePtr((void * volatile *)ppRec, pRecNew);
     126}
     127
     128
     129/** Wrapper around ASMAtomicReadPtr. */
     130DECL_FORCE_INLINE(PRTTHREADINT) rtLockValidatorReadThreadHandle(RTTHREAD volatile *phThread)
     131{
     132    return (PRTTHREADINT)ASMAtomicReadPtr((void * volatile *)phThread);
     133}
     134
     135
     136/** Wrapper around ASMAtomicUoReadPtr. */
     137DECL_FORCE_INLINE(PRTLOCKVALIDATORSHAREDONE) rtLockValidatorUoReadSharedOwner(PRTLOCKVALIDATORSHAREDONE volatile *ppOwner)
     138{
     139    return (PRTLOCKVALIDATORSHAREDONE)ASMAtomicUoReadPtr((void * volatile *)ppOwner);
     140}
     141
     142
     143/**
     144 * Reads a volatile thread handle field and returns the thread name.
     145 *
     146 * @returns Thread name (read only).
     147 * @param   phThread            The thread handle field.
     148 */
     149static const char *rtLockValidatorNameThreadHandle(RTTHREAD volatile *phThread)
     150{
     151    PRTTHREADINT pThread = rtLockValidatorReadThreadHandle(phThread);
     152    if (!pThread)
     153        return "<NIL>";
     154    if (!VALID_PTR(pThread))
     155        return "<INVALID>";
     156    if (pThread->u32Magic != RTTHREADINT_MAGIC)
     157        return "<BAD-THREAD-MAGIC>";
     158    return pThread->szName;
     159}
     160
     161
     162/**
     163 * Launch a simple assertion like complaint w/ panic.
     164 *
     165 * @param   RT_SRC_POS_DECL     Where from.
     166 * @param   pszWhat             What we're complaining about.
     167 * @param   ...                 Format arguments.
     168 */
     169static void rtLockValidatorComplain(RT_SRC_POS_DECL, const char *pszWhat, ...)
     170{
     171    if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
     172    {
     173        RTAssertMsg1Weak("RTLockValidator", iLine, pszFile, pszFunction);
     174        va_list va;
     175        va_start(va, pszWhat);
     176        RTAssertMsg2WeakV(pszWhat, va);
     177        va_end(va);
     178    }
     179    if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
     180        RTAssertPanic();
     181}
     182
     183
     184/**
     185 * Describes the lock.
     186 *
     187 * @param   pszPrefix           Message prefix.
     188 * @param   Rec                 The lock record we're working on.
     189 * @param   pszPrefix           Message suffix.
     190 */
     191static void rtLockValidatorComplainAboutLock(const char *pszPrefix, PRTLOCKVALIDATORRECUNION pRec, const char *pszSuffix)
     192{
     193    if (    VALID_PTR(pRec)
     194        &&  !ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
     195    {
     196        switch (pRec->Core.u32Magic)
     197        {
     198            case RTLOCKVALIDATORREC_MAGIC:
     199                RTAssertMsg2AddWeak("%s%p %s xrec=%p own=%s nest=%u pos={%Rbn(%u) %Rfn %p}%s", pszPrefix,
     200                                    pRec->Excl.hLock, pRec->Excl.pszName, pRec,
     201                                    rtLockValidatorNameThreadHandle(&pRec->Excl.hThread), pRec->Excl.cRecursion,
     202                                    pRec->Excl.SrcPos.pszFile, pRec->Excl.SrcPos.uLine, pRec->Excl.SrcPos.pszFunction, pRec->Excl.SrcPos.uId,
     203                                    pszSuffix);
     204                break;
     205
     206            case RTLOCKVALIDATORSHARED_MAGIC:
     207                RTAssertMsg2AddWeak("%s%p %s srec=%p%s", pszPrefix,
     208                                    pRec->Shared.hLock, pRec->Shared.pszName, pRec,
     209                                    pszSuffix);
     210                break;
     211
     212            case RTLOCKVALIDATORSHAREDONE_MAGIC:
     213            {
     214                PRTLOCKVALIDATORSHARED pShared = pRec->SharedOne.pSharedRec;
     215                if (    VALID_PTR(pShared)
     216                    &&  pShared->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC)
     217                    RTAssertMsg2AddWeak("%s%p %s srec=%p trec=%p thr=%s nest=%u pos={%Rbn(%u) %Rfn %p}%s", pszPrefix,
     218                                        pShared->hLock, pShared->pszName, pShared,
     219                                        pRec, rtLockValidatorNameThreadHandle(&pRec->SharedOne.hThread), pRec->SharedOne.cRecursion,
     220                                        pRec->SharedOne.SrcPos.pszFile, pRec->SharedOne.SrcPos.uLine, pRec->SharedOne.SrcPos.pszFunction, pRec->SharedOne.SrcPos.uId,
     221                                        pszSuffix);
     222                else
     223                    RTAssertMsg2AddWeak("%sbad srec=%p trec=%p thr=%s nest=%u pos={%Rbn(%u) %Rfn %p}%s", pszPrefix,
     224                                        pShared,
     225                                        pRec, rtLockValidatorNameThreadHandle(&pRec->SharedOne.hThread), pRec->SharedOne.cRecursion,
     226                                        pRec->SharedOne.SrcPos.pszFile, pRec->SharedOne.SrcPos.uLine, pRec->SharedOne.SrcPos.pszFunction, pRec->SharedOne.SrcPos.uId,
     227                                        pszSuffix);
     228                break;
     229            }
     230
     231            default:
     232                RTAssertMsg2AddWeak("%spRec=%p u32Magic=%#x (bad)%s", pszPrefix, pRec, pRec->Core.u32Magic, pszSuffix);
     233                break;
     234        }
     235    }
     236}
     237
     238
     239/**
     240 * Launch the initial complaint.
     241 *
     242 * @param   pszWhat             What we're complaining about.
     243 * @param   pSrcPos             Where we are complaining from, as it were.
     244 * @param   pThreadSelf         The calling thread.
     245 * @param   pRec                The main lock involved. Can be NULL.
     246 */
     247static void rtLockValidatorComplainFirst(const char *pszWhat, PCRTLOCKVALIDATORSRCPOS pSrcPos, PRTTHREADINT pThreadSelf, PRTLOCKVALIDATORRECUNION pRec)
     248{
     249    if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
     250    {
     251        RTAssertMsg1Weak("RTLockValidator", pSrcPos->uLine, pSrcPos->pszFile, pSrcPos->pszFunction);
     252        if (pSrcPos->uId)
     253            RTAssertMsg2Weak("%s  [uId=%p thrd=%s]\n", pszWhat, pSrcPos->uId, VALID_PTR(pThreadSelf) ? pThreadSelf->szName : "<NIL>");
     254        else
     255            RTAssertMsg2Weak("%s\n", pszWhat, pSrcPos->uId);
     256        rtLockValidatorComplainAboutLock("Lock: ", pRec, "\n");
     257    }
     258}
     259
     260
     261/**
     262 * Continue bitching.
     263 *
     264 * @param   pszFormat           Format string.
     265 * @param   ...                 Format arguments.
     266 */
     267static void rtLockValidatorComplainMore(const char *pszFormat, ...)
     268{
     269    if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
     270    {
     271        va_list va;
     272        va_start(va, pszFormat);
     273        RTAssertMsg2AddWeakV(pszFormat, va);
     274        va_end(va);
     275    }
     276}
     277
     278
     279/**
     280 * Raise a panic if enabled.
     281 */
     282static void rtLockValidatorComplainPanic(void)
     283{
     284    if (ASMAtomicUoReadBool(&g_fLockValidatorMayPanic))
     285        RTAssertPanic();
     286}
    66287
    67288
     
    146367                                    uint32_t uSubClass, const char *pszName, void *hLock)
    147368{
    148     pRec->u32Magic      = RTLOCKVALIDATORREC_MAGIC;
     369    pRec->Core.u32Magic = RTLOCKVALIDATORREC_MAGIC;
    149370    pRec->fEnabled      = RTLockValidatorIsEnabled();
    150371    pRec->afReserved[0] = 0;
     
    189410
    190411
     412/**
     413 * Unlinks all siblings.
     414 *
     415 * This is used during record deletion and assumes no races.
     416 *
     417 * @param   pCore               One of the siblings.
     418 */
     419static void rtLockValidatorUnlinkAllSiblings(PRTLOCKVALIDATORRECCORE pCore)
     420{
     421    /* ASSUMES sibling destruction doesn't involve any races and that all
     422       related records are to be disposed off now.  */
     423    PRTLOCKVALIDATORRECUNION pSibling = (PRTLOCKVALIDATORRECUNION)pCore;
     424    while (pSibling)
     425    {
     426        PRTLOCKVALIDATORRECUNION volatile *ppCoreNext;
     427        switch (pSibling->Core.u32Magic)
     428        {
     429            case RTLOCKVALIDATORREC_MAGIC:
     430            case RTLOCKVALIDATORREC_MAGIC_DEAD:
     431                ppCoreNext = &pSibling->Excl.pSibling;
     432                break;
     433
     434            case RTLOCKVALIDATORSHARED_MAGIC:
     435            case RTLOCKVALIDATORSHARED_MAGIC_DEAD:
     436                ppCoreNext = &pSibling->Shared.pSibling;
     437                break;
     438
     439            default:
     440                AssertFailed();
     441                ppCoreNext = NULL;
     442                break;
     443        }
     444        if (RT_UNLIKELY(ppCoreNext))
     445            break;
     446        pSibling = (PRTLOCKVALIDATORRECUNION)ASMAtomicXchgPtr((void * volatile *)ppCoreNext, NULL);
     447    }
     448}
     449
     450
    191451RTDECL(void) RTLockValidatorRecDelete(PRTLOCKVALIDATORREC pRec)
    192452{
    193     Assert(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC);
     453    Assert(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC);
    194454
    195455    rtLockValidatorSerializeDestructEnter();
    196456
    197     ASMAtomicWriteU32(&pRec->u32Magic, RTLOCKVALIDATORREC_MAGIC_DEAD);
     457    ASMAtomicWriteU32(&pRec->Core.u32Magic, RTLOCKVALIDATORREC_MAGIC_DEAD);
    198458    ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD);
    199459    ASMAtomicWriteHandle(&pRec->hClass, NIL_RTLOCKVALIDATORCLASS);
    200460    if (pRec->pSibling)
    201     {
    202         /* ASSUMES sibling destruction doesn't involve any races.  */
    203         ASMAtomicUoWritePtr((void * volatile *)&pRec->pSibling->pSibling, NULL);
    204         ASMAtomicUoWritePtr((void * volatile *)&pRec->pSibling, NULL);
    205     }
    206 
     461        rtLockValidatorUnlinkAllSiblings(&pRec->Core);
    207462    rtLockValidatorSerializeDestructLeave();
    208463}
     
    224479                                          uint32_t uSubClass, const char *pszName, void *hLock)
    225480{
    226     pRec->u32Magic      = RTLOCKVALIDATORSHARED_MAGIC;
     481    pRec->Core.u32Magic = RTLOCKVALIDATORSHARED_MAGIC;
    227482    pRec->uSubClass     = uSubClass;
    228483    pRec->hClass        = hClass;
     
    248503RTDECL(void) RTLockValidatorSharedRecDelete(PRTLOCKVALIDATORSHARED pRec)
    249504{
    250     Assert(pRec->u32Magic == RTLOCKVALIDATORSHARED_MAGIC);
     505    Assert(pRec->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC);
    251506
    252507    /*
     
    264519    }
    265520
    266     ASMAtomicWriteU32(&pRec->u32Magic, RTLOCKVALIDATORSHARED_MAGIC_DEAD);
     521    ASMAtomicWriteU32(&pRec->Core.u32Magic, RTLOCKVALIDATORSHARED_MAGIC_DEAD);
    267522    ASMAtomicUoWriteHandle(&pRec->hClass, NIL_RTLOCKVALIDATORCLASS);
    268523    if (pRec->papOwners)
     
    275530    }
    276531    if (pRec->pSibling)
    277     {
    278         /* ASSUMES sibling destruction doesn't involve any races.  */
    279         ASMAtomicUoWritePtr((void * volatile *)&pRec->pSibling->pSibling, NULL);
    280         ASMAtomicUoWritePtr((void * volatile *)&pRec->pSibling, NULL);
    281     }
     532        rtLockValidatorUnlinkAllSiblings(&pRec->Core);
    282533    ASMAtomicWriteBool(&pRec->fReallocating, false);
    283534
     
    304555        for (uint32_t iEntry = 0; iEntry < cMax; iEntry++)
    305556        {
    306             PRTLOCKVALIDATORSHAREDONE pEntry;
    307             pEntry = (PRTLOCKVALIDATORSHAREDONE)ASMAtomicUoReadPtr((void * volatile *)&papOwners[iEntry]);
     557            PRTLOCKVALIDATORSHAREDONE pEntry = rtLockValidatorUoReadSharedOwner(&papOwners[iEntry]);
    308558            if (pEntry && pEntry->hThread == hThread)
    309559            {
     
    336586    if (pEntry)
    337587    {
    338         pEntry->u32Magic        = RTLOCKVALIDATORSHAREDONE_MAGIC;
     588        pEntry->Core.u32Magic   = RTLOCKVALIDATORSHAREDONE_MAGIC;
    339589        pEntry->cRecursion      = 1;
    340590        pEntry->hThread         = hThread;
     
    363613    {
    364614        rtLockValidatorSerializeDestructEnter();
    365         ASMAtomicWriteU32(&pEntry->u32Magic, RTLOCKVALIDATORSHAREDONE_MAGIC_DEAD);
     615        ASMAtomicWriteU32(&pEntry->Core.u32Magic, RTLOCKVALIDATORSHAREDONE_MAGIC_DEAD);
    366616        ASMAtomicWriteHandle(&pEntry->hThread, NIL_RTTHREAD);
    367617        rtLockValidatorSerializeDestructLeave();
     
    399649         * Try grab the privilege to reallocating the table.
    400650         */
    401         if (    pShared->u32Magic == RTLOCKVALIDATORSHARED_MAGIC
     651        if (    pShared->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC
    402652            &&  ASMAtomicCmpXchgBool(&pShared->fReallocating, true, false))
    403653        {
     
    438688
    439689        rtLockValidatorSerializeDetectionEnter();
    440         if (RT_UNLIKELY(pShared->u32Magic != RTLOCKVALIDATORSHARED_MAGIC))
     690        if (RT_UNLIKELY(pShared->Core.u32Magic != RTLOCKVALIDATORSHARED_MAGIC))
    441691            break;
    442692
     
    461711{
    462712    rtLockValidatorSerializeDetectionEnter();
    463     if (RT_LIKELY(pShared->u32Magic == RTLOCKVALIDATORSHARED_MAGIC)) /* paranoia */
     713    if (RT_LIKELY(pShared->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC)) /* paranoia */
    464714    {
    465715        if (   ASMAtomicIncU32(&pShared->cEntries) > pShared->cAllocated /** @todo add fudge */
     
    502752     */
    503753    rtLockValidatorSerializeDetectionEnter();
    504     AssertReturnVoidStmt(pShared->u32Magic == RTLOCKVALIDATORSHARED_MAGIC, rtLockValidatorSerializeDetectionLeave());
     754    AssertReturnVoidStmt(pShared->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC, rtLockValidatorSerializeDetectionLeave());
    505755    if (RT_UNLIKELY(   iEntry >= pShared->cAllocated
    506756                    || !ASMAtomicCmpXchgPtr((void * volatile *)&pShared->papOwners[iEntry], NULL, pEntry)))
     
    526776
    527777
    528 RTDECL(int) RTLockValidatorMakeSiblings(void *pvRec1, void *pvRec2)
     778RTDECL(int) RTLockValidatorMakeSiblings(PRTLOCKVALIDATORRECCORE pRec1, PRTLOCKVALIDATORRECCORE pRec2)
    529779{
    530780    /*
    531781     * Validate input.
    532782     */
    533     union
    534     {
    535         PRTLOCKVALIDATORREC     pRec;
    536         PRTLOCKVALIDATORSHARED  pShared;
    537         uint32_t               *pu32Magic;
    538         void                   *pv;
    539     } u1, u2;
    540     u1.pv = pvRec1;
    541     u2.pv = pvRec2;
    542 
    543     AssertPtrReturn(u1.pv, VERR_SEM_LV_INVALID_PARAMETER);
    544     AssertReturn(   *u1.pu32Magic == RTLOCKVALIDATORREC_MAGIC
    545                  || *u1.pu32Magic == RTLOCKVALIDATORSHARED_MAGIC
     783    PRTLOCKVALIDATORRECUNION p1 = (PRTLOCKVALIDATORRECUNION)pRec1;
     784    PRTLOCKVALIDATORRECUNION p2 = (PRTLOCKVALIDATORRECUNION)pRec2;
     785
     786    AssertPtrReturn(p1, VERR_SEM_LV_INVALID_PARAMETER);
     787    AssertReturn(   p1->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC
     788                 || p1->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC
    546789                 , VERR_SEM_LV_INVALID_PARAMETER);
    547790
    548     AssertPtrReturn(u2.pv, VERR_SEM_LV_INVALID_PARAMETER);
    549     AssertReturn(   *u2.pu32Magic == RTLOCKVALIDATORREC_MAGIC
    550                  || *u2.pu32Magic == RTLOCKVALIDATORSHARED_MAGIC
     791    AssertPtrReturn(p2, VERR_SEM_LV_INVALID_PARAMETER);
     792    AssertReturn(   p2->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC
     793                 || p2->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC
    551794                 , VERR_SEM_LV_INVALID_PARAMETER);
    552795
     
    554797     * Link them.
    555798     */
    556     if (    *u1.pu32Magic == RTLOCKVALIDATORREC_MAGIC
    557         &&  *u2.pu32Magic == RTLOCKVALIDATORSHARED_MAGIC)
    558     {
    559         u1.pRec->pSibling    = u2.pShared;
    560         u2.pShared->pSibling = u1.pRec;
    561     }
    562     else if (    *u1.pu32Magic == RTLOCKVALIDATORSHARED_MAGIC
    563              &&  *u2.pu32Magic == RTLOCKVALIDATORREC_MAGIC)
    564     {
    565         u1.pShared->pSibling = u2.pRec;
    566         u2.pRec->pSibling    = u1.pShared;
     799    if (    p1->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC
     800        &&  p2->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC)
     801    {
     802        p1->Excl.pSibling   = p2;
     803        p2->Shared.pSibling = p1;
     804    }
     805    else if (   p1->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC
     806             && p2->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC)
     807    {
     808        p1->Shared.pSibling = p2;
     809        p2->Excl.pSibling   = p1;
    567810    }
    568811    else
     
    575818RTDECL(int) RTLockValidatorCheckOrder(PRTLOCKVALIDATORREC pRec, RTTHREAD hThread, PCRTLOCKVALIDATORSRCPOS pSrcPos)
    576819{
    577     AssertReturn(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     820    AssertReturn(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    578821    if (!pRec->fEnabled)
    579822        return VINF_SUCCESS;
     
    594837RTDECL(int)  RTLockValidatorCheckAndRelease(PRTLOCKVALIDATORREC pRec)
    595838{
    596     AssertReturn(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     839    AssertReturn(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    597840    if (!pRec->fEnabled)
    598841        return VINF_SUCCESS;
     
    606849RTDECL(int)  RTLockValidatorCheckAndReleaseReadOwner(PRTLOCKVALIDATORSHARED pRead, RTTHREAD hThread)
    607850{
    608     AssertReturn(pRead->u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     851    AssertReturn(pRead->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    609852    if (!pRead->fEnabled)
    610853        return VINF_SUCCESS;
     
    641884RTDECL(int) RTLockValidatorRecordRecursion(PRTLOCKVALIDATORREC pRec, PCRTLOCKVALIDATORSRCPOS pSrcPos)
    642885{
    643     AssertReturn(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     886    AssertReturn(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    644887    if (!pRec->fEnabled)
    645888        return VINF_SUCCESS;
     
    655898RTDECL(int) RTLockValidatorUnwindRecursion(PRTLOCKVALIDATORREC pRec)
    656899{
    657     AssertReturn(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     900    AssertReturn(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    658901    if (!pRec->fEnabled)
    659902        return VINF_SUCCESS;
     
    669912RTDECL(int) RTLockValidatorRecordReadWriteRecursion(PRTLOCKVALIDATORREC pWrite, PRTLOCKVALIDATORSHARED pRead, PCRTLOCKVALIDATORSRCPOS pSrcPos)
    670913{
    671     AssertReturn(pWrite->u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    672     AssertReturn(pRead->u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     914    AssertReturn(pWrite->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     915    AssertReturn(pRead->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    673916    AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER);
    674917    if (!pWrite->fEnabled)
     
    686929RTDECL(int) RTLockValidatorUnwindReadWriteRecursion(PRTLOCKVALIDATORREC pWrite, PRTLOCKVALIDATORSHARED pRead)
    687930{
    688     AssertReturn(pWrite->u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    689     AssertReturn(pRead->u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     931    AssertReturn(pWrite->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     932    AssertReturn(pRead->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    690933    AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER);
    691934    if (!pWrite->fEnabled)
     
    702945RTDECL(RTTHREAD) RTLockValidatorSetOwner(PRTLOCKVALIDATORREC pRec, RTTHREAD hThread, PCRTLOCKVALIDATORSRCPOS pSrcPos)
    703946{
    704     AssertReturn(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC, NIL_RTTHREAD);
     947    AssertReturn(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, NIL_RTTHREAD);
    705948    if (!pRec->fEnabled)
    706949        return VINF_SUCCESS;
     
    738981RTDECL(RTTHREAD) RTLockValidatorUnsetOwner(PRTLOCKVALIDATORREC pRec)
    739982{
    740     AssertReturn(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC, NIL_RTTHREAD);
     983    AssertReturn(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, NIL_RTTHREAD);
    741984    if (!pRec->fEnabled)
    742985        return VINF_SUCCESS;
     
    7651008RTDECL(void) RTLockValidatorAddReadOwner(PRTLOCKVALIDATORSHARED pRead, RTTHREAD hThread, PCRTLOCKVALIDATORSRCPOS pSrcPos)
    7661009{
    767     AssertReturnVoid(pRead->u32Magic == RTLOCKVALIDATORSHARED_MAGIC);
     1010    AssertReturnVoid(pRead->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC);
    7681011    if (!pRead->fEnabled)
    7691012        return;
     
    7961039RTDECL(void) RTLockValidatorRemoveReadOwner(PRTLOCKVALIDATORSHARED pRead, RTTHREAD hThread)
    7971040{
    798     AssertReturnVoid(pRead->u32Magic == RTLOCKVALIDATORSHARED_MAGIC);
     1041    AssertReturnVoid(pRead->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC);
    7991042    if (!pRead->fEnabled)
    8001043        return;
     
    8841127
    8851128
    886 
    887 /**
    888  * Bitch about a deadlock.
    889  *
    890  * @param   pRec            The lock validator record we're going to block on.
    891  * @param   pThread         This thread.
    892  * @param   pCur            The thread we're deadlocking with.
    893  * @param   enmState        The sleep state.
    894  * @param   pSrcPos         Where we are going to deadlock.
    895  */
    896 static void rtLockValidatorComplainAboutDeadlock(PRTLOCKVALIDATORREC pRec, PRTTHREADINT pThread, RTTHREADSTATE enmState,
    897                                                  PRTTHREADINT pCur, PCRTLOCKVALIDATORSRCPOS pSrcPos)
    898 {
    899     RTAssertMsg1Weak(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", pSrcPos->uLine, pSrcPos->pszFile, pSrcPos->pszFunction);
    900 
    901     /*
    902      * Print the threads and locks involved.
    903      */
    904     PRTTHREADINT    apSeenThreads[8] = {0,0,0,0,0,0,0,0};
    905     unsigned        iSeenThread = 0;
    906     pCur = pThread;
    907     for (unsigned iEntry = 0; pCur && iEntry < 256; iEntry++)
     1129/**
     1130 * Checks for stack cycles caused by another deadlock before returning.
     1131 *
     1132 * @retval  VINF_SUCCESS if the stack is simply too small.
     1133 * @retval  VERR_SEM_LV_EXISTING_DEADLOCK if a cycle was detected.
     1134 *
     1135 * @param   pStack              The deadlock detection stack.
     1136 */
     1137static int rtLockValidatorDdHandleStackOverflow(PRTLOCKVALIDATORDDSTACK pStack)
     1138{
     1139    for (size_t i = 0; i < RT_ELEMENTS(pStack->a) - 1; i++)
     1140    {
     1141        PRTTHREADINT pThread = pStack->a[i].pThread;
     1142        for (size_t j = i + 1; j < RT_ELEMENTS(pStack->a); j++)
     1143            if (pStack->a[j].pThread == pThread)
     1144                return VERR_SEM_LV_EXISTING_DEADLOCK;
     1145    }
     1146    static bool volatile s_fComplained = false;
     1147    if (!s_fComplained)
     1148    {
     1149        s_fComplained = true;
     1150        rtLockValidatorComplain(RT_SRC_POS, "lock validator stack is too small! (%zu entries)\n", RT_ELEMENTS(pStack->a));
     1151    }
     1152    return VINF_SUCCESS;
     1153}
     1154
     1155
     1156/**
     1157 * Worker for rtLockValidatorDoDeadlockCheck that checks if there is more work
     1158 * to be done during unwind.
     1159 *
     1160 * @returns true if there is more work left for this lock, false if not.
     1161 * @param   pRec            The current record.
     1162 * @param   iEntry          The current index.
     1163 * @param   pFirstSibling   The first record we examined.
     1164 */
     1165DECL_FORCE_INLINE(bool) rtLockValidatorDdMoreWorkLeft(PRTLOCKVALIDATORRECUNION pRec, uint32_t iEntry, PRTLOCKVALIDATORRECUNION pFirstSibling)
     1166{
     1167    PRTLOCKVALIDATORRECUNION pSibling;
     1168
     1169    switch (pRec->Core.u32Magic)
     1170    {
     1171        case RTLOCKVALIDATORREC_MAGIC:
     1172            pSibling = pRec->Excl.pSibling;
     1173            break;
     1174
     1175        case RTLOCKVALIDATORSHARED_MAGIC:
     1176            if (iEntry + 1 < pRec->Shared.cAllocated)
     1177                return true;
     1178            pSibling = pRec->Excl.pSibling;
     1179            break;
     1180
     1181        default:
     1182            return false;
     1183    }
     1184    return pSibling != NULL
     1185        && pSibling != pFirstSibling;
     1186}
     1187
     1188
     1189/**
     1190 * Worker for rtLockValidatorDeadlockDetection that does the actual deadlock
     1191 * detection.
     1192 *
     1193 * @returns Same as rtLockValidatorDeadlockDetection.
     1194 * @param   pStack          The stack to use.
     1195 * @param   pOriginalRec    The original record.
     1196 * @param   pThreadSelf     The calling thread.
     1197 */
     1198static int rtLockValidatorDdDoDetection(PRTLOCKVALIDATORDDSTACK pStack, PRTLOCKVALIDATORRECUNION const pOriginalRec,
     1199                                        PRTTHREADINT const pThreadSelf)
     1200{
     1201    pStack->c = 0;
     1202
     1203    /* We could use a single RTLOCKVALIDATORDDENTRY variable here, but the
     1204       compiler may make a better job of it when using individual variables. */
     1205    PRTLOCKVALIDATORRECUNION    pRec            = pOriginalRec;
     1206    PRTLOCKVALIDATORRECUNION    pFirstSibling   = pOriginalRec;
     1207    uint32_t                    iEntry          = UINT32_MAX;
     1208    PRTTHREADINT                pThread         = NIL_RTTHREAD;
     1209    RTTHREADSTATE               enmState        = RTTHREADSTATE_RUNNING;
     1210    for (;;)
    9081211    {
    9091212        /*
    910          * Print info on pCur. Determin next while doing so.
     1213         * Process the current record.
    9111214         */
    912         RTAssertMsg2Weak(" #%u: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n",
    913                          iEntry, pCur, pCur->Core.Key, pCur->szName,
    914                          pCur->LockValidator.SrcPos.pszFile, pCur->LockValidator.SrcPos.uLine,
    915                          pCur->LockValidator.SrcPos.pszFunction, pCur->LockValidator.SrcPos.uId);
    916         PRTTHREADINT  pNext       = NULL;
    917         RTTHREADSTATE enmCurState = rtThreadGetState(pCur);
    918         switch (enmCurState)
     1215        /* Extract the (next) thread. */
     1216        PRTTHREADINT pNextThread;
     1217        switch (pRec->Core.u32Magic)
    9191218        {
    920             case RTTHREADSTATE_CRITSECT:
    921             case RTTHREADSTATE_EVENT:
    922             case RTTHREADSTATE_EVENT_MULTI:
    923             case RTTHREADSTATE_FAST_MUTEX:
    924             case RTTHREADSTATE_MUTEX:
    925             case RTTHREADSTATE_SPIN_MUTEX:
     1219            case RTLOCKVALIDATORREC_MAGIC:
     1220                Assert(iEntry == UINT32_MAX);
     1221                pNextThread = rtLockValidatorReadThreadHandle(&pRec->Excl.hThread);
     1222                if (    pNextThread
     1223                    &&  !RTTHREAD_IS_SLEEPING(pNextThread->enmState)
     1224                    &&  pNextThread != pThreadSelf)
     1225                    pNextThread = NIL_RTTHREAD;
     1226                if (    pNextThread == NIL_RTTHREAD
     1227                    &&  pRec->Excl.pSibling
     1228                    &&  pRec->Excl.pSibling != pFirstSibling)
     1229                {
     1230                    pRec = pRec->Excl.pSibling;
     1231                    continue;
     1232                }
     1233                break;
     1234
     1235            case RTLOCKVALIDATORSHARED_MAGIC:
     1236                /* Skip to the next sibling if same side.  ASSUMES reader priority. */
     1237                /** @todo The read side of a read-write lock is problematic if
     1238                 * the implementation prioritizes writers over readers because
     1239                 * that means we should could deadlock against current readers
     1240                 * if a writer showed up.  If the RW sem implementation is
     1241                 * wrapping some native API, it's not so easy to detect when we
     1242                 * should do this and when we shouldn't.  Checking when we
     1243                 * shouldn't is subject to wakeup scheduling and cannot easily
     1244                 * be made reliable.
     1245                 *
     1246                 * At the moment we circumvent all this mess by declaring that
     1247                 * readers has priority.  This is TRUE on linux, but probably
     1248                 * isn't on Solaris and FreeBSD. */
     1249                if (   pRec == pFirstSibling
     1250                    && pRec->Shared.pSibling != NULL
     1251                    && pRec->Shared.pSibling != pFirstSibling)
     1252                {
     1253                    pRec = pRec->Shared.pSibling;
     1254                    Assert(iEntry == UINT32_MAX);
     1255                    continue;
     1256                }
     1257
     1258                /* Scan the owner table for blocked owners. */
     1259                if (ASMAtomicUoReadU32(&pRec->Shared.cEntries) > 0)
     1260                {
     1261                    uint32_t                            cAllocated = ASMAtomicUoReadU32(&pRec->Shared.cAllocated);
     1262                    PRTLOCKVALIDATORSHAREDONE volatile *papOwners  = pRec->Shared.papOwners;
     1263                    while (++iEntry < cAllocated)
     1264                    {
     1265                        PRTLOCKVALIDATORSHAREDONE pEntry = rtLockValidatorUoReadSharedOwner(&papOwners[iEntry]);
     1266                        if (   pEntry
     1267                            && pEntry->Core.u32Magic == RTLOCKVALIDATORSHAREDONE_MAGIC)
     1268                        {
     1269                            pNextThread = rtLockValidatorReadThreadHandle(&pEntry->hThread);
     1270                            if (    pNextThread
     1271                                &&  !RTTHREAD_IS_SLEEPING(pNextThread->enmState)
     1272                                &&  pNextThread != pThreadSelf)
     1273                                pNextThread = NIL_RTTHREAD;
     1274                        }
     1275                        else
     1276                            Assert(!pEntry || pEntry->Core.u32Magic == RTLOCKVALIDATORSHAREDONE_MAGIC_DEAD);
     1277                    }
     1278                }
     1279
     1280                /* Advance to the next sibling, if any. */
     1281                Assert(pNextThread == NIL_RTTHREAD);
     1282                if (   pRec->Shared.pSibling != NULL
     1283                    && pRec->Shared.pSibling != pFirstSibling)
     1284                {
     1285                    pRec = pRec->Shared.pSibling;
     1286                    iEntry = UINT32_MAX;
     1287                    continue;
     1288                }
     1289                break;
     1290
     1291            case RTLOCKVALIDATORREC_MAGIC_DEAD:
     1292            case RTLOCKVALIDATORSHARED_MAGIC_DEAD:
     1293                pNextThread = NIL_RTTHREAD;
     1294                break;
     1295
     1296            case RTLOCKVALIDATORSHAREDONE_MAGIC:
     1297            case RTLOCKVALIDATORSHAREDONE_MAGIC_DEAD:
     1298            default:
     1299                AssertMsgFailed(("%p: %#x\n", pRec, pRec->Core));
     1300                pNextThread = NIL_RTTHREAD;
     1301                break;
     1302        }
     1303
     1304        /* Is that thread waiting for something? */
     1305        RTTHREADSTATE               enmNextState = RTTHREADSTATE_RUNNING;
     1306        PRTLOCKVALIDATORRECUNION    pNextRec     = NULL;
     1307        if (   pNextThread != NIL_RTTHREAD
     1308            && RT_LIKELY(pNextThread->u32Magic == RTTHREADINT_MAGIC))
     1309        {
     1310            do
    9261311            {
    927                 PRTLOCKVALIDATORREC pCurRec      = pCur->LockValidator.pRec;
    928                 RTTHREADSTATE       enmCurState2 = rtThreadGetState(pCur);
    929                 if (enmCurState2 != enmCurState)
     1312                enmNextState = rtThreadGetState(pNextThread);
     1313                if (    !RTTHREAD_IS_SLEEPING(enmNextState)
     1314                    &&  pNextThread != pThreadSelf)
     1315                    break;
     1316                pNextRec = rtLockValidatorReadRecUnionPtr(&pNextThread->LockValidator.pRec);
     1317                if (RT_LIKELY(   !pNextRec
     1318                              || enmNextState == rtThreadGetState(pNextThread)))
     1319                    break;
     1320                pNextRec = NULL;
     1321            } while (pNextThread->u32Magic == RTTHREADINT_MAGIC);
     1322        }
     1323        if (pNextRec)
     1324        {
     1325            /*
     1326             * Recurse and check for deadlock.
     1327             */
     1328            uint32_t i = pStack->c;
     1329            if (RT_UNLIKELY(i >= RT_ELEMENTS(pStack->a)))
     1330                return rtLockValidatorDdHandleStackOverflow(pStack);
     1331
     1332            pStack->c++;
     1333            pStack->a[i].pRec           = pRec;
     1334            pStack->a[i].iEntry         = iEntry;
     1335            pStack->a[i].enmState       = enmState;
     1336            pStack->a[i].pThread        = pThread;
     1337            pStack->a[i].pFirstSibling  = pFirstSibling;
     1338
     1339            if (RT_UNLIKELY(pNextThread == pThreadSelf))
     1340                return VERR_SEM_LV_DEADLOCK;
     1341
     1342            pRec            = pNextRec;
     1343            pFirstSibling   = pNextRec;
     1344            iEntry          = UINT32_MAX;
     1345            enmState        = enmNextState;
     1346            pThread         = pNextThread;
     1347        }
     1348        else if (RT_LIKELY(!pNextThread))
     1349        {
     1350            /*
     1351             * No deadlock here, unwind the stack and deal with any unfinished
     1352             * business there.
     1353             */
     1354            uint32_t i = pStack->c;
     1355            for (;;)
     1356            {
     1357                /* pop */
     1358                if (i == 0)
     1359                    return VINF_SUCCESS;
     1360                i--;
     1361
     1362                /* examine it. */
     1363                pRec            = pStack->a[i].pRec;
     1364                pFirstSibling   = pStack->a[i].pFirstSibling;
     1365                iEntry          = pStack->a[i].iEntry;
     1366                if (rtLockValidatorDdMoreWorkLeft(pRec, iEntry, pFirstSibling))
    9301367                {
    931                     RTAssertMsg2Weak(" Impossible!!! enmState=%s -> %s (%d)\n",
    932                                      RTThreadStateName(enmCurState), RTThreadStateName(enmCurState2), enmCurState2);
     1368                    enmState    = pStack->a[i].enmState;
     1369                    pThread     = pStack->a[i].pThread;
    9331370                    break;
    9341371                }
    935                 if (   VALID_PTR(pCurRec)
    936                     && pCurRec->u32Magic == RTLOCKVALIDATORREC_MAGIC)
    937                 {
    938                     RTAssertMsg2Weak("     Waiting on %s %p [%s]: Entered %s(%u) %s %p\n",
    939                                      RTThreadStateName(enmCurState), pCurRec->hLock, pCurRec->pszName,
    940                                      pCurRec->SrcPos.pszFile, pCurRec->SrcPos.uLine, pCurRec->SrcPos.pszFunction, pCurRec->SrcPos.uId);
    941                     pNext = pCurRec->hThread;
    942                 }
    943                 else if (VALID_PTR(pCurRec))
    944                     RTAssertMsg2Weak("     Waiting on %s pCurRec=%p: invalid magic number: %#x\n",
    945                                      RTThreadStateName(enmCurState), pCurRec, pCurRec->u32Magic);
    946                 else
    947                     RTAssertMsg2Weak("     Waiting on %s pCurRec=%p: invalid pointer\n",
    948                                      RTThreadStateName(enmCurState), pCurRec);
    949                 break;
    9501372            }
    951 
    952 #if 0
    953             case RTTHREADSTATE_RW_READ:
    954             case RTTHREADSTATE_RW_WRITE:
    955             {
    956             }
     1373        }
     1374        /* else: see if there is another thread to check for this lock. */
     1375    }
     1376}
     1377
     1378
     1379/**
     1380 * Check for the simple no-deadlock case.
     1381 *
     1382 * @returns true if no deadlock, false if further investigation is required.
     1383 *
     1384 * @param   pOriginalRec    The original record.
     1385 */
     1386DECLINLINE(int) rtLockValidatorIsSimpleNoDeadlockCase(PRTLOCKVALIDATORRECUNION pOriginalRec)
     1387{
     1388    if (    pOriginalRec->Excl.Core.u32Magic == RTLOCKVALIDATORREC_MAGIC
     1389        &&  !pOriginalRec->Excl.pSibling)
     1390    {
     1391        PRTTHREADINT pThread = rtLockValidatorReadThreadHandle(&pOriginalRec->Excl.hThread);
     1392        if (   !pThread
     1393            || pThread->u32Magic != RTTHREADINT_MAGIC)
     1394            return true;
     1395        RTTHREADSTATE enmState = rtThreadGetState(pThread);
     1396        if (!RTTHREAD_IS_SLEEPING(enmState))
     1397            return true;
     1398    }
     1399    return false;
     1400}
     1401
     1402
     1403/**
     1404 * Worker for rtLockValidatorDeadlockDetection that bitches about a deadlock.
     1405 *
     1406 * @param   pStack          The chain of locks causing the deadlock.
     1407 * @param   pThreadSelf     This thread.
     1408 * @param   pSrcPos         Where we are going to deadlock.
     1409 * @param   rc              The return code.
     1410 */
     1411static void rcLockValidatorDoDeadlockComplaining(PRTLOCKVALIDATORDDSTACK pStack, PRTTHREADINT pThreadSelf,
     1412                                                 PCRTLOCKVALIDATORSRCPOS pSrcPos, int rc)
     1413{
     1414    if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
     1415    {
     1416        rtLockValidatorComplainFirst(  rc == VERR_SEM_LV_DEADLOCK
     1417                                     ? "deadlock"
     1418                                     : rc == VERR_SEM_LV_EXISTING_DEADLOCK
     1419                                     ? "existing-deadlock"
     1420                                     : "!unexpected rc!",
     1421                                     pSrcPos, pThreadSelf, NULL);
     1422        rtLockValidatorComplainMore("---- start of %u entry deadlock chain ----\n", pStack->c);
     1423        for (uint32_t i = 0; i < pStack->c; i++)
     1424        {
     1425            char szPrefix[24];
     1426            RTStrPrintf(szPrefix, sizeof(szPrefix), "#%u: ", i);
     1427            PRTLOCKVALIDATORSHAREDONE pSharedOne = NULL;
     1428            if (pStack->a[i].pRec->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC)
     1429                pSharedOne = pStack->a[i].pRec->Shared.papOwners[pStack->a[i].iEntry];
     1430            if (VALID_PTR(pSharedOne) && pSharedOne->Core.u32Magic == RTLOCKVALIDATORSHAREDONE_MAGIC)
     1431                rtLockValidatorComplainAboutLock(szPrefix, (PRTLOCKVALIDATORRECUNION)pSharedOne, "\n");
     1432            else
     1433                rtLockValidatorComplainAboutLock(szPrefix, pStack->a[i].pRec, "\n");
     1434        }
     1435        rtLockValidatorComplainMore("---- end of deadlock chain ----\n");
     1436    }
     1437
     1438    rtLockValidatorComplainPanic();
     1439}
     1440
     1441
     1442/**
     1443 * Perform deadlock detection.
     1444 *
     1445 * @retval  VINF_SUCCESS
     1446 * @retval  VERR_SEM_LV_DEADLOCK
     1447 * @retval  VERR_SEM_LV_EXISTING_DEADLOCK
     1448 *
     1449 * @param   pRec            The record relating to the current thread's lock
     1450 *                          operation.
     1451 * @param   pThreadSelf     The current thread.
     1452 * @param   pSrcPos         The position of the current lock operation.
     1453 */
     1454static int rtLockValidatorDeadlockDetection(PRTLOCKVALIDATORRECUNION pRec, PRTTHREADINT pThreadSelf, PCRTLOCKVALIDATORSRCPOS pSrcPos)
     1455{
     1456#ifdef DEBUG_bird
     1457    RTLOCKVALIDATORDDSTACK Stack;
     1458    int rc = rtLockValidatorDdDoDetection(&Stack, pRec, pThreadSelf);
     1459    if (RT_FAILURE(rc))
     1460        rcLockValidatorDoDeadlockComplaining(&Stack, pThreadSelf, pSrcPos, rc);
     1461    return rc;
     1462#else
     1463    return VINF_SUCCESS;
    9571464#endif
    958 
    959             default:
    960                 RTAssertMsg2Weak(" Impossible!!! enmState=%s (%d)\n", RTThreadStateName(enmCurState), enmCurState);
    961                 break;
    962         }
    963 
    964         /*
    965          * Check for cycle.
    966          */
    967         if (iEntry && pCur == pThread)
    968             break;
    969         for (unsigned i = 0; i < RT_ELEMENTS(apSeenThreads); i++)
    970             if (apSeenThreads[i] == pCur)
    971             {
    972                 RTAssertMsg2Weak(" Cycle!\n");
    973                 pNext = NULL;
    974                 break;
    975             }
    976 
    977         /*
    978          * Advance to the next thread.
    979          */
    980         iSeenThread = (iSeenThread + 1) % RT_ELEMENTS(apSeenThreads);
    981         apSeenThreads[iSeenThread] = pCur;
    982         pCur = pNext;
    983     }
    984     AssertBreakpoint();
    985 }
     1465}
     1466
    9861467
    9871468
     
    9931474     * Fend off wild life.
    9941475     */
    995     AssertPtrReturn(pWrite, VERR_SEM_LV_INVALID_PARAMETER);
    996     AssertReturn(pWrite->u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1476    PRTLOCKVALIDATORRECUNION pWriteU = (PRTLOCKVALIDATORRECUNION)pWrite; /* (avoid break aliasing rules) */
     1477    AssertPtrReturn(pWriteU, VERR_SEM_LV_INVALID_PARAMETER);
     1478    AssertReturn(pWriteU->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1479    PRTLOCKVALIDATORRECUNION pReadU = (PRTLOCKVALIDATORRECUNION)pRead;
    9971480    AssertPtrReturn(pRead, VERR_SEM_LV_INVALID_PARAMETER);
    998     AssertReturn(pRead->u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    999     AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER);
    1000     if (!pWrite->fEnabled)
     1481    AssertReturn(pReadU->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1482    AssertReturn(pReadU->Shared.fEnabled == pWriteU->Excl.fEnabled, VERR_SEM_LV_INVALID_PARAMETER);
     1483    if (!pWriteU->Excl.fEnabled)
    10011484        return VINF_SUCCESS;
    10021485    AssertReturn(RTTHREAD_IS_SLEEPING(enmState), VERR_SEM_LV_INVALID_PARAMETER);
     
    10131496     * Check for attempts at doing a read upgrade.
    10141497     */
    1015     PRTLOCKVALIDATORSHAREDONE pEntry = rtLockValidatorSharedRecFindThread(pRead, hThread, NULL);
     1498    PRTLOCKVALIDATORSHAREDONE pEntry = rtLockValidatorSharedRecFindThread(&pReadU->Shared, hThread, NULL);
    10161499    if (pEntry)
    10171500    {
    1018         AssertMsgFailed(("Read lock upgrade at %s(%d) %s %p!\nRead lock take at %s(%d) %s %p!\n",
    1019                          pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId,
    1020                          pEntry->SrcPos.pszFile, pEntry->SrcPos.uLine, pEntry->SrcPos.pszFunction, pEntry->SrcPos.uId));
     1501        rtLockValidatorComplainFirst("Read lock upgrade", pSrcPos, pThread, (PRTLOCKVALIDATORRECUNION)pEntry);
     1502        rtLockValidatorComplainPanic();
    10211503        return VERR_SEM_LV_UPGRADE;
    10221504    }
     
    10361518     */
    10371519    AssertPtrReturn(pRead, VERR_SEM_LV_INVALID_PARAMETER);
    1038     AssertReturn(pRead->u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1520    AssertReturn(pRead->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    10391521    AssertPtrReturn(pWrite, VERR_SEM_LV_INVALID_PARAMETER);
    1040     AssertReturn(pWrite->u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1522    AssertReturn(pWrite->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    10411523    AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER);
    10421524    if (!pRead->fEnabled)
     
    10651547     * Fend off wild life.
    10661548     */
    1067     AssertPtrReturn(pRec, VERR_SEM_LV_INVALID_PARAMETER);
    1068     AssertReturn(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    1069     if (!pRec->fEnabled)
     1549    PRTLOCKVALIDATORRECUNION pRecU = (PRTLOCKVALIDATORRECUNION)pRec;
     1550    AssertPtrReturn(pRecU, VERR_SEM_LV_INVALID_PARAMETER);
     1551    AssertReturn(pRecU->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1552    if (!pRecU->Excl.fEnabled)
    10701553        return VINF_SUCCESS;
    10711554    AssertReturn(RTTHREAD_IS_SLEEPING(enmState), VERR_SEM_LV_INVALID_PARAMETER);
    1072     PRTTHREADINT pThread = hThread;
    1073     AssertPtrReturn(pThread, VERR_SEM_LV_INVALID_PARAMETER);
    1074     AssertReturn(pThread->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    1075     RTTHREADSTATE enmThreadState = rtThreadGetState(pThread);
     1555    PRTTHREADINT pThreadSelf = hThread;
     1556    AssertPtrReturn(pThreadSelf, VERR_SEM_LV_INVALID_PARAMETER);
     1557    AssertReturn(pThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
     1558    RTTHREADSTATE enmThreadState = rtThreadGetState(pThreadSelf);
    10761559    AssertReturn(   enmThreadState == RTTHREADSTATE_RUNNING
    10771560                 || enmThreadState == RTTHREADSTATE_TERMINATED   /* rtThreadRemove uses locks too */
     
    10831566     * performing deadlock detection.
    10841567     */
    1085     pThread->LockValidator.pRec = pRec;
    1086     rtLockValidatorCopySrcPos(&pThread->LockValidator.SrcPos, pSrcPos);
    1087 
    1088     /*
    1089      * Don't do deadlock detection if we're recursing and that's OK.
     1568    rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, pRecU);
     1569    rtLockValidatorCopySrcPos(&pThreadSelf->LockValidator.SrcPos, pSrcPos);
     1570
     1571    /*
     1572     * Don't do deadlock detection if we're recursing.
    10901573     *
    10911574     * On some hosts we don't do recursion accounting our selves and there
    10921575     * isn't any other place to check for this.  semmutex-win.cpp for instance.
    10931576     */
    1094     if (pRec->hThread == pThread)
     1577    if (rtLockValidatorReadThreadHandle(&pRecU->Excl.hThread) == pThreadSelf)
    10951578    {
    10961579        if (fRecursiveOk)
    10971580            return VINF_SUCCESS;
    1098         AssertMsgFailed(("%p (%s)\n", pRec->hLock, pRec->pszName));
     1581        rtLockValidatorComplainFirst("Recursion not allowed", pSrcPos, pThreadSelf, pRecU);
     1582        rtLockValidatorComplainPanic();
    10991583        return VERR_SEM_LV_NESTED;
    11001584    }
    11011585
    11021586    /*
    1103      * Do deadlock detection.
    1104      *
    1105      * Since we're missing proper serialization, we don't declare it a
    1106      * deadlock until we've got three runs with the same list length.
    1107      * While this isn't perfect, it should avoid out the most obvious
    1108      * races on SMP boxes.
    1109      */
    1110     rtLockValidatorSerializeDetectionEnter();
    1111 
    1112     PRTTHREADINT    pCur;
    1113     unsigned        cPrevLength = ~0U;
    1114     unsigned        cEqualRuns  = 0;
    1115     unsigned        iParanoia   = 256;
    1116     do
    1117     {
    1118         unsigned cLength = 0;
    1119         pCur = pThread;
    1120         for (;;)
    1121         {
    1122             /*
    1123              * Get the next thread.
    1124              */
    1125             PRTTHREADINT pNext = NULL;
    1126             for (;;)
    1127             {
    1128                 RTTHREADSTATE enmCurState = rtThreadGetState(pCur);
    1129                 switch (enmCurState)
    1130                 {
    1131                     case RTTHREADSTATE_CRITSECT:
    1132                     case RTTHREADSTATE_EVENT:
    1133                     case RTTHREADSTATE_EVENT_MULTI:
    1134                     case RTTHREADSTATE_FAST_MUTEX:
    1135                     case RTTHREADSTATE_MUTEX:
    1136                     case RTTHREADSTATE_SPIN_MUTEX:
    1137                     {
    1138                         PRTLOCKVALIDATORREC pCurRec = pCur->LockValidator.pRec;
    1139                         if (    rtThreadGetState(pCur) != enmCurState
    1140                             ||  !VALID_PTR(pCurRec)
    1141                             ||  pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC)
    1142                             continue;
    1143                         pNext = pCurRec->hThread;
    1144                         if (    rtThreadGetState(pCur) != enmCurState
    1145                             ||  pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC
    1146                             ||  pCurRec->hThread != pNext)
    1147                             continue;
    1148                         break;
    1149                     }
    1150 
    1151 #if 0
    1152                     case RTTHREADSTATE_RW_WRITE:
    1153                     {
    1154                         PRTLOCKVALIDATORREC pCurRec = pCur->LockValidator.pRec;
    1155                         if (    rtThreadGetState(pCur) != enmCurState
    1156                             ||  !VALID_PTR(pCurRec)
    1157                             ||  pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC)
    1158                             continue;
    1159 
    1160                         break;
    1161                     }
    1162 
    1163                     case RTTHREADSTATE_RW_READ:
    1164                     {
    1165                         PRTLOCKVALIDATORREC pCurRec = pCur->LockValidator.pRec;
    1166                         if (    rtThreadGetState(pCur) != enmCurState
    1167                             ||  !VALID_PTR(pCurRec)
    1168                             ||  pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC)
    1169                             continue;
    1170                         pNext = pCurRec->hThread;
    1171                         if (    rtThreadGetState(pCur) != enmCurState
    1172                             ||  pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC
    1173                             ||  pCurRec->hThread != pNext)
    1174                             continue;
    1175                         break;
    1176                     }
    1177 #endif
    1178 
    1179                     default:
    1180                         pNext = NULL;
    1181                         break;
    1182                 }
    1183                 break;
    1184             }
    1185 
    1186             /*
    1187              * If we arrive at the end of the list we're good.
    1188              */
    1189             pCur = pNext;
    1190             if (!pCur)
    1191             {
    1192                 rtLockValidatorSerializeDetectionLeave();
    1193                 return VINF_SUCCESS;
    1194             }
    1195 
    1196             /*
    1197              * If we've got back to the blocking thread id we've
    1198              * got a deadlock.
    1199              */
    1200             if (pCur == pThread)
    1201                 break;
    1202 
    1203             /*
    1204              * If we've got a chain of more than 256 items, there is some
    1205              * kind of cycle in the list, which means that there is already
    1206              * a deadlock somewhere.
    1207              */
    1208             if (cLength >= 256)
    1209                 break;
    1210 
    1211             cLength++;
    1212         }
    1213 
    1214         /* compare with previous list run. */
    1215         if (cLength != cPrevLength)
    1216         {
    1217             cPrevLength = cLength;
    1218             cEqualRuns = 0;
    1219         }
    1220         else
    1221             cEqualRuns++;
    1222     } while (cEqualRuns < 3 && --iParanoia > 0);
    1223 
    1224     /*
    1225      * Ok, if we ever get here, it's most likely a genuine deadlock.
    1226      */
    1227     rtLockValidatorComplainAboutDeadlock(pRec, pThread, enmState, pCur, pSrcPos);
    1228 
    1229     rtLockValidatorSerializeDetectionLeave();
    1230 
    1231     return VERR_SEM_LV_DEADLOCK;
     1587     * Perform deadlock detection.
     1588     */
     1589    if (rtLockValidatorIsSimpleNoDeadlockCase(pRecU))
     1590        return VINF_SUCCESS;
     1591    return rtLockValidatorDeadlockDetection(pRecU, pThreadSelf, pSrcPos);
    12321592}
    12331593RT_EXPORT_SYMBOL(RTLockValidatorCheckBlocking);
     
    12471607RT_EXPORT_SYMBOL(RTLockValidatorIsEnabled);
    12481608
     1609
     1610RTDECL(bool) RTLockValidatorSetQuiet(bool fQuiet)
     1611{
     1612    return ASMAtomicXchgBool(&g_fLockValidatorQuiet, fQuiet);
     1613}
     1614RT_EXPORT_SYMBOL(RTLockValidatorSetQuiet);
     1615
     1616
     1617RTDECL(bool) RTLockValidatorAreQuiet(void)
     1618{
     1619    return ASMAtomicUoReadBool(&g_fLockValidatorQuiet);
     1620}
     1621RT_EXPORT_SYMBOL(RTLockValidatorAreQuiet);
     1622
     1623
     1624RTDECL(bool) RTLockValidatorSetMayPanic(bool fMayPanic)
     1625{
     1626    return ASMAtomicXchgBool(&g_fLockValidatorMayPanic, fMayPanic);
     1627}
     1628RT_EXPORT_SYMBOL(RTLockValidatorSetMayPanic);
     1629
     1630
     1631RTDECL(bool) RTLockValidatorMayPanic(void)
     1632{
     1633    return ASMAtomicUoReadBool(&g_fLockValidatorMayPanic);
     1634}
     1635RT_EXPORT_SYMBOL(RTLockValidatorMayPanic);
     1636
Note: See TracChangeset for help on using the changeset viewer.

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