VirtualBox

Changeset 25617 in vbox


Ignore:
Timestamp:
Jan 2, 2010 12:14:47 AM (15 years ago)
Author:
vboxsync
Message:

iprt: Added lock validator testcase for read-write semaphore deadlocks. Fixed bugs found with it.

Location:
trunk
Files:
3 edited

Legend:

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

    r25614 r25617  
    637637RTDECL(void) RTLockValidatorReadLockDec(RTTHREAD Thread);
    638638
     639/**
     640 * Query which lock the specified thread is waiting on.
     641 *
     642 * @returns The lock handle value or NULL.
     643 * @param   hThread     The thread in question.
     644 */
     645RTDECL(void *) RTLockValidatorQueryBlocking(RTTHREAD hThread);
     646
    639647
    640648
  • trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp

    r25614 r25617  
    8686/** Pointer to a deadlock detction stack. */
    8787typedef RTLOCKVALDDSTACK *PRTLOCKVALDDSTACK;
     88
     89
     90/*******************************************************************************
     91*   Defined Constants And Macros                                               *
     92*******************************************************************************/
     93/** Macro that asserts that a pointer is aligned correctly.
     94 * Only used when fighting bugs. */
     95#if 1
     96# define RTLOCKVAL_ASSERT_PTR_ALIGN(p)   \
     97    AssertMsg(!((uintptr_t)(p) & (sizeof(uintptr_t) - 1)), ("%p\n", (p)));
     98#else
     99# define RTLOCKVAL_ASSERT_PTR_ALIGN(p)   do { } while (0)
     100#endif
    88101
    89102
     
    121134DECL_FORCE_INLINE(PRTLOCKVALRECUNION) rtLockValidatorReadRecUnionPtr(PRTLOCKVALRECUNION volatile *ppRec)
    122135{
    123     return (PRTLOCKVALRECUNION)ASMAtomicReadPtr((void * volatile *)ppRec);
     136    PRTLOCKVALRECUNION p = (PRTLOCKVALRECUNION)ASMAtomicReadPtr((void * volatile *)ppRec);
     137    RTLOCKVAL_ASSERT_PTR_ALIGN(p);
     138    return p;
    124139}
    125140
     
    128143DECL_FORCE_INLINE(void) rtLockValidatorWriteRecUnionPtr(PRTLOCKVALRECUNION volatile *ppRec, PRTLOCKVALRECUNION pRecNew)
    129144{
     145    RTLOCKVAL_ASSERT_PTR_ALIGN(pRecNew);
    130146    ASMAtomicWritePtr((void * volatile *)ppRec, pRecNew);
    131147}
     
    135151DECL_FORCE_INLINE(PRTTHREADINT) rtLockValidatorReadThreadHandle(RTTHREAD volatile *phThread)
    136152{
    137     return (PRTTHREADINT)ASMAtomicReadPtr((void * volatile *)phThread);
     153    PRTTHREADINT p = (PRTTHREADINT)ASMAtomicReadPtr((void * volatile *)phThread);
     154    RTLOCKVAL_ASSERT_PTR_ALIGN(p);
     155    return p;
    138156}
    139157
     
    142160DECL_FORCE_INLINE(PRTLOCKVALRECSHRDOWN) rtLockValidatorUoReadSharedOwner(PRTLOCKVALRECSHRDOWN volatile *ppOwner)
    143161{
    144     return (PRTLOCKVALRECSHRDOWN)ASMAtomicUoReadPtr((void * volatile *)ppOwner);
     162    PRTLOCKVALRECSHRDOWN p = (PRTLOCKVALRECSHRDOWN)ASMAtomicUoReadPtr((void * volatile *)ppOwner);
     163    RTLOCKVAL_ASSERT_PTR_ALIGN(p);
     164    return p;
    145165}
    146166
     
    456476
    457477/**
    458  * Worker for rtLockValidatorDoDeadlockCheck that checks if there is more work
    459  * to be done during unwind.
    460  *
    461  * @returns true if there is more work left for this lock, false if not.
    462  * @param   pRec            The current record.
    463  * @param   iEntry          The current index.
    464  * @param   pFirstSibling   The first record we examined.
    465  */
    466 DECL_FORCE_INLINE(bool) rtLockValidatorDdMoreWorkLeft(PRTLOCKVALRECUNION pRec, uint32_t iEntry, PRTLOCKVALRECUNION pFirstSibling)
    467 {
    468     PRTLOCKVALRECUNION pSibling;
    469 
    470     switch (pRec->Core.u32Magic)
    471     {
    472         case RTLOCKVALRECEXCL_MAGIC:
    473             pSibling = pRec->Excl.pSibling;
    474             break;
    475 
    476         case RTLOCKVALRECSHRD_MAGIC:
    477             if (iEntry + 1 < pRec->Shared.cAllocated)
    478                 return true;
    479             pSibling = pRec->Excl.pSibling;
    480             break;
    481 
    482         default:
    483             return false;
    484     }
    485     return pSibling != NULL
    486         && pSibling != pFirstSibling;
    487 }
    488 
    489 
    490 /**
    491478 * Worker for rtLockValidatorDeadlockDetection that does the actual deadlock
    492479 * detection.
     
    519506         * Process the current record.
    520507         */
     508        RTLOCKVAL_ASSERT_PTR_ALIGN(pRec);
     509
    521510        /* Find the next relevant owner thread. */
    522511        PRTTHREADINT pNextThread;
     
    526515                Assert(iEntry == UINT32_MAX);
    527516                pNextThread = rtLockValidatorReadThreadHandle(&pRec->Excl.hThread);
    528                 if (    pNextThread
    529                     &&  pNextThread->u32Magic == RTTHREADINT_MAGIC
    530                     &&  !RTTHREAD_IS_SLEEPING(pNextThread->enmState)
    531                     &&  pNextThread != pThreadSelf)
    532                     pNextThread = NIL_RTTHREAD;
    533 
    534                 if (    pNextThread == NIL_RTTHREAD
    535                     &&  pRec->Excl.pSibling
    536                     &&  pRec->Excl.pSibling != pFirstSibling)
     517                if (    !pNextThread
     518                    ||  (   pNextThread != pThreadSelf
     519                         && (   pNextThread->u32Magic != RTTHREADINT_MAGIC
     520                             || !RTTHREAD_IS_SLEEPING(rtThreadGetState(pNextThread)) )
     521                        )
     522                   )
    537523                {
    538524                    pRec = pRec->Excl.pSibling;
    539                     continue;
     525                    if (    pRec
     526                        &&  pRec != pFirstSibling)
     527                        continue;
     528                    pNextThread = NIL_RTTHREAD;
    540529                }
    541530                break;
     
    580569                            {
    581570                                if (   pNextThread->u32Magic == RTTHREADINT_MAGIC
    582                                     && (   RTTHREAD_IS_SLEEPING(pNextThread->enmState)
     571                                    && (   RTTHREAD_IS_SLEEPING(rtThreadGetState(pNextThread))
    583572                                        || pNextThread == pThreadSelf))
    584573                                    break;
     
    589578                            Assert(!pEntry || pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC_DEAD);
    590579                    }
    591                     if (pNextThread == NIL_RTTHREAD)
     580                    if (pNextThread != NIL_RTTHREAD)
    592581                        break;
    593582                }
    594583
    595584                /* Advance to the next sibling, if any. */
    596                 if (   pRec->Shared.pSibling != NULL
    597                     && pRec->Shared.pSibling != pFirstSibling)
     585                pRec = pRec->Shared.pSibling;
     586                if (   pRec != NULL
     587                    && pRec != pFirstSibling)
    598588                {
    599                     pRec = pRec->Shared.pSibling;
    600589                    iEntry = UINT32_MAX;
    601590                    continue;
    602591                }
     592                Assert(pNextThread == NIL_RTTHREAD);
    603593                break;
    604594
     
    673663                    return VINF_SUCCESS;
    674664                i--;
    675 
    676                 /* examine it. */
    677                 pRec            = pStack->a[i].pRec;
    678                 pFirstSibling   = pStack->a[i].pFirstSibling;
    679                 iEntry          = pStack->a[i].iEntry;
    680                 if (rtLockValidatorDdMoreWorkLeft(pRec, iEntry, pFirstSibling))
     665                pRec    = pStack->a[i].pRec;
     666                iEntry  = pStack->a[i].iEntry;
     667
     668                /* Examine it. */
     669                uint32_t u32Magic = pRec->Core.u32Magic;
     670                if (u32Magic == RTLOCKVALRECEXCL_MAGIC)
     671                    pRec = pRec->Excl.pSibling;
     672                else if (u32Magic == RTLOCKVALRECSHRD_MAGIC)
    681673                {
    682                     enmState    = pStack->a[i].enmState;
    683                     pThread     = pStack->a[i].pThread;
    684                     pStack->c   = i;
    685                     break;
     674                    if (iEntry + 1 < pRec->Shared.cAllocated)
     675                        break;  /* continue processing this record. */
     676                    pRec = pRec->Shared.pSibling;
    686677                }
     678                else
     679                {
     680                    Assert(   u32Magic == RTLOCKVALRECEXCL_MAGIC_DEAD
     681                           || u32Magic == RTLOCKVALRECSHRD_MAGIC_DEAD);
     682                    continue;
     683                }
     684
     685                /* Any next record to advance to? */
     686                if (   !pRec
     687                    || pRec == pStack->a[i].pFirstSibling)
     688                    continue;
     689                iEntry = UINT32_MAX;
     690                break;
    687691            }
     692
     693            /* Restore the rest of the state and update the stack. */
     694            pFirstSibling   = pStack->a[i].pFirstSibling;
     695            enmState        = pStack->a[i].enmState;
     696            pThread         = pStack->a[i].pThread;
     697            pStack->c       = i;
    688698        }
    689699        /* else: see if there is another thread to check for this lock. */
     
    888898                                        uint32_t uSubClass, const char *pszName, void *hLock)
    889899{
     900    RTLOCKVAL_ASSERT_PTR_ALIGN(pRec);
     901    RTLOCKVAL_ASSERT_PTR_ALIGN(hLock);
     902
    890903    pRec->Core.u32Magic = RTLOCKVALRECEXCL_MAGIC;
    891904    pRec->fEnabled      = RTLockValidatorIsEnabled();
     
    11871200                                          uint32_t uSubClass, const char *pszName, void *hLock)
    11881201{
     1202    RTLOCKVAL_ASSERT_PTR_ALIGN(pRec);
     1203    RTLOCKVAL_ASSERT_PTR_ALIGN(hLock);
     1204
    11891205    pRec->Core.u32Magic = RTLOCKVALRECSHRD_MAGIC;
    11901206    pRec->uSubClass     = uSubClass;
     
    17701786
    17711787
     1788RTDECL(void *) RTLockValidatorQueryBlocking(RTTHREAD hThread)
     1789{
     1790    void           *pvLock  = NULL;
     1791    PRTTHREADINT    pThread = rtThreadGet(hThread);
     1792    if (pThread)
     1793    {
     1794        RTTHREADSTATE enmState = rtThreadGetState(pThread);
     1795        if (RTTHREAD_IS_SLEEPING(enmState))
     1796        {
     1797            rtLockValidatorSerializeDetectionEnter();
     1798
     1799            enmState = rtThreadGetState(pThread);
     1800            if (RTTHREAD_IS_SLEEPING(enmState))
     1801            {
     1802                PRTLOCKVALRECUNION pRec = rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pRec);
     1803                if (pRec)
     1804                {
     1805                    switch (pRec->Core.u32Magic)
     1806                    {
     1807                        case RTLOCKVALRECEXCL_MAGIC:
     1808                            pvLock = pRec->Excl.hLock;
     1809                            break;
     1810
     1811                        case RTLOCKVALRECSHRDOWN_MAGIC:
     1812                            pRec = (PRTLOCKVALRECUNION)pRec->ShrdOwner.pSharedRec;
     1813                            if (!pRec || pRec->Core.u32Magic != RTLOCKVALRECSHRD_MAGIC)
     1814                                break;
     1815                        case RTLOCKVALRECSHRD_MAGIC:
     1816                            pvLock = pRec->Shared.hLock;
     1817                            break;
     1818                    }
     1819                    if (RTThreadGetState(pThread) != enmState)
     1820                        pvLock = NULL;
     1821                }
     1822            }
     1823
     1824            rtLockValidatorSerializeDetectionLeave();
     1825        }
     1826        rtThreadRelease(pThread);
     1827    }
     1828    return pvLock;
     1829}
     1830RT_EXPORT_SYMBOL(RTLockValidatorQueryBlocking);
     1831
     1832
    17721833RTDECL(bool) RTLockValidatorSetEnabled(bool fEnabled)
    17731834{
  • trunk/src/VBox/Runtime/testcase/tstRTLockValidator.cpp

    r25614 r25617  
    4646*   Global Variables                                                           *
    4747*******************************************************************************/
     48/** The testcase handle. */
    4849static RTTEST       g_hTest;
    49 
    50 static uint32_t     g_cThreads;
    51 static RTTHREAD     g_ahThreads[32];
    52 static RTCRITSECT   g_aCritSects[32];
     50/** Flip this in the debugger to get some peace to single step wild code. */
     51bool volatile       g_fDoNotSpin = false;
     52
     53static uint32_t             g_cThreads;
     54static uint32_t volatile    g_iDeadlockThread;
     55static RTTHREAD             g_ahThreads[32];
     56static RTCRITSECT           g_aCritSects[32];
     57static RTSEMRW              g_ahSemRWs[32];
    5358
    5459
     
    6671        if (!RTCritSectIsInitialized(pCritSect))
    6772            return false;
    68         RTThreadSleep(iLoop > 256 ? 1 : 0);
     73        RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
    6974        iLoop++;
    7075    }
     
    7479
    7580/**
     81 * Spin until someone else has taken ownership (any kind) of the read-write
     82 * semaphore.
     83 *
     84 * @returns true on success, false on abort.
     85 * @param   hSemRW      The read-write semaphore.
     86 */
     87static bool testWaitForSemRWToBeOwned(RTSEMRW hSemRW)
     88{
     89    RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
     90    unsigned iLoop = 0;
     91    for (;;)
     92    {
     93        if (RTSemRWGetWriteRecursion(hSemRW) > 0)
     94            return true;
     95        if (RTSemRWGetReadCount(hSemRW) > 0)
     96            return true;
     97        RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
     98        iLoop++;
     99    }
     100    return true;
     101}
     102
     103
     104/**
    76105 * Waits for a thread to enter a sleeping state.
    77106 *
    78107 * @returns true on success, false on abort.
    79  * @param   hThread     The thread.
    80  */
    81 static bool testWaitForThreadToSleep(RTTHREAD hThread)
    82 {
     108 * @param   hThread             The thread.
     109 * @param   enmDesiredState     The desired thread sleep state.
     110 * @param   pvLock              The lock it should be sleeping on.
     111 */
     112static bool testWaitForThreadToSleep(RTTHREAD hThread, RTTHREADSTATE enmDesiredState, void *pvLock)
     113{
     114    RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
    83115    for (unsigned iLoop = 0; ; iLoop++)
    84116    {
    85117        RTTHREADSTATE enmState = RTThreadGetState(hThread);
    86118        if (RTTHREAD_IS_SLEEPING(enmState))
    87             return true;
    88         if (enmState != RTTHREADSTATE_RUNNING)
     119        {
     120            if (   enmState == enmDesiredState
     121                && (   !pvLock
     122                    || pvLock == RTLockValidatorQueryBlocking(hThread)))
     123                return true;
     124        }
     125        else if (enmState != RTTHREADSTATE_RUNNING)
    89126            return false;
    90         RTThreadSleep(iLoop > 256 ? 1 : 0);
    91     }
     127        RTThreadSleep(g_fDoNotSpin ? 3600*1000 : iLoop > 256 ? 1 : 0);
     128    }
     129}
     130
     131
     132/**
     133 * Waits for all the other threads to enter sleeping states.
     134 *
     135 * @returns VINF_SUCCESS on success, VERR_INTERNAL_ERROR on failure.
     136 * @param   enmDesiredState     The desired thread sleep state.
     137 * @param   cWaitOn             The distance to the lock they'll be waiting on,
     138 *                              the lock type is derived from the desired state.
     139 *                              UINT32_MAX means no special lock.
     140 */
     141static int testWaitForAllOtherThreadsToSleep(RTTHREADSTATE enmDesiredState, uint32_t cWaitOn)
     142{
     143    RTTHREAD hThreadSelf = RTThreadSelf();
     144    for (uint32_t i = 0; i < g_cThreads; i++)
     145    {
     146        RTTHREAD hThread = g_ahThreads[i];
     147        if (    hThread != NIL_RTTHREAD
     148            &&  hThread != hThreadSelf)
     149        {
     150            void *pvLock = NULL;
     151            if (cWaitOn != UINT32_MAX)
     152            {
     153                uint32_t j = (i + cWaitOn) % g_cThreads;
     154                switch (enmDesiredState)
     155                {
     156                    case RTTHREADSTATE_CRITSECT:    pvLock = &g_aCritSects[j]; break;
     157                    case RTTHREADSTATE_RW_WRITE:
     158                    case RTTHREADSTATE_RW_READ:     pvLock = g_ahSemRWs[j]; break;
     159                    default: break;
     160                }
     161            }
     162            bool fRet = testWaitForThreadToSleep(hThread, enmDesiredState, pvLock);
     163            if (!fRet)
     164                return VERR_INTERNAL_ERROR;
     165        }
     166    }
     167    return VINF_SUCCESS;
     168}
     169
     170
     171/**
     172 * Worker that starts the threads.
     173 *
     174 * @returns Same as RTThreadCreate.
     175 * @param   cThreads            The number of threads to start.
     176 * @param   pfnThread           Thread function.
     177 */
     178static int testStartThreads(uint32_t cThreads, PFNRTTHREAD pfnThread)
     179{
     180    uint32_t i;
     181    for (i = 0; i < RT_ELEMENTS(g_ahThreads); i++)
     182        g_ahThreads[i] = NIL_RTTHREAD;
     183
     184    for (i = 0; i < cThreads; i++)
     185        RTTEST_CHECK_RC_OK_RET(g_hTest,
     186                               RTThreadCreateF(&g_ahThreads[i], pfnThread, (void *)(uintptr_t)i, 0,
     187                                               RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "thread-%02u", i),
     188                               rcCheck);
     189    return VINF_SUCCESS;
     190}
     191
     192
     193/**
     194 * Worker that waits for the threads to complete.
     195 *
     196 * @param   cMillies            How long to wait for each.
     197 * @param   fStopOnError        Whether to stop on error and heed the thread
     198 *                              return status.
     199 */
     200static void testWaitForThreads(uint32_t cMillies, bool fStopOnError)
     201{
     202    uint32_t i = RT_ELEMENTS(g_ahThreads);
     203    while (i-- > 0)
     204        if (g_ahThreads[i] != NIL_RTTHREAD)
     205        {
     206            int rcThread;
     207            int rc2;
     208            RTTEST_CHECK_RC_OK(g_hTest, rc2 = RTThreadWait(g_ahThreads[i], cMillies, &rcThread));
     209            if (RT_SUCCESS(rc2))
     210                g_ahThreads[i] = NIL_RTTHREAD;
     211            if (fStopOnError && (RT_FAILURE(rc2) || RT_FAILURE(rcThread)))
     212                return;
     213        }
    92214}
    93215
     
    103225    {
    104226        int rc;
    105         if (i != g_cThreads - 1)
     227        if (i != g_iDeadlockThread)
    106228            RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VINF_SUCCESS);
    107229        else
    108230        {
    109             /* the last thread triggers the deadlock. */
    110             for (unsigned i = 0; i < g_cThreads - 1; i++)
    111                 RTTEST_CHECK_RET(g_hTest, testWaitForThreadToSleep(g_ahThreads[i]), VINF_SUCCESS);
    112             RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VERR_SEM_LV_DEADLOCK);
     231            RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_CRITSECT, 1));
     232            if (RT_SUCCESS(rc))
     233                RTTEST_CHECK_RC(g_hTest, rc = RTCritSectEnter(pNext), VERR_SEM_LV_DEADLOCK);
    113234        }
     235        RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
    114236        if (RT_SUCCESS(rc))
    115237            RTTEST_CHECK_RC(g_hTest, rc = RTCritSectLeave(pNext), VINF_SUCCESS);
     
    120242
    121243
    122 static void test1(uint32_t cThreads)
    123 {
    124     uint32_t i;
    125     RTTestSubF(g_hTest, "critsect deadlock with %u threads", cThreads);
     244static DECLCALLBACK(int) test2Thread(RTTHREAD ThreadSelf, void *pvUser)
     245{
     246    uintptr_t       i     = (uintptr_t)pvUser;
     247    RTSEMRW         hMine = g_ahSemRWs[i];
     248    RTSEMRW         hNext = g_ahSemRWs[(i + 1) % g_cThreads];
     249    int             rc;
     250
     251    if (i & 1)
     252        RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestWrite(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
     253    else
     254        RTTEST_CHECK_RC_RET(g_hTest, RTSemRWRequestRead(hMine, RT_INDEFINITE_WAIT), VINF_SUCCESS, rcCheck);
     255    if (testWaitForSemRWToBeOwned(hNext))
     256    {
     257        if (i != g_iDeadlockThread)
     258            RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VINF_SUCCESS);
     259        else
     260        {
     261            RTTEST_CHECK_RC_OK(g_hTest, rc = testWaitForAllOtherThreadsToSleep(RTTHREADSTATE_RW_WRITE, 1));
     262            if (RT_SUCCESS(rc))
     263            {
     264                if (g_cThreads > 1)
     265                    RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_DEADLOCK);
     266                else
     267                    RTTEST_CHECK_RC(g_hTest, rc = RTSemRWRequestWrite(hNext, RT_INDEFINITE_WAIT), VERR_SEM_LV_ILLEGAL_UPGRADE);
     268            }
     269        }
     270        RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
     271        if (RT_SUCCESS(rc))
     272            RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hNext), VINF_SUCCESS);
     273    }
     274    if (i & 1)
     275        RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hMine), VINF_SUCCESS);
     276    else
     277        RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseRead(hMine), VINF_SUCCESS);
     278    RTTEST_CHECK(g_hTest, RTThreadGetState(RTThreadSelf()) == RTTHREADSTATE_RUNNING);
     279    return VINF_SUCCESS;
     280}
     281
     282
     283static void testIt(uint32_t cThreads, uint32_t cPasses, PFNRTTHREAD pfnThread, const char *pszName)
     284{
     285    RTTestSubF(g_hTest, "%s, %u threads, %u passes", pszName, cThreads, cPasses);
     286
    126287    RTTEST_CHECK_RETV(g_hTest, RT_ELEMENTS(g_ahThreads) >= cThreads);
    127288    RTTEST_CHECK_RETV(g_hTest, RT_ELEMENTS(g_aCritSects) >= cThreads);
    128289
    129290    g_cThreads = cThreads;
    130     for (i = 0; i < cThreads; i++)
     291    g_iDeadlockThread = cThreads - 1;
     292
     293    for (uint32_t i = 0; i < cThreads; i++)
     294    {
    131295        RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectInit(&g_aCritSects[i]), VINF_SUCCESS);
    132 
    133     for (i = 0; i < cThreads && g_ahThreads[i]; i++)
    134         g_ahThreads[i] = NIL_RTTHREAD;
    135     int rc = VINF_SUCCESS;
    136     for (i = 0; i < cThreads && RT_SUCCESS(rc); i++)
    137         RTTEST_CHECK_RC_OK(g_hTest, rc = RTThreadCreateF(&g_ahThreads[i], test1Thread, (void *)(uintptr_t)i, 0,
    138                                                          RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test1-%02u", i));
    139     if (RT_SUCCESS(rc))
    140     {
    141         int rc2 = VINF_SUCCESS;
    142         i = cThreads;
    143         while (i-- > 0 && RT_SUCCESS(rc) && RT_SUCCESS(rc2))
    144         {
    145             RTTEST_CHECK_RC_OK(g_hTest, rc = RTThreadWait(g_ahThreads[i], 30*1000, &rc2));
    146             if (RT_SUCCESS(rc))
    147                 g_ahThreads[i] = NIL_RTTHREAD;
    148         }
     296        RTTEST_CHECK_RC_RETV(g_hTest, RTSemRWCreate(&g_ahSemRWs[i]), VINF_SUCCESS);
     297    }
     298
     299    uint32_t cErrors = RTTestErrorCount(g_hTest);
     300    for (uint32_t iPass = 0; iPass < cPasses && RTTestErrorCount(g_hTest) == cErrors; iPass++)
     301    {
     302#if 0 /** @todo figure why this ain't working for either of the two tests! */
     303        g_iDeadlockThread = (cThreads - 1 + iPass) % cThreads;
     304#endif
     305        int rc = testStartThreads(cThreads, pfnThread);
     306        if (RT_SUCCESS(rc))
     307            testWaitForThreads(30*1000, true);
    149308    }
    150309
    151310    for (uint32_t i = 0; i < cThreads; i++)
    152         RTTEST_CHECK_RC_RETV(g_hTest, RTCritSectDelete(&g_aCritSects[i]), VINF_SUCCESS);
    153     for (uint32_t i = 0; i < cThreads; i++)
    154         if (g_ahThreads[i] != NIL_RTTHREAD)
    155         {
    156             RTTEST_CHECK_RC_OK(g_hTest, rc = RTThreadWait(g_ahThreads[i], 10*1000, NULL));
    157             g_ahThreads[i] = NIL_RTTHREAD;
    158         }
    159 }
     311    {
     312        RTTEST_CHECK_RC(g_hTest, RTCritSectDelete(&g_aCritSects[i]), VINF_SUCCESS);
     313        RTTEST_CHECK_RC(g_hTest, RTSemRWDestroy(g_ahSemRWs[i]), VINF_SUCCESS);
     314    }
     315    testWaitForThreads(10*1000, false);
     316}
     317
     318
     319static void test1(uint32_t cThreads, uint32_t cPasses)
     320{
     321    testIt(cThreads, cPasses, test1Thread, "critsect");
     322}
     323
     324
     325static void test2(uint32_t cThreads, uint32_t cPasses)
     326{
     327    testIt(cThreads, cPasses, test2Thread, "read-write");
     328}
     329
    160330
    161331static bool testIsLockValidationCompiledIn(void)
     
    194364    RTLockValidatorSetEnabled(true);
    195365    RTLockValidatorSetMayPanic(false);
     366    RTLockValidatorSetQuiet(true);
    196367    if (!testIsLockValidationCompiledIn())
    197368        return RTTestErrorCount(g_hTest) > 0
    198369            ? RTTestSummaryAndDestroy(g_hTest)
    199370            : RTTestSkipAndDestroy(g_hTest, "deadlock detection is not compiled in");
    200 
    201     test1(2);
    202     test1(3);
    203     test1(15);
    204     test1(30);
     371    RTLockValidatorSetQuiet(false);
     372
     373    /*
     374     * Some initial tests with verbose output.
     375     */
     376    test1(3, 1);
     377
     378    test2(1, 1);
     379    test2(3, 1);
     380
     381    /*
     382     * More thorough testing without noisy output.
     383     */
     384    RTLockValidatorSetQuiet(true);
     385
     386    test1( 2, 1024);
     387    test1( 3, 1024);
     388    test1( 7,  896);
     389    test1(10,  768);
     390    test1(15,  512);
     391    test1(30,  384);
     392
     393    test2( 1,  100);
     394    test2( 2, 1024);
     395    test2( 3, 1024);
     396    test2( 7,  896);
     397    test2(10,  768);
     398    test2(15,  512);
     399    test2(30,  384);
     400
    205401
    206402    return RTTestSummaryAndDestroy(g_hTest);
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