VirtualBox

Changeset 25508 in vbox for trunk


Ignore:
Timestamp:
Dec 18, 2009 9:42:04 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
56181
Message:

iprt/lockvalidator: read/write lock accounting.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/err.h

    r25467 r25508  
    853853/** The lock validator detected a deadlock. */
    854854#define VERR_SEM_LV_DEADLOCK                (-372)
     855/** Not the lock owner according our records. */
     856#define VERR_SEM_LV_NOT_OWNER               (-373)
     857/** An illegal lock upgrade was attempted. */
     858#define VERR_SEM_LV_UPGRADE                 (-374)
    855859/** @} */
    856860
  • trunk/include/iprt/lockvalidator.h

    r25498 r25508  
    128128
    129129/** Pointer to a record of one ownership share.  */
    130 typedef struct RTLOCKVALIDATORSHAREDREC *PRTLOCKVALIDATORSHAREDREC;
     130typedef struct RTLOCKVALIDATORSHARED *PRTLOCKVALIDATORSHARED;
    131131/**
    132132 * For recording the one ownership share.
     
    135135{
    136136    /** Magic value (RTLOCKVALIDATORSHAREDONE_MAGIC). */
    137     uint32_t                                u32Magic;
     137    uint32_t                            u32Magic;
    138138    /** Recursion count */
    139     uint32_t                                cRecursion;
     139    uint32_t                            cRecursion;
    140140    /** The current owner thread. */
    141     RTTHREAD volatile                       hThread;
     141    RTTHREAD volatile                   hThread;
    142142    /** Pointer to the lock record below us. Only accessed by the owner. */
    143     R3R0PTRTYPE(PRTLOCKVALIDATORREC)        pDown;
     143    R3R0PTRTYPE(PRTLOCKVALIDATORREC)    pDown;
    144144    /** Pointer back to the shared record. */
    145     R3R0PTRTYPE(PRTLOCKVALIDATORSHAREDREC) pSharedRec;
     145    R3R0PTRTYPE(PRTLOCKVALIDATORSHARED) pSharedRec;
    146146#if HC_ARCH_BITS == 32
    147147    /** Reserved. */
    148     RTHCPTR                                 pvReserved;
     148    RTHCPTR                             pvReserved;
    149149#endif
    150150    /** Source position where the lock was taken. */
    151     RTLOCKVALIDATORSRCPOS                   SrcPos;
     151    RTLOCKVALIDATORSRCPOS               SrcPos;
    152152} RTLOCKVALIDATORSHAREDONE;
    153153AssertCompileSize(RTLOCKVALIDATORSHAREDONE, HC_ARCH_BITS == 32 ? 24 + 16 : 32 + 32);
     
    194194} RTLOCKVALIDATORSHARED;
    195195AssertCompileSize(RTLOCKVALIDATORSHARED, HC_ARCH_BITS == 32 ? 20 + 20 + 8 : 32 + 32);
    196 /** Pointer to a RTLOCKVALIDATORSHARED. */
    197 typedef RTLOCKVALIDATORSHARED *PRTLOCKVALIDATORSHARED;
    198196
    199197
  • trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp

    r25498 r25508  
    263263
    264264
     265/**
     266 * Locates a thread in a shared lock record.
     267 *
     268 * @returns Pointer to the thread record on success, NULL on failure..
     269 * @param   pShared             The shared lock record.
     270 * @param   hThread             The thread to find.
     271 * @param   piEntry             Where to optionally return the table in index.
     272 */
     273DECLINLINE(PRTLOCKVALIDATORSHAREDONE)
     274rtLockValidatorSharedRecFindThread(PRTLOCKVALIDATORSHARED pShared, RTTHREAD hThread, uint32_t *piEntry)
     275{
     276    rtLockValidatorSerializeDetectionEnter();
     277    if (pShared->papOwners)
     278    {
     279        PRTLOCKVALIDATORSHAREDONE volatile *papOwners = pShared->papOwners;
     280        uint32_t const                      cMax      = pShared->cAllocated;
     281        for (uint32_t iEntry = 0; iEntry < cMax; iEntry++)
     282        {
     283            PRTLOCKVALIDATORSHAREDONE pEntry;
     284            pEntry = (PRTLOCKVALIDATORSHAREDONE)ASMAtomicUoReadPtr((void * volatile *)&papOwners[iEntry]);
     285            if (pEntry && pEntry->hThread == hThread)
     286            {
     287                rtLockValidatorSerializeDetectionLeave();
     288                if (piEntry)
     289                    *piEntry = iEntry;
     290                return pEntry;
     291            }
     292        }
     293    }
     294    rtLockValidatorSerializeDetectionLeave();
     295    return NULL;
     296}
     297
     298
     299/**
     300 * Allocates and initializes a thread entry for the shared lock record.
     301 *
     302 * @returns The new thread entry.
     303 * @param   pShared             The shared lock record.
     304 * @param   hThread             The thread handle.
     305 * @param   pSrcPos             The source position.
     306 */
     307DECLINLINE(PRTLOCKVALIDATORSHAREDONE)
     308rtLockValidatorSharedRecAllocThread(PRTLOCKVALIDATORSHARED pRead, RTTHREAD hThread, PCRTLOCKVALIDATORSRCPOS pSrcPos)
     309{
     310    PRTLOCKVALIDATORSHAREDONE pEntry;
     311
     312    pEntry = (PRTLOCKVALIDATORSHAREDONE)RTMemAlloc(sizeof(RTLOCKVALIDATORSHAREDONE));
     313    if (pEntry)
     314    {
     315        pEntry->u32Magic        = RTLOCKVALIDATORSHAREDONE_MAGIC;
     316        pEntry->cRecursion      = 1;
     317        pEntry->hThread         = hThread;
     318        pEntry->pDown           = NULL;
     319        pEntry->pSharedRec      = pRead;
     320#if HC_ARCH_BITS == 32
     321        pEntry->pvReserved      = NULL;
     322#endif
     323        if (pSrcPos)
     324            pEntry->SrcPos      = *pSrcPos;
     325        else
     326            rtLockValidatorInitSrcPos(&pEntry->SrcPos);
     327    }
     328
     329    return pEntry;
     330}
     331
     332/**
     333 * Frees a thread entry allocated by rtLockValidatorSharedRecAllocThread.
     334 *
     335 * @param   pEntry              The thread entry.
     336 */
     337DECLINLINE(void) rtLockValidatorSharedRecFreeThread(PRTLOCKVALIDATORSHAREDONE pEntry)
     338{
     339    if (pEntry)
     340    {
     341        rtLockValidatorSerializeDestructEnter();
     342        ASMAtomicWriteU32(&pEntry->u32Magic, RTLOCKVALIDATORSHAREDONE_MAGIC_DEAD);
     343        ASMAtomicWriteHandle(&pEntry->hThread, NIL_RTTHREAD);
     344        rtLockValidatorSerializeDestructLeave();
     345
     346        RTMemFree(pEntry);
     347    }
     348}
     349
     350
     351/**
     352 * Make more room in the table.
     353 *
     354 * @retval  true on success
     355 * @retval  false if we're out of memory or running into a bad race condition
     356 *          (probably a bug somewhere).  No longer holding the lock.
     357 *
     358 * @param   pShared             The shared lock record.
     359 */
     360static bool rtLockValidatorSharedRecMakeRoom(PRTLOCKVALIDATORSHARED pShared)
     361{
     362    for (unsigned i = 0; i < 1000; i++)
     363    {
     364        /*
     365         * Switch to the other data access direction.
     366         */
     367        rtLockValidatorSerializeDetectionLeave();
     368        if (i >= 10)
     369        {
     370            Assert(i != 10 && i != 100);
     371            RTThreadSleep(i >= 100);
     372        }
     373        rtLockValidatorSerializeDestructEnter();
     374
     375        /*
     376         * Try grab the privilege to reallocating the table.
     377         */
     378        if (    pShared->u32Magic == RTLOCKVALIDATORSHARED_MAGIC
     379            &&  ASMAtomicCmpXchgBool(&pShared->fReallocating, true, false))
     380        {
     381            uint32_t cAllocated = pShared->cAllocated;
     382            if (cAllocated < pShared->cEntries)
     383            {
     384                /*
     385                 * Ok, still not enough space.  Reallocate the table.
     386                 */
     387#if 0  /** @todo enable this after making sure growing works flawlessly. */
     388                uint32_t                    cInc = RT_ALIGN_32(pShared->cEntries - cAllocated, 16);
     389#else
     390                uint32_t                    cInc = RT_ALIGN_32(pShared->cEntries - cAllocated, 1);
     391#endif
     392                PRTLOCKVALIDATORSHAREDONE  *papOwners;
     393                papOwners = (PRTLOCKVALIDATORSHAREDONE *)RTMemRealloc((void *)pShared->papOwners,
     394                                                                      (cAllocated + cInc) * sizeof(void *));
     395                if (!papOwners)
     396                {
     397                    ASMAtomicWriteBool(&pShared->fReallocating, false);
     398                    rtLockValidatorSerializeDestructLeave();
     399                    /* RTMemRealloc will assert */
     400                    return false;
     401                }
     402
     403                while (cInc-- > 0)
     404                {
     405                    papOwners[cAllocated] = NULL;
     406                    cAllocated++;
     407                }
     408
     409                ASMAtomicWritePtr((void * volatile *)&pShared->papOwners, papOwners);
     410                ASMAtomicWriteU32(&pShared->cAllocated, cAllocated);
     411            }
     412            ASMAtomicWriteBool(&pShared->fReallocating, false);
     413        }
     414        rtLockValidatorSerializeDestructLeave();
     415
     416        rtLockValidatorSerializeDetectionEnter();
     417        if (RT_UNLIKELY(pShared->u32Magic != RTLOCKVALIDATORSHARED_MAGIC))
     418            break;
     419
     420        if (pShared->cAllocated >= pShared->cEntries)
     421            return true;
     422    }
     423
     424    rtLockValidatorSerializeDetectionLeave();
     425    AssertFailed(); /* too many iterations or destroyed while racing. */
     426    return false;
     427}
     428
     429
     430/**
     431 * Adds a thread entry to a shared lock record.
     432 *
     433 * @returns true on success, false on serious race or we're if out of memory.
     434 * @param   pShared             The shared lock record.
     435 * @param   pEntry              The thread entry.
     436 */
     437DECLINLINE(bool) rtLockValidatorSharedRecAddThread(PRTLOCKVALIDATORSHARED pShared, PRTLOCKVALIDATORSHAREDONE pEntry)
     438{
     439    rtLockValidatorSerializeDetectionEnter();
     440    if (RT_LIKELY(pShared->u32Magic == RTLOCKVALIDATORSHARED_MAGIC)) /* paranoia */
     441    {
     442        if (   ASMAtomicIncU32(&pShared->cEntries) > pShared->cAllocated /** @todo add fudge */
     443            && !rtLockValidatorSharedRecMakeRoom(pShared))
     444            return false; /* the worker leave the lock */
     445
     446        PRTLOCKVALIDATORSHAREDONE volatile *papOwners = pShared->papOwners;
     447        uint32_t const                      cMax      = pShared->cAllocated;
     448        for (unsigned i = 0; i < 100; i++)
     449        {
     450            for (uint32_t iEntry = 0; iEntry < cMax; iEntry++)
     451            {
     452                if (ASMAtomicCmpXchgPtr((void * volatile *)&papOwners[iEntry], pEntry, NULL))
     453                {
     454                    rtLockValidatorSerializeDetectionLeave();
     455                    return true;
     456                }
     457            }
     458            Assert(i != 25);
     459        }
     460        AssertFailed();
     461    }
     462    rtLockValidatorSerializeDetectionLeave();
     463    return false;
     464}
     465
     466
     467/**
     468 * Remove a thread entry from a shared lock record.
     469 *
     470 * @param   pShared             The shared lock record.
     471 * @param   pEntry              The thread entry to remove.
     472 * @param   iEntry              The last known index.
     473 */
     474DECLINLINE(void) rtLockValidatorSharedRecDelete(PRTLOCKVALIDATORSHARED pShared, PRTLOCKVALIDATORSHAREDONE pEntry,
     475                                                uint32_t iEntry)
     476{
     477    rtLockValidatorSerializeDetectionEnter();
     478    if (RT_LIKELY(pShared->u32Magic == RTLOCKVALIDATORSHARED_MAGIC))
     479    {
     480        if (   iEntry >= pShared->cAllocated
     481            || !ASMAtomicCmpXchgPtr((void * volatile *)&pShared->papOwners[iEntry], NULL, pEntry))
     482        {
     483            /* this shouldn't happen yet... */
     484            AssertFailed();
     485            PRTLOCKVALIDATORSHAREDONE volatile *papOwners = pShared->papOwners;
     486            uint32_t const                      cMax      = pShared->cAllocated;
     487            for (iEntry = 0; iEntry < cMax; iEntry++)
     488                if (ASMAtomicCmpXchgPtr((void * volatile *)&papOwners[iEntry], NULL, pEntry))
     489                   break;
     490            AssertReturnVoidStmt(iEntry < cMax, rtLockValidatorSerializeDetectionLeave());
     491        }
     492        uint32_t cNow = ASMAtomicDecU32(&pShared->cEntries);
     493        Assert(!(cNow & RT_BIT_32(31))); NOREF(cNow);
     494    }
     495    rtLockValidatorSerializeDetectionLeave();
     496}
     497
     498
    265499RTDECL(int) RTLockValidatorCheckOrder(PRTLOCKVALIDATORREC pRec, RTTHREAD hThread, PCRTLOCKVALIDATORSRCPOS pSrcPos)
    266500{
     
    294528    AssertReturn(pRead->u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
    295529    AssertReturn(hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
     530
     531    /*
     532     * Locate the entry for this thread in the table.
     533     */
     534    uint32_t                    iEntry = 0;
     535    PRTLOCKVALIDATORSHAREDONE   pEntry = rtLockValidatorSharedRecFindThread(pRead, hThread, &iEntry);
     536    AssertReturn(pEntry, VERR_SEM_LV_NOT_OWNER);
     537
     538    /*
     539     * Check the release order.
     540     */
     541    if (pRead->hClass != NIL_RTLOCKVALIDATORCLASS)
     542    {
     543        /** @todo order validation */
     544    }
     545
     546    /*
     547     * Release the ownership or unwind a level of recursion.
     548     */
     549    Assert(pEntry->cRecursion > 0);
     550    if (pEntry->cRecursion > 1)
     551        pEntry->cRecursion--;
     552    else
     553        rtLockValidatorSharedRecDelete(pRead, pEntry, iEntry);
    296554
    297555    return VINF_SUCCESS;
     
    414672    AssertReturnVoid(pRead->u32Magic == RTLOCKVALIDATORSHARED_MAGIC);
    415673    AssertReturnVoid(hThread != NIL_RTTHREAD);
     674
     675    /*
     676     * Recursive?
     677     *
     678     * Note! This code can be optimized to try avoid scanning the table on
     679     *       insert. However, that's annoying work that makes the code big,
     680     *       so it can wait til later sometime.
     681     */
     682    PRTLOCKVALIDATORSHAREDONE pEntry = rtLockValidatorSharedRecFindThread(pRead, hThread, NULL);
     683    if (pEntry)
     684    {
     685        pEntry->cRecursion++;
     686        return;
     687    }
     688
     689    /*
     690     * Allocate a new thread entry and insert it into the table.
     691     */
     692    pEntry = rtLockValidatorSharedRecAllocThread(pRead, hThread, pSrcPos);
     693    if (    pEntry
     694        &&  !rtLockValidatorSharedRecAddThread(pRead, pEntry))
     695        rtLockValidatorSharedRecFreeThread(pEntry);
    416696}
    417697
     
    421701    AssertReturnVoid(pRead->u32Magic == RTLOCKVALIDATORSHARED_MAGIC);
    422702    AssertReturnVoid(hThread != NIL_RTTHREAD);
     703    AssertMsgFailed(("Not implemented"));
    423704}
    424705
     
    612893                 , VERR_SEM_LV_INVALID_PARAMETER);
    613894
     895    /*
     896     * Check for attempts at doing a read upgrade.
     897     */
     898    PRTLOCKVALIDATORSHAREDONE pEntry = rtLockValidatorSharedRecFindThread(pRead, hThread, NULL);
     899    if (pEntry)
     900    {
     901        AssertMsgFailed(("Read lock upgrade at %s(%d) %s %p!\nRead lock take at %s(%d) %s %p!\n",
     902                         pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId,
     903                         pEntry->SrcPos.pszFile, pEntry->SrcPos.uLine, pEntry->SrcPos.pszFunction, pEntry->SrcPos.uId));
     904        return VERR_SEM_LV_UPGRADE;
     905    }
     906
     907
     908
    614909    return VINF_SUCCESS;
    615910}
     
    636931                 || enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */
    637932                 , VERR_SEM_LV_INVALID_PARAMETER);
     933    Assert(pWrite->hThread != pThread);
     934
    638935
    639936    return VINF_SUCCESS;
  • trunk/src/VBox/Runtime/testcase/Makefile.kmk

    r25426 r25508  
    9393        tstSemMutex \
    9494        tstSemPingPong \
     95        tstSemRW \
    9596        tstSems \
    9697        tstRTSemXRoads \
     
    125126        tstRTBitOperationsPIC3 \
    126127        tstInlineAsmPIC \
    127         tstInlineAsmPIC3 \
    128         tstSemRW
     128        tstInlineAsmPIC3
    129129PROGRAMS.l4 += \
    130130        tstIoCtl
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