Changeset 25602 in vbox for trunk/src/VBox/Runtime/common
- Timestamp:
- Dec 31, 2009 1:18:00 AM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp
r25570 r25602 41 41 #include <iprt/once.h> 42 42 #include <iprt/semaphore.h> 43 #include <iprt/string.h> 43 44 #include <iprt/thread.h> 44 45 … … 51 52 * Structures and Typedefs * 52 53 *******************************************************************************/ 54 /** 55 * Deadlock detection stack entry. 56 */ 57 typedef struct RTLOCKVALIDATORDDENTRY 58 { 59 /** The current record. */ 60 PRTLOCKVALIDATORRECUNION pRec; 61 /** The current entry number if pRec is a shared one. */ 62 uint32_t iEntry; 63 /** The thread state of the thread we followed to get to pFirstSibling. 64 * This is only used for validating a deadlock stack. */ 65 RTTHREADSTATE enmState; 66 /** The thread we followed to get to pFirstSibling. 67 * This is only used for validating a deadlock stack. */ 68 PRTTHREADINT pThread; 69 /** What pThread is waiting on, i.e. where we entered the circular list of 70 * siblings. This is used for validating a deadlock stack as well as 71 * terminating the sibling walk. */ 72 PRTLOCKVALIDATORRECUNION pFirstSibling; 73 } RTLOCKVALIDATORDDENTRY; 74 75 76 /** 77 * Deadlock detection stack. 78 */ 79 typedef struct RTLOCKVALIDATORDDSTACK 80 { 81 /** The number stack entries. */ 82 uint32_t c; 83 /** The stack entries. */ 84 RTLOCKVALIDATORDDENTRY a[32]; 85 } RTLOCKVALIDATORDDSTACK; 86 /** Pointer to a deadlock detction stack. */ 87 typedef RTLOCKVALIDATORDDSTACK *PRTLOCKVALIDATORDDSTACK; 53 88 54 89 … … 60 95 * EW: Deadlock detection. 61 96 */ 62 static RTSEMXROADS g_hLockValidatorXRoads= NIL_RTSEMXROADS;97 static RTSEMXROADS g_hLockValidatorXRoads = NIL_RTSEMXROADS; 63 98 /** Whether the lock validator is enabled or disabled. 64 99 * Only applies to new locks. */ 65 static bool volatile g_fLockValidatorEnabled = true; 100 static bool volatile g_fLockValidatorEnabled = true; 101 /** Set if the lock validator is quiet. */ 102 #ifdef RT_STRICT 103 static bool volatile g_fLockValidatorQuiet = false; 104 #else 105 static bool volatile g_fLockValidatorQuiet = true; 106 #endif 107 /** Set if the lock validator may panic. */ 108 #ifdef RT_STRICT 109 static bool volatile g_fLockValidatorMayPanic = true; 110 #else 111 static bool volatile g_fLockValidatorMayPanic = false; 112 #endif 113 114 115 /** Wrapper around ASMAtomicReadPtr. */ 116 DECL_FORCE_INLINE(PRTLOCKVALIDATORRECUNION) rtLockValidatorReadRecUnionPtr(PRTLOCKVALIDATORRECUNION volatile *ppRec) 117 { 118 return (PRTLOCKVALIDATORRECUNION)ASMAtomicReadPtr((void * volatile *)ppRec); 119 } 120 121 122 /** Wrapper around ASMAtomicWritePtr. */ 123 DECL_FORCE_INLINE(void) rtLockValidatorWriteRecUnionPtr(PRTLOCKVALIDATORRECUNION volatile *ppRec, PRTLOCKVALIDATORRECUNION pRecNew) 124 { 125 ASMAtomicWritePtr((void * volatile *)ppRec, pRecNew); 126 } 127 128 129 /** Wrapper around ASMAtomicReadPtr. */ 130 DECL_FORCE_INLINE(PRTTHREADINT) rtLockValidatorReadThreadHandle(RTTHREAD volatile *phThread) 131 { 132 return (PRTTHREADINT)ASMAtomicReadPtr((void * volatile *)phThread); 133 } 134 135 136 /** Wrapper around ASMAtomicUoReadPtr. */ 137 DECL_FORCE_INLINE(PRTLOCKVALIDATORSHAREDONE) rtLockValidatorUoReadSharedOwner(PRTLOCKVALIDATORSHAREDONE volatile *ppOwner) 138 { 139 return (PRTLOCKVALIDATORSHAREDONE)ASMAtomicUoReadPtr((void * volatile *)ppOwner); 140 } 141 142 143 /** 144 * Reads a volatile thread handle field and returns the thread name. 145 * 146 * @returns Thread name (read only). 147 * @param phThread The thread handle field. 148 */ 149 static const char *rtLockValidatorNameThreadHandle(RTTHREAD volatile *phThread) 150 { 151 PRTTHREADINT pThread = rtLockValidatorReadThreadHandle(phThread); 152 if (!pThread) 153 return "<NIL>"; 154 if (!VALID_PTR(pThread)) 155 return "<INVALID>"; 156 if (pThread->u32Magic != RTTHREADINT_MAGIC) 157 return "<BAD-THREAD-MAGIC>"; 158 return pThread->szName; 159 } 160 161 162 /** 163 * Launch a simple assertion like complaint w/ panic. 164 * 165 * @param RT_SRC_POS_DECL Where from. 166 * @param pszWhat What we're complaining about. 167 * @param ... Format arguments. 168 */ 169 static void rtLockValidatorComplain(RT_SRC_POS_DECL, const char *pszWhat, ...) 170 { 171 if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet)) 172 { 173 RTAssertMsg1Weak("RTLockValidator", iLine, pszFile, pszFunction); 174 va_list va; 175 va_start(va, pszWhat); 176 RTAssertMsg2WeakV(pszWhat, va); 177 va_end(va); 178 } 179 if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet)) 180 RTAssertPanic(); 181 } 182 183 184 /** 185 * Describes the lock. 186 * 187 * @param pszPrefix Message prefix. 188 * @param Rec The lock record we're working on. 189 * @param pszPrefix Message suffix. 190 */ 191 static void rtLockValidatorComplainAboutLock(const char *pszPrefix, PRTLOCKVALIDATORRECUNION pRec, const char *pszSuffix) 192 { 193 if ( VALID_PTR(pRec) 194 && !ASMAtomicUoReadBool(&g_fLockValidatorQuiet)) 195 { 196 switch (pRec->Core.u32Magic) 197 { 198 case RTLOCKVALIDATORREC_MAGIC: 199 RTAssertMsg2AddWeak("%s%p %s xrec=%p own=%s nest=%u pos={%Rbn(%u) %Rfn %p}%s", pszPrefix, 200 pRec->Excl.hLock, pRec->Excl.pszName, pRec, 201 rtLockValidatorNameThreadHandle(&pRec->Excl.hThread), pRec->Excl.cRecursion, 202 pRec->Excl.SrcPos.pszFile, pRec->Excl.SrcPos.uLine, pRec->Excl.SrcPos.pszFunction, pRec->Excl.SrcPos.uId, 203 pszSuffix); 204 break; 205 206 case RTLOCKVALIDATORSHARED_MAGIC: 207 RTAssertMsg2AddWeak("%s%p %s srec=%p%s", pszPrefix, 208 pRec->Shared.hLock, pRec->Shared.pszName, pRec, 209 pszSuffix); 210 break; 211 212 case RTLOCKVALIDATORSHAREDONE_MAGIC: 213 { 214 PRTLOCKVALIDATORSHARED pShared = pRec->SharedOne.pSharedRec; 215 if ( VALID_PTR(pShared) 216 && pShared->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC) 217 RTAssertMsg2AddWeak("%s%p %s srec=%p trec=%p thr=%s nest=%u pos={%Rbn(%u) %Rfn %p}%s", pszPrefix, 218 pShared->hLock, pShared->pszName, pShared, 219 pRec, rtLockValidatorNameThreadHandle(&pRec->SharedOne.hThread), pRec->SharedOne.cRecursion, 220 pRec->SharedOne.SrcPos.pszFile, pRec->SharedOne.SrcPos.uLine, pRec->SharedOne.SrcPos.pszFunction, pRec->SharedOne.SrcPos.uId, 221 pszSuffix); 222 else 223 RTAssertMsg2AddWeak("%sbad srec=%p trec=%p thr=%s nest=%u pos={%Rbn(%u) %Rfn %p}%s", pszPrefix, 224 pShared, 225 pRec, rtLockValidatorNameThreadHandle(&pRec->SharedOne.hThread), pRec->SharedOne.cRecursion, 226 pRec->SharedOne.SrcPos.pszFile, pRec->SharedOne.SrcPos.uLine, pRec->SharedOne.SrcPos.pszFunction, pRec->SharedOne.SrcPos.uId, 227 pszSuffix); 228 break; 229 } 230 231 default: 232 RTAssertMsg2AddWeak("%spRec=%p u32Magic=%#x (bad)%s", pszPrefix, pRec, pRec->Core.u32Magic, pszSuffix); 233 break; 234 } 235 } 236 } 237 238 239 /** 240 * Launch the initial complaint. 241 * 242 * @param pszWhat What we're complaining about. 243 * @param pSrcPos Where we are complaining from, as it were. 244 * @param pThreadSelf The calling thread. 245 * @param pRec The main lock involved. Can be NULL. 246 */ 247 static void rtLockValidatorComplainFirst(const char *pszWhat, PCRTLOCKVALIDATORSRCPOS pSrcPos, PRTTHREADINT pThreadSelf, PRTLOCKVALIDATORRECUNION pRec) 248 { 249 if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet)) 250 { 251 RTAssertMsg1Weak("RTLockValidator", pSrcPos->uLine, pSrcPos->pszFile, pSrcPos->pszFunction); 252 if (pSrcPos->uId) 253 RTAssertMsg2Weak("%s [uId=%p thrd=%s]\n", pszWhat, pSrcPos->uId, VALID_PTR(pThreadSelf) ? pThreadSelf->szName : "<NIL>"); 254 else 255 RTAssertMsg2Weak("%s\n", pszWhat, pSrcPos->uId); 256 rtLockValidatorComplainAboutLock("Lock: ", pRec, "\n"); 257 } 258 } 259 260 261 /** 262 * Continue bitching. 263 * 264 * @param pszFormat Format string. 265 * @param ... Format arguments. 266 */ 267 static void rtLockValidatorComplainMore(const char *pszFormat, ...) 268 { 269 if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet)) 270 { 271 va_list va; 272 va_start(va, pszFormat); 273 RTAssertMsg2AddWeakV(pszFormat, va); 274 va_end(va); 275 } 276 } 277 278 279 /** 280 * Raise a panic if enabled. 281 */ 282 static void rtLockValidatorComplainPanic(void) 283 { 284 if (ASMAtomicUoReadBool(&g_fLockValidatorMayPanic)) 285 RTAssertPanic(); 286 } 66 287 67 288 … … 146 367 uint32_t uSubClass, const char *pszName, void *hLock) 147 368 { 148 pRec-> u32Magic= RTLOCKVALIDATORREC_MAGIC;369 pRec->Core.u32Magic = RTLOCKVALIDATORREC_MAGIC; 149 370 pRec->fEnabled = RTLockValidatorIsEnabled(); 150 371 pRec->afReserved[0] = 0; … … 189 410 190 411 412 /** 413 * Unlinks all siblings. 414 * 415 * This is used during record deletion and assumes no races. 416 * 417 * @param pCore One of the siblings. 418 */ 419 static void rtLockValidatorUnlinkAllSiblings(PRTLOCKVALIDATORRECCORE pCore) 420 { 421 /* ASSUMES sibling destruction doesn't involve any races and that all 422 related records are to be disposed off now. */ 423 PRTLOCKVALIDATORRECUNION pSibling = (PRTLOCKVALIDATORRECUNION)pCore; 424 while (pSibling) 425 { 426 PRTLOCKVALIDATORRECUNION volatile *ppCoreNext; 427 switch (pSibling->Core.u32Magic) 428 { 429 case RTLOCKVALIDATORREC_MAGIC: 430 case RTLOCKVALIDATORREC_MAGIC_DEAD: 431 ppCoreNext = &pSibling->Excl.pSibling; 432 break; 433 434 case RTLOCKVALIDATORSHARED_MAGIC: 435 case RTLOCKVALIDATORSHARED_MAGIC_DEAD: 436 ppCoreNext = &pSibling->Shared.pSibling; 437 break; 438 439 default: 440 AssertFailed(); 441 ppCoreNext = NULL; 442 break; 443 } 444 if (RT_UNLIKELY(ppCoreNext)) 445 break; 446 pSibling = (PRTLOCKVALIDATORRECUNION)ASMAtomicXchgPtr((void * volatile *)ppCoreNext, NULL); 447 } 448 } 449 450 191 451 RTDECL(void) RTLockValidatorRecDelete(PRTLOCKVALIDATORREC pRec) 192 452 { 193 Assert(pRec-> u32Magic == RTLOCKVALIDATORREC_MAGIC);453 Assert(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC); 194 454 195 455 rtLockValidatorSerializeDestructEnter(); 196 456 197 ASMAtomicWriteU32(&pRec-> u32Magic, RTLOCKVALIDATORREC_MAGIC_DEAD);457 ASMAtomicWriteU32(&pRec->Core.u32Magic, RTLOCKVALIDATORREC_MAGIC_DEAD); 198 458 ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD); 199 459 ASMAtomicWriteHandle(&pRec->hClass, NIL_RTLOCKVALIDATORCLASS); 200 460 if (pRec->pSibling) 201 { 202 /* ASSUMES sibling destruction doesn't involve any races. */ 203 ASMAtomicUoWritePtr((void * volatile *)&pRec->pSibling->pSibling, NULL); 204 ASMAtomicUoWritePtr((void * volatile *)&pRec->pSibling, NULL); 205 } 206 461 rtLockValidatorUnlinkAllSiblings(&pRec->Core); 207 462 rtLockValidatorSerializeDestructLeave(); 208 463 } … … 224 479 uint32_t uSubClass, const char *pszName, void *hLock) 225 480 { 226 pRec-> u32Magic= RTLOCKVALIDATORSHARED_MAGIC;481 pRec->Core.u32Magic = RTLOCKVALIDATORSHARED_MAGIC; 227 482 pRec->uSubClass = uSubClass; 228 483 pRec->hClass = hClass; … … 248 503 RTDECL(void) RTLockValidatorSharedRecDelete(PRTLOCKVALIDATORSHARED pRec) 249 504 { 250 Assert(pRec-> u32Magic == RTLOCKVALIDATORSHARED_MAGIC);505 Assert(pRec->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC); 251 506 252 507 /* … … 264 519 } 265 520 266 ASMAtomicWriteU32(&pRec-> u32Magic, RTLOCKVALIDATORSHARED_MAGIC_DEAD);521 ASMAtomicWriteU32(&pRec->Core.u32Magic, RTLOCKVALIDATORSHARED_MAGIC_DEAD); 267 522 ASMAtomicUoWriteHandle(&pRec->hClass, NIL_RTLOCKVALIDATORCLASS); 268 523 if (pRec->papOwners) … … 275 530 } 276 531 if (pRec->pSibling) 277 { 278 /* ASSUMES sibling destruction doesn't involve any races. */ 279 ASMAtomicUoWritePtr((void * volatile *)&pRec->pSibling->pSibling, NULL); 280 ASMAtomicUoWritePtr((void * volatile *)&pRec->pSibling, NULL); 281 } 532 rtLockValidatorUnlinkAllSiblings(&pRec->Core); 282 533 ASMAtomicWriteBool(&pRec->fReallocating, false); 283 534 … … 304 555 for (uint32_t iEntry = 0; iEntry < cMax; iEntry++) 305 556 { 306 PRTLOCKVALIDATORSHAREDONE pEntry; 307 pEntry = (PRTLOCKVALIDATORSHAREDONE)ASMAtomicUoReadPtr((void * volatile *)&papOwners[iEntry]); 557 PRTLOCKVALIDATORSHAREDONE pEntry = rtLockValidatorUoReadSharedOwner(&papOwners[iEntry]); 308 558 if (pEntry && pEntry->hThread == hThread) 309 559 { … … 336 586 if (pEntry) 337 587 { 338 pEntry-> u32Magic= RTLOCKVALIDATORSHAREDONE_MAGIC;588 pEntry->Core.u32Magic = RTLOCKVALIDATORSHAREDONE_MAGIC; 339 589 pEntry->cRecursion = 1; 340 590 pEntry->hThread = hThread; … … 363 613 { 364 614 rtLockValidatorSerializeDestructEnter(); 365 ASMAtomicWriteU32(&pEntry-> u32Magic, RTLOCKVALIDATORSHAREDONE_MAGIC_DEAD);615 ASMAtomicWriteU32(&pEntry->Core.u32Magic, RTLOCKVALIDATORSHAREDONE_MAGIC_DEAD); 366 616 ASMAtomicWriteHandle(&pEntry->hThread, NIL_RTTHREAD); 367 617 rtLockValidatorSerializeDestructLeave(); … … 399 649 * Try grab the privilege to reallocating the table. 400 650 */ 401 if ( pShared-> u32Magic == RTLOCKVALIDATORSHARED_MAGIC651 if ( pShared->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC 402 652 && ASMAtomicCmpXchgBool(&pShared->fReallocating, true, false)) 403 653 { … … 438 688 439 689 rtLockValidatorSerializeDetectionEnter(); 440 if (RT_UNLIKELY(pShared-> u32Magic != RTLOCKVALIDATORSHARED_MAGIC))690 if (RT_UNLIKELY(pShared->Core.u32Magic != RTLOCKVALIDATORSHARED_MAGIC)) 441 691 break; 442 692 … … 461 711 { 462 712 rtLockValidatorSerializeDetectionEnter(); 463 if (RT_LIKELY(pShared-> u32Magic == RTLOCKVALIDATORSHARED_MAGIC)) /* paranoia */713 if (RT_LIKELY(pShared->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC)) /* paranoia */ 464 714 { 465 715 if ( ASMAtomicIncU32(&pShared->cEntries) > pShared->cAllocated /** @todo add fudge */ … … 502 752 */ 503 753 rtLockValidatorSerializeDetectionEnter(); 504 AssertReturnVoidStmt(pShared-> u32Magic == RTLOCKVALIDATORSHARED_MAGIC, rtLockValidatorSerializeDetectionLeave());754 AssertReturnVoidStmt(pShared->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC, rtLockValidatorSerializeDetectionLeave()); 505 755 if (RT_UNLIKELY( iEntry >= pShared->cAllocated 506 756 || !ASMAtomicCmpXchgPtr((void * volatile *)&pShared->papOwners[iEntry], NULL, pEntry))) … … 526 776 527 777 528 RTDECL(int) RTLockValidatorMakeSiblings( void *pvRec1, void *pvRec2)778 RTDECL(int) RTLockValidatorMakeSiblings(PRTLOCKVALIDATORRECCORE pRec1, PRTLOCKVALIDATORRECCORE pRec2) 529 779 { 530 780 /* 531 781 * Validate input. 532 782 */ 533 union 534 { 535 PRTLOCKVALIDATORREC pRec; 536 PRTLOCKVALIDATORSHARED pShared; 537 uint32_t *pu32Magic; 538 void *pv; 539 } u1, u2; 540 u1.pv = pvRec1; 541 u2.pv = pvRec2; 542 543 AssertPtrReturn(u1.pv, VERR_SEM_LV_INVALID_PARAMETER); 544 AssertReturn( *u1.pu32Magic == RTLOCKVALIDATORREC_MAGIC 545 || *u1.pu32Magic == RTLOCKVALIDATORSHARED_MAGIC 783 PRTLOCKVALIDATORRECUNION p1 = (PRTLOCKVALIDATORRECUNION)pRec1; 784 PRTLOCKVALIDATORRECUNION p2 = (PRTLOCKVALIDATORRECUNION)pRec2; 785 786 AssertPtrReturn(p1, VERR_SEM_LV_INVALID_PARAMETER); 787 AssertReturn( p1->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC 788 || p1->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC 546 789 , VERR_SEM_LV_INVALID_PARAMETER); 547 790 548 AssertPtrReturn( u2.pv, VERR_SEM_LV_INVALID_PARAMETER);549 AssertReturn( *u2.pu32Magic == RTLOCKVALIDATORREC_MAGIC550 || *u2.pu32Magic == RTLOCKVALIDATORSHARED_MAGIC791 AssertPtrReturn(p2, VERR_SEM_LV_INVALID_PARAMETER); 792 AssertReturn( p2->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC 793 || p2->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC 551 794 , VERR_SEM_LV_INVALID_PARAMETER); 552 795 … … 554 797 * Link them. 555 798 */ 556 if ( *u1.pu32Magic == RTLOCKVALIDATORREC_MAGIC557 && *u2.pu32Magic == RTLOCKVALIDATORSHARED_MAGIC)558 { 559 u1.pRec->pSibling = u2.pShared;560 u2.pShared->pSibling = u1.pRec;561 } 562 else if ( *u1.pu32Magic == RTLOCKVALIDATORSHARED_MAGIC563 && *u2.pu32Magic == RTLOCKVALIDATORREC_MAGIC)564 { 565 u1.pShared->pSibling = u2.pRec;566 u2.pRec->pSibling = u1.pShared;799 if ( p1->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC 800 && p2->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC) 801 { 802 p1->Excl.pSibling = p2; 803 p2->Shared.pSibling = p1; 804 } 805 else if ( p1->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC 806 && p2->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC) 807 { 808 p1->Shared.pSibling = p2; 809 p2->Excl.pSibling = p1; 567 810 } 568 811 else … … 575 818 RTDECL(int) RTLockValidatorCheckOrder(PRTLOCKVALIDATORREC pRec, RTTHREAD hThread, PCRTLOCKVALIDATORSRCPOS pSrcPos) 576 819 { 577 AssertReturn(pRec-> u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);820 AssertReturn(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 578 821 if (!pRec->fEnabled) 579 822 return VINF_SUCCESS; … … 594 837 RTDECL(int) RTLockValidatorCheckAndRelease(PRTLOCKVALIDATORREC pRec) 595 838 { 596 AssertReturn(pRec-> u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);839 AssertReturn(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 597 840 if (!pRec->fEnabled) 598 841 return VINF_SUCCESS; … … 606 849 RTDECL(int) RTLockValidatorCheckAndReleaseReadOwner(PRTLOCKVALIDATORSHARED pRead, RTTHREAD hThread) 607 850 { 608 AssertReturn(pRead-> u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);851 AssertReturn(pRead->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 609 852 if (!pRead->fEnabled) 610 853 return VINF_SUCCESS; … … 641 884 RTDECL(int) RTLockValidatorRecordRecursion(PRTLOCKVALIDATORREC pRec, PCRTLOCKVALIDATORSRCPOS pSrcPos) 642 885 { 643 AssertReturn(pRec-> u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);886 AssertReturn(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 644 887 if (!pRec->fEnabled) 645 888 return VINF_SUCCESS; … … 655 898 RTDECL(int) RTLockValidatorUnwindRecursion(PRTLOCKVALIDATORREC pRec) 656 899 { 657 AssertReturn(pRec-> u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);900 AssertReturn(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 658 901 if (!pRec->fEnabled) 659 902 return VINF_SUCCESS; … … 669 912 RTDECL(int) RTLockValidatorRecordReadWriteRecursion(PRTLOCKVALIDATORREC pWrite, PRTLOCKVALIDATORSHARED pRead, PCRTLOCKVALIDATORSRCPOS pSrcPos) 670 913 { 671 AssertReturn(pWrite-> u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);672 AssertReturn(pRead-> u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);914 AssertReturn(pWrite->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 915 AssertReturn(pRead->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 673 916 AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER); 674 917 if (!pWrite->fEnabled) … … 686 929 RTDECL(int) RTLockValidatorUnwindReadWriteRecursion(PRTLOCKVALIDATORREC pWrite, PRTLOCKVALIDATORSHARED pRead) 687 930 { 688 AssertReturn(pWrite-> u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);689 AssertReturn(pRead-> u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);931 AssertReturn(pWrite->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 932 AssertReturn(pRead->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 690 933 AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER); 691 934 if (!pWrite->fEnabled) … … 702 945 RTDECL(RTTHREAD) RTLockValidatorSetOwner(PRTLOCKVALIDATORREC pRec, RTTHREAD hThread, PCRTLOCKVALIDATORSRCPOS pSrcPos) 703 946 { 704 AssertReturn(pRec-> u32Magic == RTLOCKVALIDATORREC_MAGIC, NIL_RTTHREAD);947 AssertReturn(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, NIL_RTTHREAD); 705 948 if (!pRec->fEnabled) 706 949 return VINF_SUCCESS; … … 738 981 RTDECL(RTTHREAD) RTLockValidatorUnsetOwner(PRTLOCKVALIDATORREC pRec) 739 982 { 740 AssertReturn(pRec-> u32Magic == RTLOCKVALIDATORREC_MAGIC, NIL_RTTHREAD);983 AssertReturn(pRec->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, NIL_RTTHREAD); 741 984 if (!pRec->fEnabled) 742 985 return VINF_SUCCESS; … … 765 1008 RTDECL(void) RTLockValidatorAddReadOwner(PRTLOCKVALIDATORSHARED pRead, RTTHREAD hThread, PCRTLOCKVALIDATORSRCPOS pSrcPos) 766 1009 { 767 AssertReturnVoid(pRead-> u32Magic == RTLOCKVALIDATORSHARED_MAGIC);1010 AssertReturnVoid(pRead->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC); 768 1011 if (!pRead->fEnabled) 769 1012 return; … … 796 1039 RTDECL(void) RTLockValidatorRemoveReadOwner(PRTLOCKVALIDATORSHARED pRead, RTTHREAD hThread) 797 1040 { 798 AssertReturnVoid(pRead-> u32Magic == RTLOCKVALIDATORSHARED_MAGIC);1041 AssertReturnVoid(pRead->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC); 799 1042 if (!pRead->fEnabled) 800 1043 return; … … 884 1127 885 1128 886 887 /** 888 * Bitch about a deadlock. 889 * 890 * @param pRec The lock validator record we're going to block on. 891 * @param pThread This thread. 892 * @param pCur The thread we're deadlocking with. 893 * @param enmState The sleep state. 894 * @param pSrcPos Where we are going to deadlock. 895 */ 896 static void rtLockValidatorComplainAboutDeadlock(PRTLOCKVALIDATORREC pRec, PRTTHREADINT pThread, RTTHREADSTATE enmState, 897 PRTTHREADINT pCur, PCRTLOCKVALIDATORSRCPOS pSrcPos) 898 { 899 RTAssertMsg1Weak(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", pSrcPos->uLine, pSrcPos->pszFile, pSrcPos->pszFunction); 900 901 /* 902 * Print the threads and locks involved. 903 */ 904 PRTTHREADINT apSeenThreads[8] = {0,0,0,0,0,0,0,0}; 905 unsigned iSeenThread = 0; 906 pCur = pThread; 907 for (unsigned iEntry = 0; pCur && iEntry < 256; iEntry++) 1129 /** 1130 * Checks for stack cycles caused by another deadlock before returning. 1131 * 1132 * @retval VINF_SUCCESS if the stack is simply too small. 1133 * @retval VERR_SEM_LV_EXISTING_DEADLOCK if a cycle was detected. 1134 * 1135 * @param pStack The deadlock detection stack. 1136 */ 1137 static int rtLockValidatorDdHandleStackOverflow(PRTLOCKVALIDATORDDSTACK pStack) 1138 { 1139 for (size_t i = 0; i < RT_ELEMENTS(pStack->a) - 1; i++) 1140 { 1141 PRTTHREADINT pThread = pStack->a[i].pThread; 1142 for (size_t j = i + 1; j < RT_ELEMENTS(pStack->a); j++) 1143 if (pStack->a[j].pThread == pThread) 1144 return VERR_SEM_LV_EXISTING_DEADLOCK; 1145 } 1146 static bool volatile s_fComplained = false; 1147 if (!s_fComplained) 1148 { 1149 s_fComplained = true; 1150 rtLockValidatorComplain(RT_SRC_POS, "lock validator stack is too small! (%zu entries)\n", RT_ELEMENTS(pStack->a)); 1151 } 1152 return VINF_SUCCESS; 1153 } 1154 1155 1156 /** 1157 * Worker for rtLockValidatorDoDeadlockCheck that checks if there is more work 1158 * to be done during unwind. 1159 * 1160 * @returns true if there is more work left for this lock, false if not. 1161 * @param pRec The current record. 1162 * @param iEntry The current index. 1163 * @param pFirstSibling The first record we examined. 1164 */ 1165 DECL_FORCE_INLINE(bool) rtLockValidatorDdMoreWorkLeft(PRTLOCKVALIDATORRECUNION pRec, uint32_t iEntry, PRTLOCKVALIDATORRECUNION pFirstSibling) 1166 { 1167 PRTLOCKVALIDATORRECUNION pSibling; 1168 1169 switch (pRec->Core.u32Magic) 1170 { 1171 case RTLOCKVALIDATORREC_MAGIC: 1172 pSibling = pRec->Excl.pSibling; 1173 break; 1174 1175 case RTLOCKVALIDATORSHARED_MAGIC: 1176 if (iEntry + 1 < pRec->Shared.cAllocated) 1177 return true; 1178 pSibling = pRec->Excl.pSibling; 1179 break; 1180 1181 default: 1182 return false; 1183 } 1184 return pSibling != NULL 1185 && pSibling != pFirstSibling; 1186 } 1187 1188 1189 /** 1190 * Worker for rtLockValidatorDeadlockDetection that does the actual deadlock 1191 * detection. 1192 * 1193 * @returns Same as rtLockValidatorDeadlockDetection. 1194 * @param pStack The stack to use. 1195 * @param pOriginalRec The original record. 1196 * @param pThreadSelf The calling thread. 1197 */ 1198 static int rtLockValidatorDdDoDetection(PRTLOCKVALIDATORDDSTACK pStack, PRTLOCKVALIDATORRECUNION const pOriginalRec, 1199 PRTTHREADINT const pThreadSelf) 1200 { 1201 pStack->c = 0; 1202 1203 /* We could use a single RTLOCKVALIDATORDDENTRY variable here, but the 1204 compiler may make a better job of it when using individual variables. */ 1205 PRTLOCKVALIDATORRECUNION pRec = pOriginalRec; 1206 PRTLOCKVALIDATORRECUNION pFirstSibling = pOriginalRec; 1207 uint32_t iEntry = UINT32_MAX; 1208 PRTTHREADINT pThread = NIL_RTTHREAD; 1209 RTTHREADSTATE enmState = RTTHREADSTATE_RUNNING; 1210 for (;;) 908 1211 { 909 1212 /* 910 * Pr int info on pCur. Determin next while doing so.1213 * Process the current record. 911 1214 */ 912 RTAssertMsg2Weak(" #%u: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n", 913 iEntry, pCur, pCur->Core.Key, pCur->szName, 914 pCur->LockValidator.SrcPos.pszFile, pCur->LockValidator.SrcPos.uLine, 915 pCur->LockValidator.SrcPos.pszFunction, pCur->LockValidator.SrcPos.uId); 916 PRTTHREADINT pNext = NULL; 917 RTTHREADSTATE enmCurState = rtThreadGetState(pCur); 918 switch (enmCurState) 1215 /* Extract the (next) thread. */ 1216 PRTTHREADINT pNextThread; 1217 switch (pRec->Core.u32Magic) 919 1218 { 920 case RTTHREADSTATE_CRITSECT: 921 case RTTHREADSTATE_EVENT: 922 case RTTHREADSTATE_EVENT_MULTI: 923 case RTTHREADSTATE_FAST_MUTEX: 924 case RTTHREADSTATE_MUTEX: 925 case RTTHREADSTATE_SPIN_MUTEX: 1219 case RTLOCKVALIDATORREC_MAGIC: 1220 Assert(iEntry == UINT32_MAX); 1221 pNextThread = rtLockValidatorReadThreadHandle(&pRec->Excl.hThread); 1222 if ( pNextThread 1223 && !RTTHREAD_IS_SLEEPING(pNextThread->enmState) 1224 && pNextThread != pThreadSelf) 1225 pNextThread = NIL_RTTHREAD; 1226 if ( pNextThread == NIL_RTTHREAD 1227 && pRec->Excl.pSibling 1228 && pRec->Excl.pSibling != pFirstSibling) 1229 { 1230 pRec = pRec->Excl.pSibling; 1231 continue; 1232 } 1233 break; 1234 1235 case RTLOCKVALIDATORSHARED_MAGIC: 1236 /* Skip to the next sibling if same side. ASSUMES reader priority. */ 1237 /** @todo The read side of a read-write lock is problematic if 1238 * the implementation prioritizes writers over readers because 1239 * that means we should could deadlock against current readers 1240 * if a writer showed up. If the RW sem implementation is 1241 * wrapping some native API, it's not so easy to detect when we 1242 * should do this and when we shouldn't. Checking when we 1243 * shouldn't is subject to wakeup scheduling and cannot easily 1244 * be made reliable. 1245 * 1246 * At the moment we circumvent all this mess by declaring that 1247 * readers has priority. This is TRUE on linux, but probably 1248 * isn't on Solaris and FreeBSD. */ 1249 if ( pRec == pFirstSibling 1250 && pRec->Shared.pSibling != NULL 1251 && pRec->Shared.pSibling != pFirstSibling) 1252 { 1253 pRec = pRec->Shared.pSibling; 1254 Assert(iEntry == UINT32_MAX); 1255 continue; 1256 } 1257 1258 /* Scan the owner table for blocked owners. */ 1259 if (ASMAtomicUoReadU32(&pRec->Shared.cEntries) > 0) 1260 { 1261 uint32_t cAllocated = ASMAtomicUoReadU32(&pRec->Shared.cAllocated); 1262 PRTLOCKVALIDATORSHAREDONE volatile *papOwners = pRec->Shared.papOwners; 1263 while (++iEntry < cAllocated) 1264 { 1265 PRTLOCKVALIDATORSHAREDONE pEntry = rtLockValidatorUoReadSharedOwner(&papOwners[iEntry]); 1266 if ( pEntry 1267 && pEntry->Core.u32Magic == RTLOCKVALIDATORSHAREDONE_MAGIC) 1268 { 1269 pNextThread = rtLockValidatorReadThreadHandle(&pEntry->hThread); 1270 if ( pNextThread 1271 && !RTTHREAD_IS_SLEEPING(pNextThread->enmState) 1272 && pNextThread != pThreadSelf) 1273 pNextThread = NIL_RTTHREAD; 1274 } 1275 else 1276 Assert(!pEntry || pEntry->Core.u32Magic == RTLOCKVALIDATORSHAREDONE_MAGIC_DEAD); 1277 } 1278 } 1279 1280 /* Advance to the next sibling, if any. */ 1281 Assert(pNextThread == NIL_RTTHREAD); 1282 if ( pRec->Shared.pSibling != NULL 1283 && pRec->Shared.pSibling != pFirstSibling) 1284 { 1285 pRec = pRec->Shared.pSibling; 1286 iEntry = UINT32_MAX; 1287 continue; 1288 } 1289 break; 1290 1291 case RTLOCKVALIDATORREC_MAGIC_DEAD: 1292 case RTLOCKVALIDATORSHARED_MAGIC_DEAD: 1293 pNextThread = NIL_RTTHREAD; 1294 break; 1295 1296 case RTLOCKVALIDATORSHAREDONE_MAGIC: 1297 case RTLOCKVALIDATORSHAREDONE_MAGIC_DEAD: 1298 default: 1299 AssertMsgFailed(("%p: %#x\n", pRec, pRec->Core)); 1300 pNextThread = NIL_RTTHREAD; 1301 break; 1302 } 1303 1304 /* Is that thread waiting for something? */ 1305 RTTHREADSTATE enmNextState = RTTHREADSTATE_RUNNING; 1306 PRTLOCKVALIDATORRECUNION pNextRec = NULL; 1307 if ( pNextThread != NIL_RTTHREAD 1308 && RT_LIKELY(pNextThread->u32Magic == RTTHREADINT_MAGIC)) 1309 { 1310 do 926 1311 { 927 PRTLOCKVALIDATORREC pCurRec = pCur->LockValidator.pRec; 928 RTTHREADSTATE enmCurState2 = rtThreadGetState(pCur); 929 if (enmCurState2 != enmCurState) 1312 enmNextState = rtThreadGetState(pNextThread); 1313 if ( !RTTHREAD_IS_SLEEPING(enmNextState) 1314 && pNextThread != pThreadSelf) 1315 break; 1316 pNextRec = rtLockValidatorReadRecUnionPtr(&pNextThread->LockValidator.pRec); 1317 if (RT_LIKELY( !pNextRec 1318 || enmNextState == rtThreadGetState(pNextThread))) 1319 break; 1320 pNextRec = NULL; 1321 } while (pNextThread->u32Magic == RTTHREADINT_MAGIC); 1322 } 1323 if (pNextRec) 1324 { 1325 /* 1326 * Recurse and check for deadlock. 1327 */ 1328 uint32_t i = pStack->c; 1329 if (RT_UNLIKELY(i >= RT_ELEMENTS(pStack->a))) 1330 return rtLockValidatorDdHandleStackOverflow(pStack); 1331 1332 pStack->c++; 1333 pStack->a[i].pRec = pRec; 1334 pStack->a[i].iEntry = iEntry; 1335 pStack->a[i].enmState = enmState; 1336 pStack->a[i].pThread = pThread; 1337 pStack->a[i].pFirstSibling = pFirstSibling; 1338 1339 if (RT_UNLIKELY(pNextThread == pThreadSelf)) 1340 return VERR_SEM_LV_DEADLOCK; 1341 1342 pRec = pNextRec; 1343 pFirstSibling = pNextRec; 1344 iEntry = UINT32_MAX; 1345 enmState = enmNextState; 1346 pThread = pNextThread; 1347 } 1348 else if (RT_LIKELY(!pNextThread)) 1349 { 1350 /* 1351 * No deadlock here, unwind the stack and deal with any unfinished 1352 * business there. 1353 */ 1354 uint32_t i = pStack->c; 1355 for (;;) 1356 { 1357 /* pop */ 1358 if (i == 0) 1359 return VINF_SUCCESS; 1360 i--; 1361 1362 /* examine it. */ 1363 pRec = pStack->a[i].pRec; 1364 pFirstSibling = pStack->a[i].pFirstSibling; 1365 iEntry = pStack->a[i].iEntry; 1366 if (rtLockValidatorDdMoreWorkLeft(pRec, iEntry, pFirstSibling)) 930 1367 { 931 RTAssertMsg2Weak(" Impossible!!! enmState=%s -> %s (%d)\n",932 RTThreadStateName(enmCurState), RTThreadStateName(enmCurState2), enmCurState2);1368 enmState = pStack->a[i].enmState; 1369 pThread = pStack->a[i].pThread; 933 1370 break; 934 1371 } 935 if ( VALID_PTR(pCurRec)936 && pCurRec->u32Magic == RTLOCKVALIDATORREC_MAGIC)937 {938 RTAssertMsg2Weak(" Waiting on %s %p [%s]: Entered %s(%u) %s %p\n",939 RTThreadStateName(enmCurState), pCurRec->hLock, pCurRec->pszName,940 pCurRec->SrcPos.pszFile, pCurRec->SrcPos.uLine, pCurRec->SrcPos.pszFunction, pCurRec->SrcPos.uId);941 pNext = pCurRec->hThread;942 }943 else if (VALID_PTR(pCurRec))944 RTAssertMsg2Weak(" Waiting on %s pCurRec=%p: invalid magic number: %#x\n",945 RTThreadStateName(enmCurState), pCurRec, pCurRec->u32Magic);946 else947 RTAssertMsg2Weak(" Waiting on %s pCurRec=%p: invalid pointer\n",948 RTThreadStateName(enmCurState), pCurRec);949 break;950 1372 } 951 952 #if 0 953 case RTTHREADSTATE_RW_READ: 954 case RTTHREADSTATE_RW_WRITE: 955 { 956 } 1373 } 1374 /* else: see if there is another thread to check for this lock. */ 1375 } 1376 } 1377 1378 1379 /** 1380 * Check for the simple no-deadlock case. 1381 * 1382 * @returns true if no deadlock, false if further investigation is required. 1383 * 1384 * @param pOriginalRec The original record. 1385 */ 1386 DECLINLINE(int) rtLockValidatorIsSimpleNoDeadlockCase(PRTLOCKVALIDATORRECUNION pOriginalRec) 1387 { 1388 if ( pOriginalRec->Excl.Core.u32Magic == RTLOCKVALIDATORREC_MAGIC 1389 && !pOriginalRec->Excl.pSibling) 1390 { 1391 PRTTHREADINT pThread = rtLockValidatorReadThreadHandle(&pOriginalRec->Excl.hThread); 1392 if ( !pThread 1393 || pThread->u32Magic != RTTHREADINT_MAGIC) 1394 return true; 1395 RTTHREADSTATE enmState = rtThreadGetState(pThread); 1396 if (!RTTHREAD_IS_SLEEPING(enmState)) 1397 return true; 1398 } 1399 return false; 1400 } 1401 1402 1403 /** 1404 * Worker for rtLockValidatorDeadlockDetection that bitches about a deadlock. 1405 * 1406 * @param pStack The chain of locks causing the deadlock. 1407 * @param pThreadSelf This thread. 1408 * @param pSrcPos Where we are going to deadlock. 1409 * @param rc The return code. 1410 */ 1411 static void rcLockValidatorDoDeadlockComplaining(PRTLOCKVALIDATORDDSTACK pStack, PRTTHREADINT pThreadSelf, 1412 PCRTLOCKVALIDATORSRCPOS pSrcPos, int rc) 1413 { 1414 if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet)) 1415 { 1416 rtLockValidatorComplainFirst( rc == VERR_SEM_LV_DEADLOCK 1417 ? "deadlock" 1418 : rc == VERR_SEM_LV_EXISTING_DEADLOCK 1419 ? "existing-deadlock" 1420 : "!unexpected rc!", 1421 pSrcPos, pThreadSelf, NULL); 1422 rtLockValidatorComplainMore("---- start of %u entry deadlock chain ----\n", pStack->c); 1423 for (uint32_t i = 0; i < pStack->c; i++) 1424 { 1425 char szPrefix[24]; 1426 RTStrPrintf(szPrefix, sizeof(szPrefix), "#%u: ", i); 1427 PRTLOCKVALIDATORSHAREDONE pSharedOne = NULL; 1428 if (pStack->a[i].pRec->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC) 1429 pSharedOne = pStack->a[i].pRec->Shared.papOwners[pStack->a[i].iEntry]; 1430 if (VALID_PTR(pSharedOne) && pSharedOne->Core.u32Magic == RTLOCKVALIDATORSHAREDONE_MAGIC) 1431 rtLockValidatorComplainAboutLock(szPrefix, (PRTLOCKVALIDATORRECUNION)pSharedOne, "\n"); 1432 else 1433 rtLockValidatorComplainAboutLock(szPrefix, pStack->a[i].pRec, "\n"); 1434 } 1435 rtLockValidatorComplainMore("---- end of deadlock chain ----\n"); 1436 } 1437 1438 rtLockValidatorComplainPanic(); 1439 } 1440 1441 1442 /** 1443 * Perform deadlock detection. 1444 * 1445 * @retval VINF_SUCCESS 1446 * @retval VERR_SEM_LV_DEADLOCK 1447 * @retval VERR_SEM_LV_EXISTING_DEADLOCK 1448 * 1449 * @param pRec The record relating to the current thread's lock 1450 * operation. 1451 * @param pThreadSelf The current thread. 1452 * @param pSrcPos The position of the current lock operation. 1453 */ 1454 static int rtLockValidatorDeadlockDetection(PRTLOCKVALIDATORRECUNION pRec, PRTTHREADINT pThreadSelf, PCRTLOCKVALIDATORSRCPOS pSrcPos) 1455 { 1456 #ifdef DEBUG_bird 1457 RTLOCKVALIDATORDDSTACK Stack; 1458 int rc = rtLockValidatorDdDoDetection(&Stack, pRec, pThreadSelf); 1459 if (RT_FAILURE(rc)) 1460 rcLockValidatorDoDeadlockComplaining(&Stack, pThreadSelf, pSrcPos, rc); 1461 return rc; 1462 #else 1463 return VINF_SUCCESS; 957 1464 #endif 958 959 default: 960 RTAssertMsg2Weak(" Impossible!!! enmState=%s (%d)\n", RTThreadStateName(enmCurState), enmCurState); 961 break; 962 } 963 964 /* 965 * Check for cycle. 966 */ 967 if (iEntry && pCur == pThread) 968 break; 969 for (unsigned i = 0; i < RT_ELEMENTS(apSeenThreads); i++) 970 if (apSeenThreads[i] == pCur) 971 { 972 RTAssertMsg2Weak(" Cycle!\n"); 973 pNext = NULL; 974 break; 975 } 976 977 /* 978 * Advance to the next thread. 979 */ 980 iSeenThread = (iSeenThread + 1) % RT_ELEMENTS(apSeenThreads); 981 apSeenThreads[iSeenThread] = pCur; 982 pCur = pNext; 983 } 984 AssertBreakpoint(); 985 } 1465 } 1466 986 1467 987 1468 … … 993 1474 * Fend off wild life. 994 1475 */ 995 AssertPtrReturn(pWrite, VERR_SEM_LV_INVALID_PARAMETER); 996 AssertReturn(pWrite->u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1476 PRTLOCKVALIDATORRECUNION pWriteU = (PRTLOCKVALIDATORRECUNION)pWrite; /* (avoid break aliasing rules) */ 1477 AssertPtrReturn(pWriteU, VERR_SEM_LV_INVALID_PARAMETER); 1478 AssertReturn(pWriteU->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1479 PRTLOCKVALIDATORRECUNION pReadU = (PRTLOCKVALIDATORRECUNION)pRead; 997 1480 AssertPtrReturn(pRead, VERR_SEM_LV_INVALID_PARAMETER); 998 AssertReturn(pRead ->u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);999 AssertReturn(pRead ->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER);1000 if (!pWrite ->fEnabled)1481 AssertReturn(pReadU->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1482 AssertReturn(pReadU->Shared.fEnabled == pWriteU->Excl.fEnabled, VERR_SEM_LV_INVALID_PARAMETER); 1483 if (!pWriteU->Excl.fEnabled) 1001 1484 return VINF_SUCCESS; 1002 1485 AssertReturn(RTTHREAD_IS_SLEEPING(enmState), VERR_SEM_LV_INVALID_PARAMETER); … … 1013 1496 * Check for attempts at doing a read upgrade. 1014 1497 */ 1015 PRTLOCKVALIDATORSHAREDONE pEntry = rtLockValidatorSharedRecFindThread( pRead, hThread, NULL);1498 PRTLOCKVALIDATORSHAREDONE pEntry = rtLockValidatorSharedRecFindThread(&pReadU->Shared, hThread, NULL); 1016 1499 if (pEntry) 1017 1500 { 1018 AssertMsgFailed(("Read lock upgrade at %s(%d) %s %p!\nRead lock take at %s(%d) %s %p!\n", 1019 pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId, 1020 pEntry->SrcPos.pszFile, pEntry->SrcPos.uLine, pEntry->SrcPos.pszFunction, pEntry->SrcPos.uId)); 1501 rtLockValidatorComplainFirst("Read lock upgrade", pSrcPos, pThread, (PRTLOCKVALIDATORRECUNION)pEntry); 1502 rtLockValidatorComplainPanic(); 1021 1503 return VERR_SEM_LV_UPGRADE; 1022 1504 } … … 1036 1518 */ 1037 1519 AssertPtrReturn(pRead, VERR_SEM_LV_INVALID_PARAMETER); 1038 AssertReturn(pRead-> u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);1520 AssertReturn(pRead->Core.u32Magic == RTLOCKVALIDATORSHARED_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1039 1521 AssertPtrReturn(pWrite, VERR_SEM_LV_INVALID_PARAMETER); 1040 AssertReturn(pWrite-> u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);1522 AssertReturn(pWrite->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1041 1523 AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER); 1042 1524 if (!pRead->fEnabled) … … 1065 1547 * Fend off wild life. 1066 1548 */ 1067 AssertPtrReturn(pRec, VERR_SEM_LV_INVALID_PARAMETER); 1068 AssertReturn(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1069 if (!pRec->fEnabled) 1549 PRTLOCKVALIDATORRECUNION pRecU = (PRTLOCKVALIDATORRECUNION)pRec; 1550 AssertPtrReturn(pRecU, VERR_SEM_LV_INVALID_PARAMETER); 1551 AssertReturn(pRecU->Core.u32Magic == RTLOCKVALIDATORREC_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1552 if (!pRecU->Excl.fEnabled) 1070 1553 return VINF_SUCCESS; 1071 1554 AssertReturn(RTTHREAD_IS_SLEEPING(enmState), VERR_SEM_LV_INVALID_PARAMETER); 1072 PRTTHREADINT pThread = hThread;1073 AssertPtrReturn(pThread , VERR_SEM_LV_INVALID_PARAMETER);1074 AssertReturn(pThread ->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);1075 RTTHREADSTATE enmThreadState = rtThreadGetState(pThread );1555 PRTTHREADINT pThreadSelf = hThread; 1556 AssertPtrReturn(pThreadSelf, VERR_SEM_LV_INVALID_PARAMETER); 1557 AssertReturn(pThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1558 RTTHREADSTATE enmThreadState = rtThreadGetState(pThreadSelf); 1076 1559 AssertReturn( enmThreadState == RTTHREADSTATE_RUNNING 1077 1560 || enmThreadState == RTTHREADSTATE_TERMINATED /* rtThreadRemove uses locks too */ … … 1083 1566 * performing deadlock detection. 1084 1567 */ 1085 pThread->LockValidator.pRec = pRec;1086 rtLockValidatorCopySrcPos(&pThread ->LockValidator.SrcPos, pSrcPos);1087 1088 /* 1089 * Don't do deadlock detection if we're recursing and that's OK.1568 rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, pRecU); 1569 rtLockValidatorCopySrcPos(&pThreadSelf->LockValidator.SrcPos, pSrcPos); 1570 1571 /* 1572 * Don't do deadlock detection if we're recursing. 1090 1573 * 1091 1574 * On some hosts we don't do recursion accounting our selves and there 1092 1575 * isn't any other place to check for this. semmutex-win.cpp for instance. 1093 1576 */ 1094 if ( pRec->hThread == pThread)1577 if (rtLockValidatorReadThreadHandle(&pRecU->Excl.hThread) == pThreadSelf) 1095 1578 { 1096 1579 if (fRecursiveOk) 1097 1580 return VINF_SUCCESS; 1098 AssertMsgFailed(("%p (%s)\n", pRec->hLock, pRec->pszName)); 1581 rtLockValidatorComplainFirst("Recursion not allowed", pSrcPos, pThreadSelf, pRecU); 1582 rtLockValidatorComplainPanic(); 1099 1583 return VERR_SEM_LV_NESTED; 1100 1584 } 1101 1585 1102 1586 /* 1103 * Do deadlock detection. 1104 * 1105 * Since we're missing proper serialization, we don't declare it a 1106 * deadlock until we've got three runs with the same list length. 1107 * While this isn't perfect, it should avoid out the most obvious 1108 * races on SMP boxes. 1109 */ 1110 rtLockValidatorSerializeDetectionEnter(); 1111 1112 PRTTHREADINT pCur; 1113 unsigned cPrevLength = ~0U; 1114 unsigned cEqualRuns = 0; 1115 unsigned iParanoia = 256; 1116 do 1117 { 1118 unsigned cLength = 0; 1119 pCur = pThread; 1120 for (;;) 1121 { 1122 /* 1123 * Get the next thread. 1124 */ 1125 PRTTHREADINT pNext = NULL; 1126 for (;;) 1127 { 1128 RTTHREADSTATE enmCurState = rtThreadGetState(pCur); 1129 switch (enmCurState) 1130 { 1131 case RTTHREADSTATE_CRITSECT: 1132 case RTTHREADSTATE_EVENT: 1133 case RTTHREADSTATE_EVENT_MULTI: 1134 case RTTHREADSTATE_FAST_MUTEX: 1135 case RTTHREADSTATE_MUTEX: 1136 case RTTHREADSTATE_SPIN_MUTEX: 1137 { 1138 PRTLOCKVALIDATORREC pCurRec = pCur->LockValidator.pRec; 1139 if ( rtThreadGetState(pCur) != enmCurState 1140 || !VALID_PTR(pCurRec) 1141 || pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC) 1142 continue; 1143 pNext = pCurRec->hThread; 1144 if ( rtThreadGetState(pCur) != enmCurState 1145 || pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC 1146 || pCurRec->hThread != pNext) 1147 continue; 1148 break; 1149 } 1150 1151 #if 0 1152 case RTTHREADSTATE_RW_WRITE: 1153 { 1154 PRTLOCKVALIDATORREC pCurRec = pCur->LockValidator.pRec; 1155 if ( rtThreadGetState(pCur) != enmCurState 1156 || !VALID_PTR(pCurRec) 1157 || pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC) 1158 continue; 1159 1160 break; 1161 } 1162 1163 case RTTHREADSTATE_RW_READ: 1164 { 1165 PRTLOCKVALIDATORREC pCurRec = pCur->LockValidator.pRec; 1166 if ( rtThreadGetState(pCur) != enmCurState 1167 || !VALID_PTR(pCurRec) 1168 || pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC) 1169 continue; 1170 pNext = pCurRec->hThread; 1171 if ( rtThreadGetState(pCur) != enmCurState 1172 || pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC 1173 || pCurRec->hThread != pNext) 1174 continue; 1175 break; 1176 } 1177 #endif 1178 1179 default: 1180 pNext = NULL; 1181 break; 1182 } 1183 break; 1184 } 1185 1186 /* 1187 * If we arrive at the end of the list we're good. 1188 */ 1189 pCur = pNext; 1190 if (!pCur) 1191 { 1192 rtLockValidatorSerializeDetectionLeave(); 1193 return VINF_SUCCESS; 1194 } 1195 1196 /* 1197 * If we've got back to the blocking thread id we've 1198 * got a deadlock. 1199 */ 1200 if (pCur == pThread) 1201 break; 1202 1203 /* 1204 * If we've got a chain of more than 256 items, there is some 1205 * kind of cycle in the list, which means that there is already 1206 * a deadlock somewhere. 1207 */ 1208 if (cLength >= 256) 1209 break; 1210 1211 cLength++; 1212 } 1213 1214 /* compare with previous list run. */ 1215 if (cLength != cPrevLength) 1216 { 1217 cPrevLength = cLength; 1218 cEqualRuns = 0; 1219 } 1220 else 1221 cEqualRuns++; 1222 } while (cEqualRuns < 3 && --iParanoia > 0); 1223 1224 /* 1225 * Ok, if we ever get here, it's most likely a genuine deadlock. 1226 */ 1227 rtLockValidatorComplainAboutDeadlock(pRec, pThread, enmState, pCur, pSrcPos); 1228 1229 rtLockValidatorSerializeDetectionLeave(); 1230 1231 return VERR_SEM_LV_DEADLOCK; 1587 * Perform deadlock detection. 1588 */ 1589 if (rtLockValidatorIsSimpleNoDeadlockCase(pRecU)) 1590 return VINF_SUCCESS; 1591 return rtLockValidatorDeadlockDetection(pRecU, pThreadSelf, pSrcPos); 1232 1592 } 1233 1593 RT_EXPORT_SYMBOL(RTLockValidatorCheckBlocking); … … 1247 1607 RT_EXPORT_SYMBOL(RTLockValidatorIsEnabled); 1248 1608 1609 1610 RTDECL(bool) RTLockValidatorSetQuiet(bool fQuiet) 1611 { 1612 return ASMAtomicXchgBool(&g_fLockValidatorQuiet, fQuiet); 1613 } 1614 RT_EXPORT_SYMBOL(RTLockValidatorSetQuiet); 1615 1616 1617 RTDECL(bool) RTLockValidatorAreQuiet(void) 1618 { 1619 return ASMAtomicUoReadBool(&g_fLockValidatorQuiet); 1620 } 1621 RT_EXPORT_SYMBOL(RTLockValidatorAreQuiet); 1622 1623 1624 RTDECL(bool) RTLockValidatorSetMayPanic(bool fMayPanic) 1625 { 1626 return ASMAtomicXchgBool(&g_fLockValidatorMayPanic, fMayPanic); 1627 } 1628 RT_EXPORT_SYMBOL(RTLockValidatorSetMayPanic); 1629 1630 1631 RTDECL(bool) RTLockValidatorMayPanic(void) 1632 { 1633 return ASMAtomicUoReadBool(&g_fLockValidatorMayPanic); 1634 } 1635 RT_EXPORT_SYMBOL(RTLockValidatorMayPanic); 1636
Note:
See TracChangeset
for help on using the changeset viewer.