VirtualBox

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


Ignore:
Timestamp:
Dec 15, 2009 2:23:53 PM (15 years ago)
Author:
vboxsync
Message:

IPRT,PDMCritSect: Lock validation can only be performed in ring-3; fixed #PF on 32-bit darwin with debug builds. Hopefully fixed the recursion issue on windows.

Location:
trunk/src/VBox/Runtime/common/misc
Files:
2 edited

Legend:

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

    r25373 r25406  
    4343#include <iprt/thread.h>
    4444
     45#include "internal/lockvalidator.h"
    4546#include "internal/magics.h"
     47#include "internal/thread.h"
    4648
    4749
     
    6971    pRec->hClass        = hClass;
    7072    pRec->uSubClass     = uSubClass;
    71     pRec->u32Reserved   = UINT32_MAX;
     73    pRec->cRecursion    = 0;
    7274    pRec->hLock         = hLock;
    7375    pRec->pszName       = pszName;
     
    8486
    8587    RTLockValidatorInit(pRec, hClass, uSubClass, pszName, pvLock);
    86     pRec->u32Reserved = UINT32_MAX / 2;
    8788
    8889    return VINF_SUCCESS;
     
    9394{
    9495    Assert(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC);
    95     Assert(pRec->u32Reserved == UINT32_MAX);
    9696
    9797    ASMAtomicWriteU32(&pRec->u32Magic, RTLOCKVALIDATORREC_MAGIC_DEAD);
    9898    ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD);
    9999    ASMAtomicWriteHandle(&pRec->hClass, NIL_RTLOCKVALIDATORCLASS);
    100     ASMAtomicWriteU32(&pRec->u32Reserved, 0);
    101100}
    102101
     
    108107    if (pRec)
    109108    {
    110         Assert(pRec->u32Reserved == UINT32_MAX / 2);
    111         pRec->u32Reserved = UINT32_MAX;
    112109        RTLockValidatorDelete(pRec);
    113110        RTMemFree(pRec);
     
    136133{
    137134    AssertReturn(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC, NIL_RTTHREAD);
    138     Assert(pRec->hThread == NIL_RTTHREAD);
    139 
    140     /*
    141      * Update the record.
    142      */
    143     ASMAtomicUoWriteU32(&pRec->uLine, iLine);
    144     ASMAtomicUoWritePtr((void * volatile *)&pRec->pszFile,      pszFile);
    145     ASMAtomicUoWritePtr((void * volatile *)&pRec->pszFunction,  pszFunction);
    146     ASMAtomicUoWritePtr((void * volatile *)&pRec->uId,          (void *)uId);
    147135
    148136    if (hThread == NIL_RTTHREAD)
    149 #ifdef IN_RING3
    150137        hThread = RTThreadSelfAutoAdopt();
    151 #else
    152         hThread = RTThreadSelf();
    153 #endif
    154     ASMAtomicWriteHandle(&pRec->hThread, hThread);
    155 
    156     /*
    157      * Push the lock onto the lock stack.
    158      */
    159     /** @todo push it onto the per-thread lock stack. */
     138    if (pRec->hThread == hThread)
     139        pRec->cRecursion++;
     140    else
     141    {
     142        Assert(pRec->hThread == NIL_RTTHREAD);
     143
     144        /*
     145         * Update the record.
     146         */
     147        ASMAtomicUoWriteU32(&pRec->uLine, iLine);
     148        ASMAtomicUoWritePtr((void * volatile *)&pRec->pszFile,      pszFile);
     149        ASMAtomicUoWritePtr((void * volatile *)&pRec->pszFunction,  pszFunction);
     150        ASMAtomicUoWritePtr((void * volatile *)&pRec->uId,          (void *)uId);
     151        ASMAtomicUoWriteU32(&pRec->cRecursion, 1);
     152
     153        ASMAtomicWriteHandle(&pRec->hThread, hThread);
     154
     155        /*
     156         * Push the lock onto the lock stack.
     157         */
     158        /** @todo push it onto the per-thread lock stack. */
     159    }
    160160
    161161    return hThread;
     
    168168    RTTHREAD hThread = pRec->hThread;
    169169    AssertReturn(hThread != NIL_RTTHREAD, hThread);
    170 
    171     /*
    172      * Pop (remove) the lock.
    173      */
    174     /** @todo remove it from the per-thread stack/whatever. */
    175 
    176     /*
    177      * Update the record.
    178      */
    179     ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD);
     170    AssertReturn(pRec->hThread == hThread, hThread);
     171
     172    if (ASMAtomicDecU32(&pRec->cRecursion) == 0)
     173    {
     174        /*
     175         * Pop (remove) the lock.
     176         */
     177        /** @todo remove it from the per-thread stack/whatever. */
     178
     179        /*
     180         * Update the record.
     181         */
     182        ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD);
     183    }
    180184
    181185    return hThread;
    182186}
    183187
     188
     189/**
     190 * Bitch about a deadlock.
     191 *
     192 * @param   pRec            The lock validator record we're going to block on.
     193 * @param   pThread         This thread.
     194 * @param   pCur            The thread we're deadlocking with.
     195 * @param   enmState        The sleep state.
     196 * @param   RT_SRC_POS_DECL Where we are going to deadlock.
     197 * @param   uId             Where we are going to deadlock.
     198 */
     199static void rtLockValidatorComplainAboutDeadlock(PRTLOCKVALIDATORREC pRec, PRTTHREADINT pThread, RTTHREADSTATE enmState,
     200                                                 PRTTHREADINT pCur, RTHCUINTPTR uId, RT_SRC_POS_DECL)
     201{
     202    AssertMsg1(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", iLine, pszFile, pszFunction);
     203
     204    /*
     205     * Print the threads and locks involved.
     206     */
     207    PRTTHREADINT    apSeenThreads[8] = {0,0,0,0,0,0,0,0};
     208    unsigned        iSeenThread = 0;
     209    pCur = pThread;
     210    for (unsigned iEntry = 0; pCur && iEntry < 256; iEntry++)
     211    {
     212        /*
     213         * Print info on pCur. Determin next while doing so.
     214         */
     215        AssertMsg2(" #%u: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n",
     216                   iEntry, pCur, pCur->Core.Key, pCur->szName,
     217                   pCur->LockValidator.pszBlockFile, pCur->LockValidator.uBlockLine,
     218                   pCur->LockValidator.pszBlockFunction, pCur->LockValidator.uBlockId);
     219        PRTTHREADINT  pNext       = NULL;
     220        RTTHREADSTATE enmCurState = rtThreadGetState(pCur);
     221        switch (enmCurState)
     222        {
     223            case RTTHREADSTATE_CRITSECT:
     224            case RTTHREADSTATE_EVENT:
     225            case RTTHREADSTATE_EVENT_MULTI:
     226            case RTTHREADSTATE_FAST_MUTEX:
     227            case RTTHREADSTATE_MUTEX:
     228            case RTTHREADSTATE_RW_READ:
     229            case RTTHREADSTATE_RW_WRITE:
     230            case RTTHREADSTATE_SPIN_MUTEX:
     231            {
     232                PRTLOCKVALIDATORREC pCurRec      = pCur->LockValidator.pRec;
     233                RTTHREADSTATE       enmCurState2 = rtThreadGetState(pCur);
     234                if (enmCurState2 != enmCurState)
     235                {
     236                    AssertMsg2(" Impossible!!! enmState=%s -> %s (%d)\n",
     237                               RTThreadStateName(enmCurState), RTThreadStateName(enmCurState2), enmCurState2);
     238                    break;
     239                }
     240                if (   VALID_PTR(pCurRec)
     241                    && pCurRec->u32Magic == RTLOCKVALIDATORREC_MAGIC)
     242                {
     243                    AssertMsg2("     Waiting on %s %p [%s]: Entered %s(%u) %s %p\n",
     244                               RTThreadStateName(enmCurState), pCurRec->hLock, pCurRec->pszName,
     245                               pCurRec->pszFile, pCurRec->uLine, pCurRec->pszFunction, pCurRec->uId);
     246                    pNext = pCurRec->hThread;
     247                }
     248                else if (VALID_PTR(pCurRec))
     249                    AssertMsg2("     Waiting on %s pCurRec=%p: invalid magic number: %#x\n",
     250                               RTThreadStateName(enmCurState), pCurRec, pCurRec->u32Magic);
     251                else
     252                    AssertMsg2("     Waiting on %s pCurRec=%p: invalid pointer\n",
     253                               RTThreadStateName(enmCurState), pCurRec);
     254                break;
     255            }
     256
     257            default:
     258                AssertMsg2(" Impossible!!! enmState=%s (%d)\n", RTThreadStateName(enmCurState), enmCurState);
     259                break;
     260        }
     261
     262        /*
     263         * Check for cycle.
     264         */
     265        if (iEntry && pCur == pThread)
     266            break;
     267        for (unsigned i = 0; i < RT_ELEMENTS(apSeenThreads); i++)
     268            if (apSeenThreads[i] == pCur)
     269            {
     270                AssertMsg2(" Cycle!\n");
     271                pNext = NULL;
     272                break;
     273            }
     274
     275        /*
     276         * Advance to the next thread.
     277         */
     278        iSeenThread = (iSeenThread + 1) % RT_ELEMENTS(apSeenThreads);
     279        apSeenThreads[iSeenThread] = pCur;
     280        pCur = pNext;
     281    }
     282    AssertBreakpoint();
     283}
     284
     285
     286/**
     287 * Change the thread state to blocking and do deadlock detection.
     288 *
     289 * @param   pRec                The validator record we're blocing on.
     290 * @param   hThread             The current thread.  Shall not be NIL_RTTHREAD!
     291 * @param   enmState            The sleep state.
     292 * @param   pvBlock             Pointer to a RTLOCKVALIDATORREC structure.
     293 * @param   fRecursiveOk        Whether it's ok to recurse.
     294 * @param   uId                 Where we are blocking.
     295 * @param   RT_SRC_POS_DECL     Where we are blocking.
     296 */
     297RTDECL(void) RTLockValidatorCheckBlocking(PRTLOCKVALIDATORREC pRec, RTTHREAD hThread,
     298                                          RTTHREADSTATE enmState, bool fRecursiveOk,
     299                                          RTHCUINTPTR uId, RT_SRC_POS_DECL)
     300{
     301    /*
     302     * Fend off wild life.
     303     */
     304    AssertReturnVoid(RTTHREAD_IS_SLEEPING(enmState));
     305    AssertPtrReturnVoid(pRec);
     306    AssertReturnVoid(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC);
     307    PRTTHREADINT pThread = hThread;
     308    AssertPtrReturnVoid(pThread);
     309    AssertReturnVoid(pThread->u32Magic == RTTHREADINT_MAGIC);
     310    AssertReturnVoid(rtThreadGetState(pThread) == RTTHREADSTATE_RUNNING);
     311
     312    /*
     313     * Record the location and everything before changing the state and
     314     * performing deadlock detection.
     315     */
     316    /** @todo This has to be serialized! The deadlock detection isn't 100% safe!!! */
     317    pThread->LockValidator.pRec             = pRec;
     318    pThread->LockValidator.pszBlockFunction = pszFunction;
     319    pThread->LockValidator.pszBlockFile     = pszFile;
     320    pThread->LockValidator.uBlockLine       = iLine;
     321    pThread->LockValidator.uBlockId         = uId;
     322
     323    RTThreadBlocking(hThread, enmState);
     324
     325    /*
     326     * Don't do deadlock detection if we're recursing and that's OK.
     327     *
     328     * On some hosts we don't do recursion accounting our selves and there
     329     * isn't any other place to check for this.  semmutex-win.cpp for instance.
     330     */
     331    if (    !fRecursiveOk
     332        ||  pRec->hThread != pThread)
     333    {
     334        /*
     335         * Do deadlock detection.
     336         *
     337         * Since we're missing proper serialization, we don't declare it a
     338         * deadlock until we've got three runs with the same list length.
     339         * While this isn't perfect, it should avoid out the most obvious
     340         * races on SMP boxes.
     341         */
     342        PRTTHREADINT    pCur;
     343        unsigned        cPrevLength = ~0U;
     344        unsigned        cEqualRuns  = 0;
     345        unsigned        iParanoia   = 256;
     346        do
     347        {
     348            unsigned cLength = 0;
     349            pCur = pThread;
     350            for (;;)
     351            {
     352                /*
     353                 * Get the next thread.
     354                 */
     355                PRTTHREADINT pNext = NULL;
     356                for (;;)
     357                {
     358                    RTTHREADSTATE enmCurState = rtThreadGetState(pCur);
     359                    switch (enmCurState)
     360                    {
     361                        case RTTHREADSTATE_CRITSECT:
     362                        case RTTHREADSTATE_EVENT:
     363                        case RTTHREADSTATE_EVENT_MULTI:
     364                        case RTTHREADSTATE_FAST_MUTEX:
     365                        case RTTHREADSTATE_MUTEX:
     366                        case RTTHREADSTATE_RW_READ:
     367                        case RTTHREADSTATE_RW_WRITE:
     368                        case RTTHREADSTATE_SPIN_MUTEX:
     369                        {
     370                            PRTLOCKVALIDATORREC pCurRec = pCur->LockValidator.pRec;
     371                            if (    rtThreadGetState(pCur) != enmCurState
     372                                ||  !VALID_PTR(pCurRec)
     373                                ||  pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC)
     374                                continue;
     375                            pNext = pCurRec->hThread;
     376                            if (    rtThreadGetState(pCur) != enmCurState
     377                                ||  pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC
     378                                ||  pCurRec->hThread != pNext)
     379                                continue;
     380                            break;
     381                        }
     382
     383                        default:
     384                            pNext = NULL;
     385                            break;
     386                    }
     387                    break;
     388                }
     389
     390                /*
     391                 * If we arrive at the end of the list we're good.
     392                 */
     393                pCur = pNext;
     394                if (!pCur)
     395                    return;
     396
     397                /*
     398                 * If we've got back to the blocking thread id we've
     399                 * got a deadlock.
     400                 */
     401                if (pCur == pThread)
     402                    break;
     403
     404                /*
     405                 * If we've got a chain of more than 256 items, there is some
     406                 * kind of cycle in the list, which means that there is already
     407                 * a deadlock somewhere.
     408                 */
     409                if (cLength >= 256)
     410                    break;
     411
     412                cLength++;
     413            }
     414
     415            /* compare with previous list run. */
     416            if (cLength != cPrevLength)
     417            {
     418                cPrevLength = cLength;
     419                cEqualRuns = 0;
     420            }
     421            else
     422                cEqualRuns++;
     423        } while (cEqualRuns < 3 && --iParanoia > 0);
     424
     425        /*
     426         * Ok, if we ever get here, it's most likely a genuine deadlock.
     427         */
     428        rtLockValidatorComplainAboutDeadlock(pRec, pThread, enmState, pCur, uId, RT_SRC_POS_ARGS);
     429    }
     430}
     431RT_EXPORT_SYMBOL(RTThreadBlocking);
     432
  • trunk/src/VBox/Runtime/common/misc/thread.cpp

    r25398 r25406  
    194194        AssertMsg2("WARNING: g_ThreadTree=%p\n", g_ThreadTree);
    195195#endif
    196 }
    197 
    198 
    199 /**
    200  * Gets the thread state.
    201  *
    202  * @returns The thread state.
    203  * @param   pThread             The thread.
    204  */
    205 DECLINLINE(RTTHREADSTATE) rtThreadGetState(PRTTHREADINT pThread)
    206 {
    207     return pThread->enmState;
    208196}
    209197
     
    12291217 * @returns Number of locks on success (0+) and VERR_INVALID_HANDLER on failure
    12301218 * @param   Thread          The thread we're inquiring about.
     1219 *
     1220 * @todo Move this.
    12311221 */
    12321222RTDECL(int32_t) RTThreadGetWriteLockCount(RTTHREAD Thread)
     
    12381228    if (!pThread)
    12391229        return VERR_INVALID_HANDLE;
    1240     int32_t cWriteLocks = ASMAtomicReadS32(&pThread->cWriteLocks);
     1230    int32_t cWriteLocks = ASMAtomicReadS32(&pThread->LockValidator.cWriteLocks);
    12411231    rtThreadRelease(pThread);
    12421232    return cWriteLocks;
     
    12491239 *
    12501240 * @param   Thread      The current thread.
     1241 *
     1242 * @todo Move this.
    12511243 */
    12521244RTDECL(void) RTThreadWriteLockInc(RTTHREAD Thread)
     
    12541246    PRTTHREADINT pThread = rtThreadGet(Thread);
    12551247    AssertReturnVoid(pThread);
    1256     ASMAtomicIncS32(&pThread->cWriteLocks);
     1248    ASMAtomicIncS32(&pThread->LockValidator.cWriteLocks);
    12571249    rtThreadRelease(pThread);
    12581250}
     
    12641256 *
    12651257 * @param   Thread      The current thread.
     1258 *
     1259 * @todo Move this.
    12661260 */
    12671261RTDECL(void) RTThreadWriteLockDec(RTTHREAD Thread)
     
    12691263    PRTTHREADINT pThread = rtThreadGet(Thread);
    12701264    AssertReturnVoid(pThread);
    1271     ASMAtomicDecS32(&pThread->cWriteLocks);
     1265    ASMAtomicDecS32(&pThread->LockValidator.cWriteLocks);
    12721266    rtThreadRelease(pThread);
    12731267}
     
    12851279 * @returns Number of read locks on success (0+) and VERR_INVALID_HANDLER on failure
    12861280 * @param   Thread          The thread we're inquiring about.
     1281 *
     1282 * @todo Move this.
    12871283 */
    12881284RTDECL(int32_t) RTThreadGetReadLockCount(RTTHREAD Thread)
     
    12941290    if (!pThread)
    12951291        return VERR_INVALID_HANDLE;
    1296     int32_t cReadLocks = ASMAtomicReadS32(&pThread->cReadLocks);
     1292    int32_t cReadLocks = ASMAtomicReadS32(&pThread->LockValidator.cReadLocks);
    12971293    rtThreadRelease(pThread);
    12981294    return cReadLocks;
     
    13051301 *
    13061302 * @param   Thread      The current thread.
     1303 *
     1304 * @todo Move this.
    13071305 */
    13081306RTDECL(void) RTThreadReadLockInc(RTTHREAD Thread)
     
    13101308    PRTTHREADINT pThread = rtThreadGet(Thread);
    13111309    Assert(pThread);
    1312     ASMAtomicIncS32(&pThread->cReadLocks);
     1310    ASMAtomicIncS32(&pThread->LockValidator.cReadLocks);
    13131311    rtThreadRelease(pThread);
    13141312}
     
    13201318 *
    13211319 * @param   Thread      The current thread.
     1320 *
     1321 * @todo Move this.
    13221322 */
    13231323RTDECL(void) RTThreadReadLockDec(RTTHREAD Thread)
     
    13251325    PRTTHREADINT pThread = rtThreadGet(Thread);
    13261326    Assert(pThread);
    1327     ASMAtomicDecS32(&pThread->cReadLocks);
     1327    ASMAtomicDecS32(&pThread->LockValidator.cReadLocks);
    13281328    rtThreadRelease(pThread);
    13291329}
     
    14211421
    14221422/**
     1423 * Change the thread state to blocking.
     1424 *
     1425 * @param   hThread         The current thread.
     1426 * @param   enmState        The sleep state.
     1427 */
     1428RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState)
     1429{
     1430    Assert(RTTHREAD_IS_SLEEPING(enmState));
     1431    PRTTHREADINT pThread = hThread;
     1432    if (hThread && rtThreadGetState(pThread) != RTTHREADSTATE_RUNNING)
     1433        rtThreadSetState(pThread, enmState);
     1434}
     1435RT_EXPORT_SYMBOL(RTThreadBlocking);
     1436
     1437
     1438/**
     1439 * Unblocks a thread.
     1440 *
     1441 * This function is paired with rtThreadBlocking.
     1442 *
     1443 * @param   hThread     The current thread.
     1444 * @param   enmCurState The current state, used to check for nested blocking.
     1445 *                      The new state will be running.
     1446 */
     1447RTDECL(void) RTThreadUnblocked(RTTHREAD hThread, RTTHREADSTATE enmCurState)
     1448{
     1449    if (hThread && rtThreadGetState(hThread) == enmCurState)
     1450        rtThreadSetState(hThread, RTTHREADSTATE_RUNNING);
     1451}
     1452RT_EXPORT_SYMBOL(RTThreadUnblocked);
     1453
     1454
     1455/**
    14231456 * Translate a thread state into a string.
    14241457 *
     
    14261459 * @param   enmState            The state.
    14271460 */
    1428 static const char *rtThreadStateName(RTTHREADSTATE enmState)
     1461RTDECL(const char *) RTThreadStateName(RTTHREADSTATE enmState)
    14291462{
    14301463    switch (enmState)
     
    14461479    }
    14471480}
    1448 
    1449 
    1450 /**
    1451  * Bitch about a deadlock.
    1452  *
    1453  * @param   pThread         This thread.
    1454  * @param   pCur            The thread we're deadlocking with.
    1455  * @param   enmState        The sleep state.
    1456  * @param   pRec            The lock validator record we're going to block on.
    1457  * @param   RT_SRC_POS_DECL Where we are going to deadlock.
    1458  * @param   uId             Where we are going to deadlock.
    1459  */
    1460 static void rtThreadDeadlock(PRTTHREADINT pThread, PRTTHREADINT pCur, RTTHREADSTATE enmState,
    1461                              PRTLOCKVALIDATORREC pRec, RTHCUINTPTR uId, RT_SRC_POS_DECL)
    1462 {
    1463     AssertMsg1(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", iLine, pszFile, pszFunction);
    1464 
    1465     /*
    1466      * Print the threads and locks involved.
    1467      */
    1468     PRTTHREADINT    apSeenThreads[8] = {0,0,0,0,0,0,0,0};
    1469     unsigned        iSeenThread = 0;
    1470     pCur = pThread;
    1471     for (unsigned iEntry = 0; pCur && iEntry < 256; iEntry++)
    1472     {
    1473         /*
    1474          * Print info on pCur. Determin next while doing so.
    1475          */
    1476         AssertMsg2(" #%u: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n",
    1477                    iEntry, pCur, pCur->Core.Key, pCur->szName,
    1478                    pCur->pszBlockFile, pCur->uBlockLine, pCur->pszBlockFunction, pCur->uBlockId);
    1479         PRTTHREADINT  pNext       = NULL;
    1480         RTTHREADSTATE enmCurState = rtThreadGetState(pCur);
    1481         switch (enmCurState)
    1482         {
    1483             case RTTHREADSTATE_CRITSECT:
    1484             case RTTHREADSTATE_EVENT:
    1485             case RTTHREADSTATE_EVENT_MULTI:
    1486             case RTTHREADSTATE_FAST_MUTEX:
    1487             case RTTHREADSTATE_MUTEX:
    1488             case RTTHREADSTATE_RW_READ:
    1489             case RTTHREADSTATE_RW_WRITE:
    1490             case RTTHREADSTATE_SPIN_MUTEX:
    1491             {
    1492                 PRTLOCKVALIDATORREC pCurRec      = pCur->Block.pRec;
    1493                 RTTHREADSTATE       enmCurState2 = rtThreadGetState(pCur);
    1494                 if (enmCurState2 != enmCurState)
    1495                 {
    1496                     AssertMsg2(" Impossible!!! enmState=%s -> %s (%d)\n",
    1497                                rtThreadStateName(enmCurState), rtThreadStateName(enmCurState2), enmCurState2);
    1498                     break;
    1499                 }
    1500                 if (   VALID_PTR(pCurRec)
    1501                     && pCurRec->u32Magic == RTLOCKVALIDATORREC_MAGIC)
    1502                 {
    1503                     AssertMsg2("     Waiting on %s %p [%s]: Entered %s(%u) %s %p\n",
    1504                                rtThreadStateName(enmCurState), pCurRec->hLock, pCurRec->pszName,
    1505                                pCurRec->pszFile, pCurRec->uLine, pCurRec->pszFunction, pCurRec->uId);
    1506                     pNext = pCurRec->hThread;
    1507                 }
    1508                 else if (VALID_PTR(pCurRec))
    1509                     AssertMsg2("     Waiting on %s pCurRec=%p: invalid magic number: %#x\n",
    1510                                rtThreadStateName(enmCurState), pCurRec, pCurRec->u32Magic);
    1511                 else
    1512                     AssertMsg2("     Waiting on %s pCurRec=%p: invalid pointer\n",
    1513                                rtThreadStateName(enmCurState), pCurRec);
    1514                 break;
    1515             }
    1516 
    1517             default:
    1518                 AssertMsg2(" Impossible!!! enmState=%s (%d)\n", rtThreadStateName(enmCurState), enmCurState);
    1519                 break;
    1520         }
    1521 
    1522         /*
    1523          * Check for cycle.
    1524          */
    1525         if (iEntry && pCur == pThread)
    1526             break;
    1527         for (unsigned i = 0; i < RT_ELEMENTS(apSeenThreads); i++)
    1528             if (apSeenThreads[i] == pCur)
    1529             {
    1530                 AssertMsg2(" Cycle!\n");
    1531                 pNext = NULL;
    1532                 break;
    1533             }
    1534 
    1535         /*
    1536          * Advance to the next thread.
    1537          */
    1538         iSeenThread = (iSeenThread + 1) % RT_ELEMENTS(apSeenThreads);
    1539         apSeenThreads[iSeenThread] = pCur;
    1540         pCur = pNext;
    1541     }
    1542     AssertBreakpoint();
    1543 }
    1544 
    1545 
    1546 /**
    1547  * Change the thread state to blocking.
    1548  *
    1549  * @param   hThread         The current thread.
    1550  * @param   enmState        The sleep state.
    1551  */
    1552 RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState)
    1553 
    1554 {
    1555     Assert(RTTHREAD_IS_SLEEPING(enmState));
    1556 
    1557     /*
    1558      * Fend off wild life.
    1559      */
    1560     PRTTHREADINT pThread = hThread;
    1561     if (!pThread)
    1562         return;
    1563     if (rtThreadGetState(pThread) != RTTHREADSTATE_RUNNING)
    1564         return;
    1565 
    1566     /*
    1567      * Do the job.
    1568      */
    1569     rtThreadSetState(pThread, enmState);
    1570 }
    1571 
    1572 
    1573 /**
    1574  * Change the thread state to blocking and do deadlock detection.
    1575  *
    1576  * This is a RT_STRICT method for debugging locks and detecting deadlocks.
    1577  *
    1578  * @param   hThread         The current thread.
    1579  * @param   enmState        The sleep state.
    1580  * @param   pvBlock         Pointer to a RTLOCKVALIDATORREC structure.
    1581  * @param   fRecursiveOk    Whether it's ok to recurse.
    1582  * @param   uId             Where we are blocking.
    1583  * @param   RT_SRC_POS_DECL Where we are blocking.
    1584  *
    1585  * @todo    Move this to RTLockValidator.
    1586  */
    1587 RTDECL(void) RTThreadBlockingDebug(RTTHREAD hThread, RTTHREADSTATE enmState, bool fRecursiveOk,
    1588                                    PRTLOCKVALIDATORREC pValidatorRec, RTHCUINTPTR uId, RT_SRC_POS_DECL)
    1589 
    1590 {
    1591     /*
    1592      * Fend off wild life.
    1593      */
    1594     AssertReturnVoid(RTTHREAD_IS_SLEEPING(enmState));
    1595     AssertPtrReturnVoid(pValidatorRec);
    1596     AssertReturnVoid(pValidatorRec->u32Magic == RTLOCKVALIDATORREC_MAGIC);
    1597     PRTTHREADINT pThread = hThread;
    1598     AssertPtrReturnVoid(pThread);
    1599     AssertReturnVoid(pThread->u32Magic == RTTHREADINT_MAGIC);
    1600     AssertReturnVoid(rtThreadGetState(pThread) == RTTHREADSTATE_RUNNING);
    1601 
    1602     /*
    1603      * Record the location and everything before changing the state and
    1604      * performing deadlock detection.
    1605      */
    1606     /** @todo This has to be serialized! The deadlock detection isn't 100% safe!!! */
    1607     pThread->Block.pRec         = pValidatorRec;
    1608     pThread->pszBlockFunction   = pszFunction;
    1609     pThread->pszBlockFile       = pszFile;
    1610     pThread->uBlockLine         = iLine;
    1611     pThread->uBlockId           = uId;
    1612     rtThreadSetState(pThread, enmState);
    1613 
    1614     /*
    1615      * Don't do deadlock detection if we're recursing and that's OK.
    1616      *
    1617      * On some hosts we don't do recursion accounting our selves and there
    1618      * isn't any other place to check for this.  semmutex-win.cpp for instance.
    1619      */
    1620     if (    !fRecursiveOk
    1621         ||  pValidatorRec->hThread != pThread)
    1622     {
    1623         /*
    1624          * Do deadlock detection.
    1625          *
    1626          * Since we're missing proper serialization, we don't declare it a
    1627          * deadlock until we've got three runs with the same list length.
    1628          * While this isn't perfect, it should avoid out the most obvious
    1629          * races on SMP boxes.
    1630          */
    1631         PRTTHREADINT    pCur;
    1632         unsigned        cPrevLength = ~0U;
    1633         unsigned        cEqualRuns  = 0;
    1634         unsigned        iParanoia   = 256;
    1635         do
    1636         {
    1637             unsigned cLength = 0;
    1638             pCur = pThread;
    1639             for (;;)
    1640             {
    1641                 /*
    1642                  * Get the next thread.
    1643                  */
    1644                 PRTTHREADINT pNext = NULL;
    1645                 for (;;)
    1646                 {
    1647                     RTTHREADSTATE enmCurState = rtThreadGetState(pCur);
    1648                     switch (enmCurState)
    1649                     {
    1650                         case RTTHREADSTATE_CRITSECT:
    1651                         case RTTHREADSTATE_EVENT:
    1652                         case RTTHREADSTATE_EVENT_MULTI:
    1653                         case RTTHREADSTATE_FAST_MUTEX:
    1654                         case RTTHREADSTATE_MUTEX:
    1655                         case RTTHREADSTATE_RW_READ:
    1656                         case RTTHREADSTATE_RW_WRITE:
    1657                         case RTTHREADSTATE_SPIN_MUTEX:
    1658                         {
    1659                             PRTLOCKVALIDATORREC pRec = pCur->Block.pRec;
    1660                             if (    rtThreadGetState(pCur) != enmCurState
    1661                                 ||  !VALID_PTR(pRec)
    1662                                 ||  pRec->u32Magic != RTLOCKVALIDATORREC_MAGIC)
    1663                                 continue;
    1664                             pNext = pRec->hThread;
    1665                             if (    rtThreadGetState(pCur) != enmCurState
    1666                                 ||  pRec->u32Magic != RTLOCKVALIDATORREC_MAGIC
    1667                                 ||  pRec->hThread != pNext)
    1668                                 continue;
    1669                             break;
    1670                         }
    1671 
    1672                         default:
    1673                             pNext = NULL;
    1674                             break;
    1675                     }
    1676                     break;
    1677                 }
    1678 
    1679                 /*
    1680                  * If we arrive at the end of the list we're good.
    1681                  */
    1682                 pCur = pNext;
    1683                 if (!pCur)
    1684                     return;
    1685 
    1686                 /*
    1687                  * If we've got back to the blocking thread id we've
    1688                  * got a deadlock.
    1689                  */
    1690                 if (pCur == pThread)
    1691                     break;
    1692 
    1693                 /*
    1694                  * If we've got a chain of more than 256 items, there is some
    1695                  * kind of cycle in the list, which means that there is already
    1696                  * a deadlock somewhere.
    1697                  */
    1698                 if (cLength >= 256)
    1699                     break;
    1700 
    1701                 cLength++;
    1702             }
    1703 
    1704             /* compare with previous list run. */
    1705             if (cLength != cPrevLength)
    1706             {
    1707                 cPrevLength = cLength;
    1708                 cEqualRuns = 0;
    1709             }
    1710             else
    1711                 cEqualRuns++;
    1712         } while (cEqualRuns < 3 && --iParanoia > 0);
    1713 
    1714         /*
    1715          * Ok, if we ever get here, it's most likely a genuine deadlock.
    1716          */
    1717         rtThreadDeadlock(pThread, pCur, enmState, pValidatorRec, uId, RT_SRC_POS_ARGS);
    1718     }
    1719 }
    1720 RT_EXPORT_SYMBOL(RTThreadBlocking);
    1721 
    1722 
    1723 /**
    1724  * Unblocks a thread.
    1725  *
    1726  * This function is paired with rtThreadBlocking.
    1727  *
    1728  * @param   hThread     The current thread.
    1729  * @param   enmCurState The current state, used to check for nested blocking.
    1730  *                      The new state will be running.
    1731  */
    1732 RTDECL(void) RTThreadUnblocked(RTTHREAD hThread, RTTHREADSTATE enmCurState)
    1733 {
    1734     if (hThread && rtThreadGetState(hThread) == enmCurState)
    1735         rtThreadSetState(hThread, RTTHREADSTATE_RUNNING);
    1736 }
    1737 RT_EXPORT_SYMBOL(RTThreadUnblocked);
     1481RT_EXPORT_SYMBOL(RTThreadStateName);
    17381482
    17391483#endif /* IN_RING3 */
    1740 
    1741 
    17421484#ifdef IPRT_WITH_GENERIC_TLS
    17431485
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