VirtualBox

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


Ignore:
Timestamp:
Dec 14, 2009 4:31:40 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
55985
Message:

RTCritSect,PDMCritSect,iprt/lockvalidator.h: Reworked the deadlocking detection for critical sections and preparing for lock order validation. This change generalizes the RTCRITSECT::Strict data and moves it out of the RTCRITSECT, leaving a pointer behind. This saves a bit of space in release builds.

Location:
trunk/src/VBox/Runtime/common/misc
Files:
1 added
1 edited

Legend:

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

    r25000 r25368  
    4141#include <iprt/alloc.h>
    4242#include <iprt/assert.h>
     43#include <iprt/lockvalidator.h>
    4344#include <iprt/semaphore.h>
    4445#ifdef IN_RING0
     
    4849#include <iprt/err.h>
    4950#include <iprt/string.h>
     51#include "internal/magics.h"
    5052#include "internal/thread.h"
    5153#include "internal/sched.h"
     
    195197
    196198
     199/**
     200 * Gets the thread state.
     201 *
     202 * @returns The thread state.
     203 * @param   pThread             The thread.
     204 */
     205DECLINLINE(RTTHREADSTATE) rtThreadGetState(PRTTHREADINT pThread)
     206{
     207    return pThread->enmState;
     208}
     209
     210
     211/**
     212 * Sets the thread state.
     213 *
     214 * @param   pThread             The thread.
     215 * @param   enmNewState         The new thread state.
     216 */
     217DECLINLINE(void) rtThreadSetState(PRTTHREADINT pThread, RTTHREADSTATE enmNewState)
     218{
     219    AssertCompile(sizeof(pThread->enmState) == sizeof(uint32_t));
     220    ASMAtomicWriteU32((uint32_t volatile *)&pThread->enmState, enmNewState);
     221}
    197222
    198223#ifdef IN_RING3
     
    255280        {
    256281            rtThreadInsert(pThread, NativeThread);
    257             ASMAtomicWriteSize(&pThread->enmState, RTTHREADSTATE_RUNNING);
     282            rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
    258283            rtThreadRelease(pThread);
    259284        }
     
    376401     * it should not be reinserted at this point.
    377402     */
    378     if (pThread->enmState != RTTHREADSTATE_TERMINATED)
     403    if (rtThreadGetState(pThread) != RTTHREADSTATE_TERMINATED)
    379404    {
    380405        /*
     
    588613     */
    589614    pThread->rc = rc;
    590     ASMAtomicWriteSize(&pThread->enmState, RTTHREADSTATE_TERMINATED);
     615    rtThreadSetState(pThread, RTTHREADSTATE_TERMINATED);
    591616    ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAGS_TERMINATED);
    592617    if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
     
    634659     * Call thread function and terminate when it returns.
    635660     */
    636     ASMAtomicWriteSize(&pThread->enmState, RTTHREADSTATE_RUNNING);
     661    rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
    637662    rc = pThread->pfnThread(pThread, pThread->pvUser);
    638663
     
    13801405
    13811406/**
     1407 * Translate a thread state into a string.
     1408 *
     1409 * @returns Pointer to a read-only string containing the state name.
     1410 * @param   enmState            The state.
     1411 */
     1412static const char *rtThreadStateName(RTTHREADSTATE enmState)
     1413{
     1414    switch (enmState)
     1415    {
     1416        case RTTHREADSTATE_INVALID:         return "INVALID";
     1417        case RTTHREADSTATE_INITIALIZING:    return "INITIALIZING";
     1418        case RTTHREADSTATE_TERMINATED:      return "TERMINATED";
     1419        case RTTHREADSTATE_RUNNING:         return "RUNNING";
     1420        case RTTHREADSTATE_CRITSECT:        return "CRITSECT";
     1421        case RTTHREADSTATE_EVENT:           return "EVENT";
     1422        case RTTHREADSTATE_EVENT_MULTI:     return "EVENT_MULTI";
     1423        case RTTHREADSTATE_FAST_MUTEX:      return "FAST_MUTEX";
     1424        case RTTHREADSTATE_MUTEX:           return "MUTEX";
     1425        case RTTHREADSTATE_RW_READ:         return "RW_READ";
     1426        case RTTHREADSTATE_RW_WRITE:        return "RW_WRITE";
     1427        case RTTHREADSTATE_SLEEP:           return "SLEEP";
     1428        case RTTHREADSTATE_SPIN_MUTEX:      return "SPIN_MUTEX";
     1429        default:                            return "UnknownThreadState";
     1430    }
     1431}
     1432
     1433
     1434/**
    13821435 * Bitch about a deadlock.
    13831436 *
    1384  * @param   pThread     This thread.
    1385  * @param   pCur        The thread we're deadlocking with.
    1386  * @param   enmState    The sleep state.
    1387  * @param   u64Block    The block data. A pointer or handle.
    1388  * @param   pszFile     Where we are gonna block.
    1389  * @param   uLine       Where we are gonna block.
    1390  * @param   uId         Where we are gonna block.
    1391  */
    1392 static void rtThreadDeadlock(PRTTHREADINT pThread, PRTTHREADINT pCur, RTTHREADSTATE enmState, uint64_t u64Block,
    1393                              const char *pszFile, unsigned uLine, RTUINTPTR uId)
    1394 {
    1395     AssertMsg1(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", uLine, pszFile, "");
     1437 * @param   pThread         This thread.
     1438 * @param   pCur            The thread we're deadlocking with.
     1439 * @param   enmState        The sleep state.
     1440 * @param   pRec            The lock validator record we're going to block on.
     1441 * @param   RT_SRC_POS_DECL Where we are going to deadlock.
     1442 * @param   uId             Where we are going to deadlock.
     1443 */
     1444static void rtThreadDeadlock(PRTTHREADINT pThread, PRTTHREADINT pCur, RTTHREADSTATE enmState,
     1445                             PRTLOCKVALIDATORREC pRec, RTHCUINTPTR uId, RT_SRC_POS_DECL)
     1446{
     1447    AssertMsg1(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", iLine, pszFile, pszFunction);
    13961448
    13971449    /*
     
    14061458         * Print info on pCur. Determin next while doing so.
    14071459         */
    1408         AssertMsg2(" #%d: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n",
     1460        AssertMsg2(" #%u: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n",
    14091461                   iEntry, pCur, pCur->Core.Key, pCur->szName,
    1410                    pCur->pszBlockFile, pCur->uBlockLine, pCur->uBlockId);
    1411         PRTTHREADINT pNext = NULL;
    1412         switch (pCur->enmState)
     1462                   pCur->pszBlockFile, pCur->uBlockLine, pCur->pszBlockFunction, pCur->uBlockId);
     1463        PRTTHREADINT  pNext       = NULL;
     1464        RTTHREADSTATE enmCurState = rtThreadGetState(pCur);
     1465        switch (enmCurState)
    14131466        {
    14141467            case RTTHREADSTATE_CRITSECT:
     1468            case RTTHREADSTATE_EVENT:
     1469            case RTTHREADSTATE_EVENT_MULTI:
     1470            case RTTHREADSTATE_FAST_MUTEX:
     1471            case RTTHREADSTATE_MUTEX:
     1472            case RTTHREADSTATE_RW_READ:
     1473            case RTTHREADSTATE_RW_WRITE:
     1474            case RTTHREADSTATE_SPIN_MUTEX:
    14151475            {
    1416                 PRTCRITSECT pCritSect = pCur->Block.pCritSect;
    1417                 if (pCur->enmState != RTTHREADSTATE_CRITSECT)
     1476                PRTLOCKVALIDATORREC pCurRec      = pCur->Block.pRec;
     1477                RTTHREADSTATE       enmCurState2 = rtThreadGetState(pCur);
     1478                if (enmCurState2 != enmCurState)
    14181479                {
    1419                     AssertMsg2("Impossible!!!\n");
     1480                    AssertMsg2(" Impossible!!! enmState=%s -> %s (%d)\n",
     1481                               rtThreadStateName(enmCurState), rtThreadStateName(enmCurState2), enmCurState2);
    14201482                    break;
    14211483                }
    1422                 if (VALID_PTR(pCritSect) && RTCritSectIsInitialized(pCritSect))
     1484                if (   VALID_PTR(pCurRec)
     1485                    && pCurRec->u32Magic == RTLOCKVALIDATORREC_MAGIC)
    14231486                {
    1424                     AssertMsg2("     Waiting on CRITSECT %p: Entered %s(%u) %RTptr\n",
    1425                                pCritSect, pCritSect->Strict.pszEnterFile,
    1426                                pCritSect->Strict.u32EnterLine, pCritSect->Strict.uEnterId);
    1427                     pNext = pCritSect->Strict.ThreadOwner;
     1487                    AssertMsg2("     Waiting on %s %p [%s]: Entered %s(%u) %s %p\n",
     1488                               rtThreadStateName(enmCurState), pCurRec->hLock, pCurRec->pszName,
     1489                               pCurRec->pszFile, pCurRec->uLine, pCurRec->pszFunction, pCurRec->uId);
     1490                    pNext = pCurRec->hThread;
    14281491                }
     1492                else if (VALID_PTR(pCurRec))
     1493                    AssertMsg2("     Waiting on %s pCurRec=%p: invalid magic number: %#x\n",
     1494                               rtThreadStateName(enmCurState), pCurRec, pCurRec->u32Magic);
    14291495                else
    1430                     AssertMsg2("     Waiting on CRITSECT %p: invalid pointer or uninitialized critsect\n", pCritSect);
     1496                    AssertMsg2("     Waiting on %s pCurRec=%p: invalid pointer\n",
     1497                               rtThreadStateName(enmCurState), pCurRec);
    14311498                break;
    14321499            }
    14331500
    14341501            default:
    1435                 AssertMsg2(" Impossible!!! enmState=%d\n", pCur->enmState);
     1502                AssertMsg2(" Impossible!!! enmState=%s (%d)\n", rtThreadStateName(enmCurState), enmCurState);
    14361503                break;
    14371504        }
     
    14661533 * This is a RT_STRICT method for debugging locks and detecting deadlocks.
    14671534 *
    1468  * @param   hThread     The current thread.
    1469  * @param   enmState    The sleep state.
    1470  * @param   u64Block    The block data. A pointer or handle.
    1471  * @param   pszFile     Where we are blocking.
    1472  * @param   uLine      Where we are blocking.
    1473  * @param   uId         Where we are blocking.
    1474  */
    1475 RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState, uint64_t u64Block,
    1476                               const char *pszFile, unsigned uLine, RTUINTPTR uId)
     1535 * @param   hThread         The current thread.
     1536 * @param   enmState        The sleep state.
     1537 * @param   pvBlock         Pointer to a RTLOCKVALIDATORREC structure.
     1538 * @param   uId             Where we are blocking.
     1539 * @param   RT_SRC_POS_DECL Where we are blocking.
     1540 */
     1541RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState,
     1542                              PRTLOCKVALIDATORREC pValidatorRec, RTHCUINTPTR uId, RT_SRC_POS_DECL)
     1543
    14771544{
    14781545    PRTTHREADINT pThread = hThread;
    14791546    Assert(RTTHREAD_IS_SLEEPING(enmState));
    1480     if (pThread && pThread->enmState == RTTHREADSTATE_RUNNING)
     1547    if (pThread && rtThreadGetState(pThread) == RTTHREADSTATE_RUNNING)
    14811548    {
    14821549        /** @todo This has to be serialized! The deadlock detection isn't 100% safe!!! */
    1483         pThread->Block.u64      = u64Block;
    1484         pThread->pszBlockFile   = pszFile;
    1485         pThread->uBlockLine     = uLine;
    1486         pThread->uBlockId       = uId;
    1487         ASMAtomicWriteSize(&pThread->enmState, enmState);
     1550        pThread->Block.pRec         = pValidatorRec;
     1551        pThread->pszBlockFunction   = pszFunction;
     1552        pThread->pszBlockFile       = pszFile;
     1553        pThread->uBlockLine         = iLine;
     1554        pThread->uBlockId           = uId;
     1555        rtThreadSetState(pThread, enmState);
    14881556
    14891557        /*
     
    14971565        PRTTHREADINT    pCur;
    14981566        unsigned        cPrevLength = ~0U;
    1499         unsigned        cEqualRuns = 0;
    1500         unsigned        iParanoia = 256;
     1567        unsigned        cEqualRuns  = 0;
     1568        unsigned        iParanoia   = 256;
    15011569        do
    15021570        {
     
    15081576                 * Get the next thread.
    15091577                 */
     1578                PRTTHREADINT pNext = NULL;
    15101579                for (;;)
    15111580                {
    1512                     switch (pCur->enmState)
     1581                    RTTHREADSTATE enmCurState = rtThreadGetState(pCur);
     1582                    switch (enmCurState)
    15131583                    {
    15141584                        case RTTHREADSTATE_CRITSECT:
     1585                        case RTTHREADSTATE_EVENT:
     1586                        case RTTHREADSTATE_EVENT_MULTI:
     1587                        case RTTHREADSTATE_FAST_MUTEX:
     1588                        case RTTHREADSTATE_MUTEX:
     1589                        case RTTHREADSTATE_RW_READ:
     1590                        case RTTHREADSTATE_RW_WRITE:
     1591                        case RTTHREADSTATE_SPIN_MUTEX:
    15151592                        {
    1516                             PRTCRITSECT pCritSect = pCur->Block.pCritSect;
    1517                             if (pCur->enmState != RTTHREADSTATE_CRITSECT)
     1593                            PRTLOCKVALIDATORREC pRec = pCur->Block.pRec;
     1594                            if (    rtThreadGetState(pCur) != enmCurState
     1595                                ||  !VALID_PTR(pRec)
     1596                                ||  pRec->u32Magic != RTLOCKVALIDATORREC_MAGIC)
    15181597                                continue;
    1519                             pCur = pCritSect->Strict.ThreadOwner;
     1598                            pNext = pRec->hThread;
     1599                            if (    rtThreadGetState(pCur) != enmCurState
     1600                                ||  pRec->u32Magic != RTLOCKVALIDATORREC_MAGIC
     1601                                ||  pRec->hThread != pNext)
     1602                                continue;
    15201603                            break;
    15211604                        }
    15221605
    15231606                        default:
    1524                             pCur = NULL;
     1607                            pNext = NULL;
    15251608                            break;
    15261609                    }
    15271610                    break;
    15281611                }
     1612
     1613                /*
     1614                 * If we arrive at the end of the list we're good.
     1615                 */
     1616                pCur = pNext;
    15291617                if (!pCur)
    15301618                    return;
    15311619
    15321620                /*
    1533                  * If we've got back to the blocking thread id we've got a deadlock.
    1534                  * If we've got a chain of more than 256 items, there is some kind of cycle
    1535                  * in the list, which means that there is already a deadlock somewhere.
     1621                 * If we've got back to the blocking thread id we've
     1622                 * got a deadlock.
    15361623                 */
    1537                 if (pCur == pThread || cLength >= 256)
     1624                if (pCur == pThread)
    15381625                    break;
     1626
     1627                /*
     1628                 * If we've got a chain of more than 256 items, there is some
     1629                 * kind of cycle in the list, which means that there is already
     1630                 * a deadlock somewhere.
     1631                 */
     1632                if (cLength >= 256)
     1633                    break;
     1634
    15391635                cLength++;
    15401636            }
     
    15531649         * Ok, if we ever get here, it's most likely a genuine deadlock.
    15541650         */
    1555         rtThreadDeadlock(pThread, pCur, enmState, u64Block, pszFile, uLine, uId);
     1651        rtThreadDeadlock(pThread, pCur, enmState, pValidatorRec, uId, RT_SRC_POS_ARGS);
    15561652    }
    15571653}
     
    15701666RTDECL(void) RTThreadUnblocked(RTTHREAD hThread, RTTHREADSTATE enmCurState)
    15711667{
    1572     if (hThread && hThread->enmState == enmCurState)
    1573         ASMAtomicWriteSize(&hThread->enmState, RTTHREADSTATE_RUNNING);
     1668    if (hThread && rtThreadGetState(hThread) == enmCurState)
     1669        rtThreadSetState(hThread, RTTHREADSTATE_RUNNING);
    15741670}
    15751671RT_EXPORT_SYMBOL(RTThreadUnblocked);
Note: See TracChangeset for help on using the changeset viewer.

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