Changeset 25614 in vbox for trunk/src/VBox/Runtime/common
- Timestamp:
- Jan 1, 2010 2:19:06 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 56305
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp
r25611 r25614 254 254 if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet)) 255 255 { 256 RTAssertMsg1Weak("RTLockValidator", pSrcPos ->uLine, pSrcPos->pszFile, pSrcPos->pszFunction);257 if (pSrcPos ->uId)256 RTAssertMsg1Weak("RTLockValidator", pSrcPos ? pSrcPos->uLine : 0, pSrcPos ? pSrcPos->pszFile : NULL, pSrcPos ? pSrcPos->pszFunction : NULL); 257 if (pSrcPos && pSrcPos->uId) 258 258 RTAssertMsg2Weak("%s [uId=%p thrd=%s]\n", pszWhat, pSrcPos->uId, VALID_PTR(pThreadSelf) ? pThreadSelf->szName : "<NIL>"); 259 259 else 260 RTAssertMsg2Weak("%s \n", pszWhat, pSrcPos->uId);260 RTAssertMsg2Weak("%s [thrd=%s]\n", pszWhat, VALID_PTR(pThreadSelf) ? pThreadSelf->szName : "<NIL>"); 261 261 rtLockValidatorComplainAboutLock("Lock: ", pRec, "\n"); 262 262 } … … 296 296 * 297 297 * @param pDst The destination. 298 * @param pSrc The source. 298 * @param pSrc The source. Can be NULL. 299 299 */ 300 300 DECL_FORCE_INLINE(void) rtLockValidatorCopySrcPos(PRTLOCKVALSRCPOS pDst, PCRTLOCKVALSRCPOS pSrc) 301 301 { 302 ASMAtomicUoWriteU32(&pDst->uLine, pSrc->uLine); 303 ASMAtomicUoWritePtr((void * volatile *)&pDst->pszFile, pSrc->pszFile); 304 ASMAtomicUoWritePtr((void * volatile *)&pDst->pszFunction, pSrc->pszFunction); 305 ASMAtomicUoWritePtr((void * volatile *)&pDst->uId, (void *)pSrc->uId); 302 if (pSrc) 303 { 304 ASMAtomicUoWriteU32(&pDst->uLine, pSrc->uLine); 305 ASMAtomicUoWritePtr((void * volatile *)&pDst->pszFile, pSrc->pszFile); 306 ASMAtomicUoWritePtr((void * volatile *)&pDst->pszFunction, pSrc->pszFunction); 307 ASMAtomicUoWritePtr((void * volatile *)&pDst->uId, (void *)pSrc->uId); 308 } 309 else 310 { 311 ASMAtomicUoWriteU32(&pDst->uLine, 0); 312 ASMAtomicUoWritePtr((void * volatile *)&pDst->pszFile, NULL); 313 ASMAtomicUoWritePtr((void * volatile *)&pDst->pszFunction, NULL); 314 ASMAtomicUoWritePtr((void * volatile *)&pDst->uId, 0); 315 } 306 316 } 307 317 … … 382 392 Assert(pPerThread->cWriteLocks == 0); 383 393 Assert(pPerThread->cReadLocks == 0); 394 } 395 396 397 /** 398 * Verifies the deadlock stack before calling it a deadlock. 399 * 400 * @retval VERR_SEM_LV_DEADLOCK if it's a deadlock. 401 * @retval VERR_SEM_LV_ILLEGAL_UPGRADE if it's a deadlock on the same lock. 402 * @retval VERR_TRY_AGAIN if something changed. 403 * 404 * @param pStack The deadlock detection stack. 405 */ 406 static int rtLockValidatorDdVerifyDeadlock(PRTLOCKVALDDSTACK pStack) 407 { 408 uint32_t const c = pStack->c; 409 for (uint32_t iPass = 0; iPass < 3; iPass++) 410 { 411 for (uint32_t i = 1; i < c; i++) 412 { 413 PRTTHREADINT pThread = pStack->a[i].pThread; 414 if (pThread->u32Magic != RTTHREADINT_MAGIC) 415 return VERR_TRY_AGAIN; 416 if (rtThreadGetState(pThread) != pStack->a[i].enmState) 417 return VERR_TRY_AGAIN; 418 if (rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pRec) != pStack->a[i].pFirstSibling) 419 return VERR_TRY_AGAIN; 420 } 421 RTThreadYield(); 422 } 423 424 if (c == 1) 425 return VERR_SEM_LV_ILLEGAL_UPGRADE; 426 return VERR_SEM_LV_DEADLOCK; 427 } 428 429 430 /** 431 * Checks for stack cycles caused by another deadlock before returning. 432 * 433 * @retval VINF_SUCCESS if the stack is simply too small. 434 * @retval VERR_SEM_LV_EXISTING_DEADLOCK if a cycle was detected. 435 * 436 * @param pStack The deadlock detection stack. 437 */ 438 static int rtLockValidatorDdHandleStackOverflow(PRTLOCKVALDDSTACK pStack) 439 { 440 for (size_t i = 0; i < RT_ELEMENTS(pStack->a) - 1; i++) 441 { 442 PRTTHREADINT pThread = pStack->a[i].pThread; 443 for (size_t j = i + 1; j < RT_ELEMENTS(pStack->a); j++) 444 if (pStack->a[j].pThread == pThread) 445 return VERR_SEM_LV_EXISTING_DEADLOCK; 446 } 447 static bool volatile s_fComplained = false; 448 if (!s_fComplained) 449 { 450 s_fComplained = true; 451 rtLockValidatorComplain(RT_SRC_POS, "lock validator stack is too small! (%zu entries)\n", RT_ELEMENTS(pStack->a)); 452 } 453 return VINF_SUCCESS; 454 } 455 456 457 /** 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 /** 491 * Worker for rtLockValidatorDeadlockDetection that does the actual deadlock 492 * detection. 493 * 494 * @retval VINF_SUCCESS 495 * @retval VERR_SEM_LV_DEADLOCK 496 * @retval VERR_SEM_LV_EXISTING_DEADLOCK 497 * @retval VERR_SEM_LV_ILLEGAL_UPGRADE 498 * @retval VERR_TRY_AGAIN 499 * 500 * @param pStack The stack to use. 501 * @param pOriginalRec The original record. 502 * @param pThreadSelf The calling thread. 503 */ 504 static int rtLockValidatorDdDoDetection(PRTLOCKVALDDSTACK pStack, PRTLOCKVALRECUNION const pOriginalRec, 505 PRTTHREADINT const pThreadSelf) 506 { 507 pStack->c = 0; 508 509 /* We could use a single RTLOCKVALDDENTRY variable here, but the 510 compiler may make a better job of it when using individual variables. */ 511 PRTLOCKVALRECUNION pRec = pOriginalRec; 512 PRTLOCKVALRECUNION pFirstSibling = pOriginalRec; 513 uint32_t iEntry = UINT32_MAX; 514 PRTTHREADINT pThread = NIL_RTTHREAD; 515 RTTHREADSTATE enmState = RTTHREADSTATE_RUNNING; 516 for (;;) 517 { 518 /* 519 * Process the current record. 520 */ 521 /* Find the next relevant owner thread. */ 522 PRTTHREADINT pNextThread; 523 switch (pRec->Core.u32Magic) 524 { 525 case RTLOCKVALRECEXCL_MAGIC: 526 Assert(iEntry == UINT32_MAX); 527 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) 537 { 538 pRec = pRec->Excl.pSibling; 539 continue; 540 } 541 break; 542 543 case RTLOCKVALRECSHRD_MAGIC: 544 /* Skip to the next sibling if same side. ASSUMES reader priority. */ 545 /** @todo The read side of a read-write lock is problematic if 546 * the implementation prioritizes writers over readers because 547 * that means we should could deadlock against current readers 548 * if a writer showed up. If the RW sem implementation is 549 * wrapping some native API, it's not so easy to detect when we 550 * should do this and when we shouldn't. Checking when we 551 * shouldn't is subject to wakeup scheduling and cannot easily 552 * be made reliable. 553 * 554 * At the moment we circumvent all this mess by declaring that 555 * readers has priority. This is TRUE on linux, but probably 556 * isn't on Solaris and FreeBSD. */ 557 if ( pRec == pFirstSibling 558 && pRec->Shared.pSibling != NULL 559 && pRec->Shared.pSibling != pFirstSibling) 560 { 561 pRec = pRec->Shared.pSibling; 562 Assert(iEntry == UINT32_MAX); 563 continue; 564 } 565 566 /* Scan the owner table for blocked owners. */ 567 pNextThread = NIL_RTTHREAD; 568 if (ASMAtomicUoReadU32(&pRec->Shared.cEntries) > 0) 569 { 570 uint32_t cAllocated = ASMAtomicUoReadU32(&pRec->Shared.cAllocated); 571 PRTLOCKVALRECSHRDOWN volatile *papOwners = pRec->Shared.papOwners; 572 while (++iEntry < cAllocated) 573 { 574 PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorUoReadSharedOwner(&papOwners[iEntry]); 575 if ( pEntry 576 && pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC) 577 { 578 pNextThread = rtLockValidatorReadThreadHandle(&pEntry->hThread); 579 if (pNextThread) 580 { 581 if ( pNextThread->u32Magic == RTTHREADINT_MAGIC 582 && ( RTTHREAD_IS_SLEEPING(pNextThread->enmState) 583 || pNextThread == pThreadSelf)) 584 break; 585 pNextThread = NIL_RTTHREAD; 586 } 587 } 588 else 589 Assert(!pEntry || pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC_DEAD); 590 } 591 if (pNextThread == NIL_RTTHREAD) 592 break; 593 } 594 595 /* Advance to the next sibling, if any. */ 596 if ( pRec->Shared.pSibling != NULL 597 && pRec->Shared.pSibling != pFirstSibling) 598 { 599 pRec = pRec->Shared.pSibling; 600 iEntry = UINT32_MAX; 601 continue; 602 } 603 break; 604 605 case RTLOCKVALRECEXCL_MAGIC_DEAD: 606 case RTLOCKVALRECSHRD_MAGIC_DEAD: 607 pNextThread = NIL_RTTHREAD; 608 break; 609 610 case RTLOCKVALRECSHRDOWN_MAGIC: 611 case RTLOCKVALRECSHRDOWN_MAGIC_DEAD: 612 default: 613 AssertMsgFailed(("%p: %#x\n", pRec, pRec->Core)); 614 pNextThread = NIL_RTTHREAD; 615 break; 616 } 617 618 /* If we found a thread, check if it is still waiting for something. */ 619 RTTHREADSTATE enmNextState = RTTHREADSTATE_RUNNING; 620 PRTLOCKVALRECUNION pNextRec = NULL; 621 if ( pNextThread != NIL_RTTHREAD 622 && RT_LIKELY(pNextThread->u32Magic == RTTHREADINT_MAGIC)) 623 { 624 do 625 { 626 enmNextState = rtThreadGetState(pNextThread); 627 if ( !RTTHREAD_IS_SLEEPING(enmNextState) 628 && pNextThread != pThreadSelf) 629 break; 630 pNextRec = rtLockValidatorReadRecUnionPtr(&pNextThread->LockValidator.pRec); 631 if (RT_LIKELY( !pNextRec 632 || enmNextState == rtThreadGetState(pNextThread))) 633 break; 634 pNextRec = NULL; 635 } while (pNextThread->u32Magic == RTTHREADINT_MAGIC); 636 } 637 if (pNextRec) 638 { 639 /* 640 * Recurse and check for deadlock. 641 */ 642 uint32_t i = pStack->c; 643 if (RT_UNLIKELY(i >= RT_ELEMENTS(pStack->a))) 644 return rtLockValidatorDdHandleStackOverflow(pStack); 645 646 pStack->c++; 647 pStack->a[i].pRec = pRec; 648 pStack->a[i].iEntry = iEntry; 649 pStack->a[i].enmState = enmState; 650 pStack->a[i].pThread = pThread; 651 pStack->a[i].pFirstSibling = pFirstSibling; 652 653 if (RT_UNLIKELY(pNextThread == pThreadSelf)) 654 return rtLockValidatorDdVerifyDeadlock(pStack); 655 656 pRec = pNextRec; 657 pFirstSibling = pNextRec; 658 iEntry = UINT32_MAX; 659 enmState = enmNextState; 660 pThread = pNextThread; 661 } 662 else if (RT_LIKELY(!pNextThread)) 663 { 664 /* 665 * No deadlock here, unwind the stack and deal with any unfinished 666 * business there. 667 */ 668 uint32_t i = pStack->c; 669 for (;;) 670 { 671 /* pop */ 672 if (i == 0) 673 return VINF_SUCCESS; 674 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)) 681 { 682 enmState = pStack->a[i].enmState; 683 pThread = pStack->a[i].pThread; 684 pStack->c = i; 685 break; 686 } 687 } 688 } 689 /* else: see if there is another thread to check for this lock. */ 690 } 691 } 692 693 694 /** 695 * Check for the simple no-deadlock case. 696 * 697 * @returns true if no deadlock, false if further investigation is required. 698 * 699 * @param pOriginalRec The original record. 700 */ 701 DECLINLINE(int) rtLockValidatorIsSimpleNoDeadlockCase(PRTLOCKVALRECUNION pOriginalRec) 702 { 703 if ( pOriginalRec->Excl.Core.u32Magic == RTLOCKVALRECEXCL_MAGIC 704 && !pOriginalRec->Excl.pSibling) 705 { 706 PRTTHREADINT pThread = rtLockValidatorReadThreadHandle(&pOriginalRec->Excl.hThread); 707 if ( !pThread 708 || pThread->u32Magic != RTTHREADINT_MAGIC) 709 return true; 710 RTTHREADSTATE enmState = rtThreadGetState(pThread); 711 if (!RTTHREAD_IS_SLEEPING(enmState)) 712 return true; 713 } 714 return false; 715 } 716 717 718 /** 719 * Worker for rtLockValidatorDeadlockDetection that bitches about a deadlock. 720 * 721 * @param pStack The chain of locks causing the deadlock. 722 * @param pRec The record relating to the current thread's lock 723 * operation. 724 * @param pThreadSelf This thread. 725 * @param pSrcPos Where we are going to deadlock. 726 * @param rc The return code. 727 */ 728 static void rcLockValidatorDoDeadlockComplaining(PRTLOCKVALDDSTACK pStack, PRTLOCKVALRECUNION pRec, 729 PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos, int rc) 730 { 731 if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet)) 732 { 733 const char *pszWhat; 734 switch (rc) 735 { 736 case VERR_SEM_LV_DEADLOCK: pszWhat = "Detected deadlock!"; break; 737 case VERR_SEM_LV_EXISTING_DEADLOCK: pszWhat = "Found existing deadlock!"; break; 738 case VERR_SEM_LV_ILLEGAL_UPGRADE: pszWhat = "Illegal lock upgrade!"; break; 739 default: AssertFailed(); pszWhat = "!unexpected rc!"; break; 740 } 741 rtLockValidatorComplainFirst(pszWhat, pSrcPos, pThreadSelf, pStack->a[0].pRec != pRec ? pRec : NULL); 742 rtLockValidatorComplainMore("---- start of deadlock chain - %u entries ----\n", pStack->c); 743 for (uint32_t i = 0; i < pStack->c; i++) 744 { 745 char szPrefix[24]; 746 RTStrPrintf(szPrefix, sizeof(szPrefix), "#%02u: ", i); 747 PRTLOCKVALRECSHRDOWN pShrdOwner = NULL; 748 if (pStack->a[i].pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC) 749 pShrdOwner = pStack->a[i].pRec->Shared.papOwners[pStack->a[i].iEntry]; 750 if (VALID_PTR(pShrdOwner) && pShrdOwner->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC) 751 rtLockValidatorComplainAboutLock(szPrefix, (PRTLOCKVALRECUNION)pShrdOwner, "\n"); 752 else 753 rtLockValidatorComplainAboutLock(szPrefix, pStack->a[i].pRec, "\n"); 754 } 755 rtLockValidatorComplainMore("---- end of deadlock chain ----\n"); 756 } 757 758 rtLockValidatorComplainPanic(); 759 } 760 761 762 /** 763 * Perform deadlock detection. 764 * 765 * @retval VINF_SUCCESS 766 * @retval VERR_SEM_LV_DEADLOCK 767 * @retval VERR_SEM_LV_EXISTING_DEADLOCK 768 * @retval VERR_SEM_LV_ILLEGAL_UPGRADE 769 * 770 * @param pRec The record relating to the current thread's lock 771 * operation. 772 * @param pThreadSelf The current thread. 773 * @param pSrcPos The position of the current lock operation. 774 */ 775 static int rtLockValidatorDeadlockDetection(PRTLOCKVALRECUNION pRec, PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos) 776 { 777 #ifdef DEBUG_bird 778 RTLOCKVALDDSTACK Stack; 779 int rc = rtLockValidatorDdDoDetection(&Stack, pRec, pThreadSelf); 780 if (RT_SUCCESS(rc)) 781 return VINF_SUCCESS; 782 783 if (rc == VERR_TRY_AGAIN) 784 { 785 for (uint32_t iLoop = 0; ; iLoop++) 786 { 787 rc = rtLockValidatorDdDoDetection(&Stack, pRec, pThreadSelf); 788 if (RT_SUCCESS_NP(rc)) 789 return VINF_SUCCESS; 790 if (rc != VERR_TRY_AGAIN) 791 break; 792 RTThreadYield(); 793 if (iLoop >= 3) 794 return VINF_SUCCESS; 795 } 796 } 797 798 rcLockValidatorDoDeadlockComplaining(&Stack, pRec, pThreadSelf, pSrcPos, rc); 799 return rc; 800 #else 801 return VINF_SUCCESS; 802 #endif 384 803 } 385 804 … … 539 958 540 959 960 RTDECL(void) RTLockValidatorRecExclSetOwner(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, 961 PCRTLOCKVALSRCPOS pSrcPos, bool fFirstRecursion) 962 { 963 AssertReturnVoid(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC); 964 if (!pRec->fEnabled) 965 return; 966 if (hThreadSelf == NIL_RTTHREAD) 967 { 968 hThreadSelf = RTThreadSelfAutoAdopt(); 969 AssertReturnVoid(hThreadSelf != NIL_RTTHREAD); 970 } 971 Assert(hThreadSelf == RTThreadSelf()); 972 973 ASMAtomicIncS32(&hThreadSelf->LockValidator.cWriteLocks); 974 975 if (pRec->hThread == hThreadSelf) 976 { 977 Assert(!fFirstRecursion); 978 pRec->cRecursion++; 979 } 980 else 981 { 982 Assert(pRec->hThread == NIL_RTTHREAD); 983 984 /* 985 * Update the record. 986 */ 987 rtLockValidatorCopySrcPos(&pRec->SrcPos, pSrcPos); 988 ASMAtomicUoWriteU32(&pRec->cRecursion, 1); 989 ASMAtomicWriteHandle(&pRec->hThread, hThreadSelf); 990 991 /* 992 * Push the lock onto the lock stack. 993 */ 994 /** @todo push it onto the per-thread lock stack. */ 995 } 996 } 997 998 999 RTDECL(int) RTLockValidatorRecExclReleaseOwner(PRTLOCKVALRECEXCL pRec, bool fFinalRecursion) 1000 { 1001 AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1002 if (!pRec->fEnabled) 1003 return VINF_SUCCESS; 1004 AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER); 1005 1006 RTLockValidatorRecExclReleaseOwnerUnchecked(pRec); 1007 return VINF_SUCCESS; 1008 } 1009 1010 1011 RTDECL(void) RTLockValidatorRecExclReleaseOwnerUnchecked(PRTLOCKVALRECEXCL pRec) 1012 { 1013 AssertReturnVoid(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC); 1014 if (!pRec->fEnabled) 1015 return; 1016 RTTHREADINT *pThread = pRec->hThread; 1017 AssertReturnVoid(pThread != NIL_RTTHREAD); 1018 Assert(pThread == RTThreadSelf()); 1019 1020 ASMAtomicDecS32(&pThread->LockValidator.cWriteLocks); 1021 1022 if (ASMAtomicDecU32(&pRec->cRecursion) == 0) 1023 { 1024 /* 1025 * Pop (remove) the lock. 1026 */ 1027 /** @todo remove it from the per-thread stack/whatever. */ 1028 1029 /* 1030 * Update the record. 1031 */ 1032 ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD); 1033 } 1034 } 1035 1036 1037 RTDECL(int) RTLockValidatorRecExclRecursion(PRTLOCKVALRECEXCL pRec, PCRTLOCKVALSRCPOS pSrcPos) 1038 { 1039 AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1040 if (!pRec->fEnabled) 1041 return VINF_SUCCESS; 1042 AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER); 1043 1044 Assert(pRec->cRecursion < _1M); 1045 pRec->cRecursion++; 1046 1047 return VINF_SUCCESS; 1048 } 1049 1050 1051 RTDECL(int) RTLockValidatorRecExclUnwind(PRTLOCKVALRECEXCL pRec) 1052 { 1053 AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1054 if (!pRec->fEnabled) 1055 return VINF_SUCCESS; 1056 AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER); 1057 AssertReturn(pRec->cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER); 1058 1059 Assert(pRec->cRecursion); 1060 pRec->cRecursion--; 1061 return VINF_SUCCESS; 1062 } 1063 1064 1065 RTDECL(int) RTLockValidatorRecExclRecursionMixed(PRTLOCKVALRECEXCL pRec, PRTLOCKVALRECCORE pRecMixed, PCRTLOCKVALSRCPOS pSrcPos) 1066 { 1067 AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1068 PRTLOCKVALRECUNION pRecMixedU = (PRTLOCKVALRECUNION)pRecMixed; 1069 AssertReturn( pRecMixedU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC 1070 || pRecMixedU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC 1071 , VERR_SEM_LV_INVALID_PARAMETER); 1072 if (!pRec->fEnabled) 1073 return VINF_SUCCESS; 1074 AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER); 1075 AssertReturn(pRec->cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER); 1076 1077 Assert(pRec->cRecursion < _1M); 1078 pRec->cRecursion++; 1079 1080 return VINF_SUCCESS; 1081 } 1082 1083 1084 RTDECL(int) RTLockValidatorRecExclUnwindMixed(PRTLOCKVALRECEXCL pRec, PRTLOCKVALRECCORE pRecMixed) 1085 { 1086 AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1087 PRTLOCKVALRECUNION pRecMixedU = (PRTLOCKVALRECUNION)pRecMixed; 1088 AssertReturn( pRecMixedU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC 1089 || pRecMixedU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC 1090 , VERR_SEM_LV_INVALID_PARAMETER); 1091 if (!pRec->fEnabled) 1092 return VINF_SUCCESS; 1093 AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER); 1094 AssertReturn(pRec->cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER); 1095 1096 Assert(pRec->cRecursion); 1097 pRec->cRecursion--; 1098 return VINF_SUCCESS; 1099 } 1100 1101 1102 RTDECL(int) RTLockValidatorRecExclCheckOrder(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, PCRTLOCKVALSRCPOS pSrcPos) 1103 { 1104 AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1105 if (!pRec->fEnabled) 1106 return VINF_SUCCESS; 1107 1108 /* 1109 * Check it locks we're currently holding. 1110 */ 1111 /** @todo later */ 1112 1113 /* 1114 * If missing order rules, add them. 1115 */ 1116 1117 return VINF_SUCCESS; 1118 } 1119 1120 1121 RTDECL(int) RTLockValidatorRecExclCheckBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, 1122 PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk) 1123 { 1124 /* 1125 * Fend off wild life. 1126 */ 1127 PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec; 1128 AssertPtrReturn(pRecU, VERR_SEM_LV_INVALID_PARAMETER); 1129 AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1130 if (!pRecU->Excl.fEnabled) 1131 return VINF_SUCCESS; 1132 1133 PRTTHREADINT pThreadSelf = hThreadSelf; 1134 AssertPtrReturn(pThreadSelf, VERR_SEM_LV_INVALID_PARAMETER); 1135 AssertReturn(pThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1136 Assert(pThreadSelf == RTThreadSelf()); 1137 1138 RTTHREADSTATE enmThreadState = rtThreadGetState(pThreadSelf); 1139 AssertReturn( enmThreadState == RTTHREADSTATE_RUNNING 1140 || enmThreadState == RTTHREADSTATE_TERMINATED /* rtThreadRemove uses locks too */ 1141 || enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */ 1142 , VERR_SEM_LV_INVALID_PARAMETER); 1143 1144 /* 1145 * Record the location. 1146 */ 1147 rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, pRecU); 1148 rtLockValidatorCopySrcPos(&pThreadSelf->LockValidator.SrcPos, pSrcPos); 1149 1150 /* 1151 * Don't do deadlock detection if we're recursing. 1152 * 1153 * On some hosts we don't do recursion accounting our selves and there 1154 * isn't any other place to check for this. semmutex-win.cpp for instance. 1155 */ 1156 if (rtLockValidatorReadThreadHandle(&pRecU->Excl.hThread) == pThreadSelf) 1157 { 1158 if (fRecursiveOk) 1159 return VINF_SUCCESS; 1160 rtLockValidatorComplainFirst("Recursion not allowed", pSrcPos, pThreadSelf, pRecU); 1161 rtLockValidatorComplainPanic(); 1162 return VERR_SEM_LV_NESTED; 1163 } 1164 1165 /* 1166 * Perform deadlock detection. 1167 */ 1168 if (rtLockValidatorIsSimpleNoDeadlockCase(pRecU)) 1169 return VINF_SUCCESS; 1170 return rtLockValidatorDeadlockDetection(pRecU, pThreadSelf, pSrcPos); 1171 } 1172 RT_EXPORT_SYMBOL(RTLockValidatorRecExclCheckBlocking); 1173 1174 1175 RTDECL(int) RTLockValidatorRecExclCheckOrderAndBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf, 1176 PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk) 1177 { 1178 int rc = RTLockValidatorRecExclCheckOrder(pRec, hThreadSelf, pSrcPos); 1179 if (RT_SUCCESS(rc)) 1180 rc = RTLockValidatorRecExclCheckBlocking(pRec, hThreadSelf, pSrcPos, fRecursiveOk); 1181 return rc; 1182 } 1183 RT_EXPORT_SYMBOL(RTLockValidatorRecExclCheckOrderAndBlocking); 1184 1185 541 1186 RTDECL(void) RTLockValidatorRecSharedInit(PRTLOCKVALRECSHRD pRec, RTLOCKVALIDATORCLASS hClass, 542 1187 uint32_t uSubClass, const char *pszName, void *hLock) … … 636 1281 637 1282 1283 RTDECL(int) RTLockValidatorRecSharedCheckOrder(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, PCRTLOCKVALSRCPOS pSrcPos) 1284 { 1285 AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1286 if (!pRec->fEnabled) 1287 return VINF_SUCCESS; 1288 Assert(hThreadSelf == NIL_RTTHREAD || hThreadSelf == RTThreadSelf()); 1289 1290 /* 1291 * Check it locks we're currently holding. 1292 */ 1293 /** @todo later */ 1294 1295 /* 1296 * If missing order rules, add them. 1297 */ 1298 1299 return VINF_SUCCESS; 1300 } 1301 1302 1303 RTDECL(int) RTLockValidatorRecSharedCheckBlocking(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, 1304 PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk) 1305 { 1306 /* 1307 * Fend off wild life. 1308 */ 1309 PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec; 1310 AssertPtrReturn(pRecU, VERR_SEM_LV_INVALID_PARAMETER); 1311 AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1312 if (!pRecU->Shared.fEnabled) 1313 return VINF_SUCCESS; 1314 1315 PRTTHREADINT pThreadSelf = hThreadSelf; 1316 AssertPtrReturn(pThreadSelf, VERR_SEM_LV_INVALID_PARAMETER); 1317 AssertReturn(pThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1318 Assert(pThreadSelf == RTThreadSelf()); 1319 1320 RTTHREADSTATE enmThreadState = rtThreadGetState(pThreadSelf); 1321 AssertReturn( enmThreadState == RTTHREADSTATE_RUNNING 1322 || enmThreadState == RTTHREADSTATE_TERMINATED /* rtThreadRemove uses locks too */ 1323 || enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */ 1324 , VERR_SEM_LV_INVALID_PARAMETER); 1325 1326 /* 1327 * Record the location. 1328 */ 1329 rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, pRecU); 1330 rtLockValidatorCopySrcPos(&pThreadSelf->LockValidator.SrcPos, pSrcPos); 1331 1332 /* 1333 * Don't do deadlock detection if we're recursing. 1334 */ 1335 PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(&pRecU->Shared, pThreadSelf, NULL); 1336 if (pEntry) 1337 { 1338 if (fRecursiveOk) 1339 return VINF_SUCCESS; 1340 rtLockValidatorComplainFirst("Recursion not allowed", pSrcPos, pThreadSelf, pRecU); 1341 rtLockValidatorComplainPanic(); 1342 return VERR_SEM_LV_NESTED; 1343 } 1344 1345 /* 1346 * Perform deadlock detection. 1347 */ 1348 if (rtLockValidatorIsSimpleNoDeadlockCase(pRecU)) 1349 return VINF_SUCCESS; 1350 return rtLockValidatorDeadlockDetection(pRecU, pThreadSelf, pSrcPos); 1351 } 1352 RT_EXPORT_SYMBOL(RTLockValidatorRecSharedCheckBlocking); 1353 1354 1355 RTDECL(int) RTLockValidatorRecSharedCheckOrderAndBlocking(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk) 1356 { 1357 int rc = RTLockValidatorRecSharedCheckOrder(pRec, hThreadSelf, pSrcPos); 1358 if (RT_SUCCESS(rc)) 1359 rc = RTLockValidatorRecSharedCheckBlocking(pRec, hThreadSelf, pSrcPos, fRecursiveOk); 1360 return rc; 1361 } 1362 RT_EXPORT_SYMBOL(RTLockValidatorRecSharedCheckOrderAndBlocking); 1363 1364 638 1365 /** 639 1366 * Allocates and initializes an owner entry for the shared lock record. … … 657 1384 { 658 1385 iEntry--; 659 pThreadSelf->LockValidator.bmFreeShrdOwners |=RT_BIT_32(iEntry);1386 pThreadSelf->LockValidator.bmFreeShrdOwners &= ~RT_BIT_32(iEntry); 660 1387 pEntry = &pThreadSelf->LockValidator.aShrdOwners[iEntry]; 661 1388 Assert(!pEntry->fReserved); … … 702 1429 Assert(pThreadSelf == RTThreadSelf()); 703 1430 1431 Assert(pEntry->fReserved); 704 1432 pEntry->fReserved = false; 705 1433 706 Assert(pEntry->fReserved);707 1434 if (pEntry->fStaticAlloc) 708 1435 { 709 1436 uintptr_t iEntry = pEntry - &pThreadSelf->LockValidator.aShrdOwners[0]; 710 1437 AssertReleaseReturnVoid(iEntry < RT_ELEMENTS(pThreadSelf->LockValidator.aShrdOwners)); 711 pThreadSelf->LockValidator.bmFreeShrdOwners &= ~RT_BIT_32(iEntry);1438 pThreadSelf->LockValidator.bmFreeShrdOwners |= RT_BIT_32(iEntry); 712 1439 } 713 1440 else … … 876 1603 877 1604 878 RTDECL( int) RTLockValidatorCheckOrder(PRTLOCKVALRECEXCL pRec, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos)879 { 880 AssertReturn (pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);1605 RTDECL(void) RTLockValidatorSharedRecAddOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf, PCRTLOCKVALSRCPOS pSrcPos) 1606 { 1607 AssertReturnVoid(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC); 881 1608 if (!pRec->fEnabled) 882 return VINF_SUCCESS; 883 884 /* 885 * Check it locks we're currently holding. 886 */ 887 /** @todo later */ 888 889 /* 890 * If missing order rules, add them. 891 */ 892 893 return VINF_SUCCESS; 894 } 895 896 897 RTDECL(int) RTLockValidatorCheckAndRelease(PRTLOCKVALRECEXCL pRec) 898 { 899 AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 1609 return; 1610 AssertReturnVoid(hThreadSelf != NIL_RTTHREAD); 1611 AssertReturnVoid(hThreadSelf->u32Magic == RTTHREADINT_MAGIC); 1612 Assert(hThreadSelf == RTThreadSelf()); 1613 1614 /* 1615 * Recursive? 1616 * 1617 * Note! This code can be optimized to try avoid scanning the table on 1618 * insert. However, that's annoying work that makes the code big, 1619 * so it can wait til later sometime. 1620 */ 1621 PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(pRec, hThreadSelf, NULL); 1622 if (pEntry) 1623 { 1624 pEntry->cRecursion++; 1625 return; 1626 } 1627 1628 /* 1629 * Allocate a new owner entry and insert it into the table. 1630 */ 1631 pEntry = rtLockValidatorRecSharedAllocOwner(pRec, hThreadSelf, pSrcPos); 1632 if ( pEntry 1633 && !rtLockValidatorRecSharedAddOwner(pRec, pEntry)) 1634 rtLockValidatorRecSharedFreeOwner(pEntry); 1635 } 1636 RT_EXPORT_SYMBOL(RTLockValidatorSharedRecAddOwner); 1637 1638 1639 RTDECL(void) RTLockValidatorSharedRecRemoveOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf) 1640 { 1641 AssertReturnVoid(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC); 900 1642 if (!pRec->fEnabled) 901 return VINF_SUCCESS; 902 AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER); 903 904 RTLockValidatorUnsetOwner(pRec); 905 return VINF_SUCCESS; 906 } 907 908 909 RTDECL(int) RTLockValidatorCheckAndReleaseReadOwner(PRTLOCKVALRECSHRD pRead, RTTHREAD hThread) 1643 return; 1644 AssertReturnVoid(hThreadSelf != NIL_RTTHREAD); 1645 AssertReturnVoid(hThreadSelf->u32Magic == RTTHREADINT_MAGIC); 1646 Assert(hThreadSelf == RTThreadSelf()); 1647 1648 /* 1649 * Find the entry hope it's a recursive one. 1650 */ 1651 uint32_t iEntry = UINT32_MAX; /* shuts up gcc */ 1652 PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(pRec, hThreadSelf, &iEntry); 1653 AssertReturnVoid(pEntry); 1654 if (pEntry->cRecursion > 1) 1655 pEntry->cRecursion--; 1656 else 1657 rtLockValidatorRecSharedRemoveAndFreeOwner(pRec, pEntry, iEntry); 1658 } 1659 RT_EXPORT_SYMBOL(RTLockValidatorSharedRecRemoveOwner); 1660 1661 1662 RTDECL(int) RTLockValidatorRecSharedCheckAndRelease(PRTLOCKVALRECSHRD pRead, RTTHREAD hThreadSelf) 910 1663 { 911 1664 AssertReturn(pRead->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER); 912 1665 if (!pRead->fEnabled) 913 1666 return VINF_SUCCESS; 914 AssertReturn(hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER); 1667 if (hThreadSelf == NIL_RTTHREAD) 1668 { 1669 hThreadSelf = RTThreadSelfAutoAdopt(); 1670 AssertReturn(hThreadSelf != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER); 1671 } 1672 Assert(hThreadSelf == RTThreadSelf()); 915 1673 916 1674 /* … … 918 1676 */ 919 1677 uint32_t iEntry = 0; 920 PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(pRead, hThread , &iEntry);1678 PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(pRead, hThreadSelf, &iEntry); 921 1679 AssertReturn(pEntry, VERR_SEM_LV_NOT_OWNER); 922 1680 … … 939 1697 940 1698 return VINF_SUCCESS; 941 }942 943 944 RTDECL(int) RTLockValidatorRecordRecursion(PRTLOCKVALRECEXCL pRec, PCRTLOCKVALSRCPOS pSrcPos)945 {946 AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);947 if (!pRec->fEnabled)948 return VINF_SUCCESS;949 AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);950 951 Assert(pRec->cRecursion < _1M);952 pRec->cRecursion++;953 954 return VINF_SUCCESS;955 }956 957 958 RTDECL(int) RTLockValidatorUnwindRecursion(PRTLOCKVALRECEXCL pRec)959 {960 AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);961 if (!pRec->fEnabled)962 return VINF_SUCCESS;963 AssertReturn(pRec->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);964 AssertReturn(pRec->cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER);965 966 Assert(pRec->cRecursion);967 pRec->cRecursion--;968 return VINF_SUCCESS;969 }970 971 972 RTDECL(int) RTLockValidatorRecordReadWriteRecursion(PRTLOCKVALRECEXCL pWrite, PRTLOCKVALRECSHRD pRead, PCRTLOCKVALSRCPOS pSrcPos)973 {974 AssertReturn(pWrite->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);975 AssertReturn(pRead->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);976 AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER);977 if (!pWrite->fEnabled)978 return VINF_SUCCESS;979 AssertReturn(pWrite->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);980 AssertReturn(pWrite->cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER);981 982 Assert(pWrite->cRecursion < _1M);983 pWrite->cRecursion++;984 985 return VINF_SUCCESS;986 }987 988 989 RTDECL(int) RTLockValidatorUnwindReadWriteRecursion(PRTLOCKVALRECEXCL pWrite, PRTLOCKVALRECSHRD pRead)990 {991 AssertReturn(pWrite->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);992 AssertReturn(pRead->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);993 AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER);994 if (!pWrite->fEnabled)995 return VINF_SUCCESS;996 AssertReturn(pWrite->hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);997 AssertReturn(pWrite->cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER);998 999 Assert(pWrite->cRecursion);1000 pWrite->cRecursion--;1001 return VINF_SUCCESS;1002 }1003 1004 1005 RTDECL(RTTHREAD) RTLockValidatorSetOwner(PRTLOCKVALRECEXCL pRec, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos)1006 {1007 AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, NIL_RTTHREAD);1008 if (!pRec->fEnabled)1009 return VINF_SUCCESS;1010 if (hThread == NIL_RTTHREAD)1011 {1012 hThread = RTThreadSelfAutoAdopt();1013 AssertReturn(hThread != NIL_RTTHREAD, hThread);1014 }1015 1016 ASMAtomicIncS32(&hThread->LockValidator.cWriteLocks);1017 1018 if (pRec->hThread == hThread)1019 pRec->cRecursion++;1020 else1021 {1022 Assert(pRec->hThread == NIL_RTTHREAD);1023 1024 /*1025 * Update the record.1026 */1027 rtLockValidatorCopySrcPos(&pRec->SrcPos, pSrcPos);1028 ASMAtomicUoWriteU32(&pRec->cRecursion, 1);1029 ASMAtomicWriteHandle(&pRec->hThread, hThread);1030 1031 /*1032 * Push the lock onto the lock stack.1033 */1034 /** @todo push it onto the per-thread lock stack. */1035 }1036 1037 return hThread;1038 }1039 1040 1041 RTDECL(RTTHREAD) RTLockValidatorUnsetOwner(PRTLOCKVALRECEXCL pRec)1042 {1043 AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, NIL_RTTHREAD);1044 if (!pRec->fEnabled)1045 return VINF_SUCCESS;1046 RTTHREADINT *pThread = pRec->hThread;1047 AssertReturn(pThread != NIL_RTTHREAD, pThread);1048 1049 ASMAtomicDecS32(&pThread->LockValidator.cWriteLocks);1050 1051 if (ASMAtomicDecU32(&pRec->cRecursion) == 0)1052 {1053 /*1054 * Pop (remove) the lock.1055 */1056 /** @todo remove it from the per-thread stack/whatever. */1057 1058 /*1059 * Update the record.1060 */1061 ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD);1062 }1063 1064 return pThread;1065 }1066 1067 1068 RTDECL(void) RTLockValidatorAddReadOwner(PRTLOCKVALRECSHRD pRead, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos)1069 {1070 AssertReturnVoid(pRead->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC);1071 if (!pRead->fEnabled)1072 return;1073 AssertReturnVoid(hThread != NIL_RTTHREAD);1074 AssertReturnVoid(hThread->u32Magic == RTTHREADINT_MAGIC);1075 1076 /*1077 * Recursive?1078 *1079 * Note! This code can be optimized to try avoid scanning the table on1080 * insert. However, that's annoying work that makes the code big,1081 * so it can wait til later sometime.1082 */1083 PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(pRead, hThread, NULL);1084 if (pEntry)1085 {1086 pEntry->cRecursion++;1087 return;1088 }1089 1090 /*1091 * Allocate a new owner entry and insert it into the table.1092 */1093 pEntry = rtLockValidatorRecSharedAllocOwner(pRead, hThread, pSrcPos);1094 if ( pEntry1095 && !rtLockValidatorRecSharedAddOwner(pRead, pEntry))1096 rtLockValidatorRecSharedFreeOwner(pEntry);1097 }1098 1099 1100 RTDECL(void) RTLockValidatorRemoveReadOwner(PRTLOCKVALRECSHRD pRead, RTTHREAD hThread)1101 {1102 AssertReturnVoid(pRead->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC);1103 if (!pRead->fEnabled)1104 return;1105 AssertReturnVoid(hThread != NIL_RTTHREAD);1106 1107 /*1108 * Find the entry hope it's a recursive one.1109 */1110 uint32_t iEntry = UINT32_MAX; /* shuts up gcc */1111 PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(pRead, hThread, &iEntry);1112 AssertReturnVoid(pEntry);1113 if (pEntry->cRecursion > 1)1114 pEntry->cRecursion--;1115 else1116 rtLockValidatorRecSharedRemoveAndFreeOwner(pRead, pEntry, iEntry);1117 1699 } 1118 1700 … … 1188 1770 1189 1771 1190 /**1191 * Verifies the deadlock stack before calling it a deadlock.1192 *1193 * @retval VERR_SEM_LV_DEADLOCK if it's a deadlock.1194 * @retval VERR_TRY_AGAIN if something changed.1195 *1196 * @param pStack The deadlock detection stack.1197 */1198 static int rtLockValidatorDdVerifyDeadlock(PRTLOCKVALDDSTACK pStack)1199 {1200 uint32_t const c = pStack->c;1201 for (uint32_t iPass = 0; iPass < 3; iPass++)1202 {1203 for (uint32_t i = 1; i < c; i++)1204 {1205 PRTTHREADINT pThread = pStack->a[i].pThread;1206 if (pThread->u32Magic != RTTHREADINT_MAGIC)1207 return VERR_TRY_AGAIN;1208 if (rtThreadGetState(pThread) != pStack->a[i].enmState)1209 return VERR_TRY_AGAIN;1210 if (rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pRec) != pStack->a[i].pFirstSibling)1211 return VERR_TRY_AGAIN;1212 }1213 RTThreadYield();1214 }1215 1216 return VERR_SEM_LV_DEADLOCK;1217 }1218 1219 1220 /**1221 * Checks for stack cycles caused by another deadlock before returning.1222 *1223 * @retval VINF_SUCCESS if the stack is simply too small.1224 * @retval VERR_SEM_LV_EXISTING_DEADLOCK if a cycle was detected.1225 *1226 * @param pStack The deadlock detection stack.1227 */1228 static int rtLockValidatorDdHandleStackOverflow(PRTLOCKVALDDSTACK pStack)1229 {1230 for (size_t i = 0; i < RT_ELEMENTS(pStack->a) - 1; i++)1231 {1232 PRTTHREADINT pThread = pStack->a[i].pThread;1233 for (size_t j = i + 1; j < RT_ELEMENTS(pStack->a); j++)1234 if (pStack->a[j].pThread == pThread)1235 return VERR_SEM_LV_EXISTING_DEADLOCK;1236 }1237 static bool volatile s_fComplained = false;1238 if (!s_fComplained)1239 {1240 s_fComplained = true;1241 rtLockValidatorComplain(RT_SRC_POS, "lock validator stack is too small! (%zu entries)\n", RT_ELEMENTS(pStack->a));1242 }1243 return VINF_SUCCESS;1244 }1245 1246 1247 /**1248 * Worker for rtLockValidatorDoDeadlockCheck that checks if there is more work1249 * to be done during unwind.1250 *1251 * @returns true if there is more work left for this lock, false if not.1252 * @param pRec The current record.1253 * @param iEntry The current index.1254 * @param pFirstSibling The first record we examined.1255 */1256 DECL_FORCE_INLINE(bool) rtLockValidatorDdMoreWorkLeft(PRTLOCKVALRECUNION pRec, uint32_t iEntry, PRTLOCKVALRECUNION pFirstSibling)1257 {1258 PRTLOCKVALRECUNION pSibling;1259 1260 switch (pRec->Core.u32Magic)1261 {1262 case RTLOCKVALRECEXCL_MAGIC:1263 pSibling = pRec->Excl.pSibling;1264 break;1265 1266 case RTLOCKVALRECSHRD_MAGIC:1267 if (iEntry + 1 < pRec->Shared.cAllocated)1268 return true;1269 pSibling = pRec->Excl.pSibling;1270 break;1271 1272 default:1273 return false;1274 }1275 return pSibling != NULL1276 && pSibling != pFirstSibling;1277 }1278 1279 1280 /**1281 * Worker for rtLockValidatorDeadlockDetection that does the actual deadlock1282 * detection.1283 *1284 * @retval VINF_SUCCESS1285 * @retval VERR_SEM_LV_DEADLOCK1286 * @retval VERR_SEM_LV_EXISTING_DEADLOCK1287 * @retval VERR_TRY_AGAIN1288 *1289 * @param pStack The stack to use.1290 * @param pOriginalRec The original record.1291 * @param pThreadSelf The calling thread.1292 */1293 static int rtLockValidatorDdDoDetection(PRTLOCKVALDDSTACK pStack, PRTLOCKVALRECUNION const pOriginalRec,1294 PRTTHREADINT const pThreadSelf)1295 {1296 pStack->c = 0;1297 1298 /* We could use a single RTLOCKVALDDENTRY variable here, but the1299 compiler may make a better job of it when using individual variables. */1300 PRTLOCKVALRECUNION pRec = pOriginalRec;1301 PRTLOCKVALRECUNION pFirstSibling = pOriginalRec;1302 uint32_t iEntry = UINT32_MAX;1303 PRTTHREADINT pThread = NIL_RTTHREAD;1304 RTTHREADSTATE enmState = RTTHREADSTATE_RUNNING;1305 for (;;)1306 {1307 /*1308 * Process the current record.1309 */1310 /* Find the next relevant owner thread. */1311 PRTTHREADINT pNextThread;1312 switch (pRec->Core.u32Magic)1313 {1314 case RTLOCKVALRECEXCL_MAGIC:1315 Assert(iEntry == UINT32_MAX);1316 pNextThread = rtLockValidatorReadThreadHandle(&pRec->Excl.hThread);1317 if ( pNextThread1318 && !RTTHREAD_IS_SLEEPING(pNextThread->enmState)1319 && pNextThread != pThreadSelf)1320 pNextThread = NIL_RTTHREAD;1321 1322 if ( pNextThread == NIL_RTTHREAD1323 && pRec->Excl.pSibling1324 && pRec->Excl.pSibling != pFirstSibling)1325 {1326 pRec = pRec->Excl.pSibling;1327 continue;1328 }1329 break;1330 1331 case RTLOCKVALRECSHRD_MAGIC:1332 /* Skip to the next sibling if same side. ASSUMES reader priority. */1333 /** @todo The read side of a read-write lock is problematic if1334 * the implementation prioritizes writers over readers because1335 * that means we should could deadlock against current readers1336 * if a writer showed up. If the RW sem implementation is1337 * wrapping some native API, it's not so easy to detect when we1338 * should do this and when we shouldn't. Checking when we1339 * shouldn't is subject to wakeup scheduling and cannot easily1340 * be made reliable.1341 *1342 * At the moment we circumvent all this mess by declaring that1343 * readers has priority. This is TRUE on linux, but probably1344 * isn't on Solaris and FreeBSD. */1345 if ( pRec == pFirstSibling1346 && pRec->Shared.pSibling != NULL1347 && pRec->Shared.pSibling != pFirstSibling)1348 {1349 pRec = pRec->Shared.pSibling;1350 Assert(iEntry == UINT32_MAX);1351 continue;1352 }1353 1354 /* Scan the owner table for blocked owners. */1355 pNextThread = NIL_RTTHREAD;1356 if (ASMAtomicUoReadU32(&pRec->Shared.cEntries) > 0)1357 {1358 uint32_t cAllocated = ASMAtomicUoReadU32(&pRec->Shared.cAllocated);1359 PRTLOCKVALRECSHRDOWN volatile *papOwners = pRec->Shared.papOwners;1360 while (++iEntry < cAllocated)1361 {1362 PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorUoReadSharedOwner(&papOwners[iEntry]);1363 if ( pEntry1364 && pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC)1365 {1366 pNextThread = rtLockValidatorReadThreadHandle(&pEntry->hThread);1367 if (pNextThread)1368 {1369 if ( pNextThread->u32Magic == RTTHREADINT_MAGIC1370 && RTTHREAD_IS_SLEEPING(pNextThread->enmState))1371 break;1372 pNextThread = NIL_RTTHREAD;1373 }1374 }1375 else1376 Assert(!pEntry || pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC_DEAD);1377 }1378 if (pNextThread == NIL_RTTHREAD)1379 break;1380 }1381 1382 /* Advance to the next sibling, if any. */1383 if ( pRec->Shared.pSibling != NULL1384 && pRec->Shared.pSibling != pFirstSibling)1385 {1386 pRec = pRec->Shared.pSibling;1387 iEntry = UINT32_MAX;1388 continue;1389 }1390 break;1391 1392 case RTLOCKVALRECEXCL_MAGIC_DEAD:1393 case RTLOCKVALRECSHRD_MAGIC_DEAD:1394 pNextThread = NIL_RTTHREAD;1395 break;1396 1397 case RTLOCKVALRECSHRDOWN_MAGIC:1398 case RTLOCKVALRECSHRDOWN_MAGIC_DEAD:1399 default:1400 AssertMsgFailed(("%p: %#x\n", pRec, pRec->Core));1401 pNextThread = NIL_RTTHREAD;1402 break;1403 }1404 1405 /* If we found a thread, check if it is still waiting for something. */1406 RTTHREADSTATE enmNextState = RTTHREADSTATE_RUNNING;1407 PRTLOCKVALRECUNION pNextRec = NULL;1408 if ( pNextThread != NIL_RTTHREAD1409 && RT_LIKELY(pNextThread->u32Magic == RTTHREADINT_MAGIC))1410 {1411 do1412 {1413 enmNextState = rtThreadGetState(pNextThread);1414 if ( !RTTHREAD_IS_SLEEPING(enmNextState)1415 && pNextThread != pThreadSelf)1416 break;1417 pNextRec = rtLockValidatorReadRecUnionPtr(&pNextThread->LockValidator.pRec);1418 if (RT_LIKELY( !pNextRec1419 || enmNextState == rtThreadGetState(pNextThread)))1420 break;1421 pNextRec = NULL;1422 } while (pNextThread->u32Magic == RTTHREADINT_MAGIC);1423 }1424 if (pNextRec)1425 {1426 /*1427 * Recurse and check for deadlock.1428 */1429 uint32_t i = pStack->c;1430 if (RT_UNLIKELY(i >= RT_ELEMENTS(pStack->a)))1431 return rtLockValidatorDdHandleStackOverflow(pStack);1432 1433 pStack->c++;1434 pStack->a[i].pRec = pRec;1435 pStack->a[i].iEntry = iEntry;1436 pStack->a[i].enmState = enmState;1437 pStack->a[i].pThread = pThread;1438 pStack->a[i].pFirstSibling = pFirstSibling;1439 1440 if (RT_UNLIKELY(pNextThread == pThreadSelf))1441 return rtLockValidatorDdVerifyDeadlock(pStack);1442 1443 pRec = pNextRec;1444 pFirstSibling = pNextRec;1445 iEntry = UINT32_MAX;1446 enmState = enmNextState;1447 pThread = pNextThread;1448 }1449 else if (RT_LIKELY(!pNextThread))1450 {1451 /*1452 * No deadlock here, unwind the stack and deal with any unfinished1453 * business there.1454 */1455 uint32_t i = pStack->c;1456 for (;;)1457 {1458 /* pop */1459 if (i == 0)1460 return VINF_SUCCESS;1461 i--;1462 1463 /* examine it. */1464 pRec = pStack->a[i].pRec;1465 pFirstSibling = pStack->a[i].pFirstSibling;1466 iEntry = pStack->a[i].iEntry;1467 if (rtLockValidatorDdMoreWorkLeft(pRec, iEntry, pFirstSibling))1468 {1469 enmState = pStack->a[i].enmState;1470 pThread = pStack->a[i].pThread;1471 break;1472 }1473 }1474 }1475 /* else: see if there is another thread to check for this lock. */1476 }1477 }1478 1479 1480 /**1481 * Check for the simple no-deadlock case.1482 *1483 * @returns true if no deadlock, false if further investigation is required.1484 *1485 * @param pOriginalRec The original record.1486 */1487 DECLINLINE(int) rtLockValidatorIsSimpleNoDeadlockCase(PRTLOCKVALRECUNION pOriginalRec)1488 {1489 if ( pOriginalRec->Excl.Core.u32Magic == RTLOCKVALRECEXCL_MAGIC1490 && !pOriginalRec->Excl.pSibling)1491 {1492 PRTTHREADINT pThread = rtLockValidatorReadThreadHandle(&pOriginalRec->Excl.hThread);1493 if ( !pThread1494 || pThread->u32Magic != RTTHREADINT_MAGIC)1495 return true;1496 RTTHREADSTATE enmState = rtThreadGetState(pThread);1497 if (!RTTHREAD_IS_SLEEPING(enmState))1498 return true;1499 }1500 return false;1501 }1502 1503 1504 /**1505 * Worker for rtLockValidatorDeadlockDetection that bitches about a deadlock.1506 *1507 * @param pStack The chain of locks causing the deadlock.1508 * @param pRec The record relating to the current thread's lock1509 * operation.1510 * @param pThreadSelf This thread.1511 * @param pSrcPos Where we are going to deadlock.1512 * @param rc The return code.1513 */1514 static void rcLockValidatorDoDeadlockComplaining(PRTLOCKVALDDSTACK pStack, PRTLOCKVALRECUNION pRec,1515 PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos, int rc)1516 {1517 if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))1518 {1519 rtLockValidatorComplainFirst( rc == VERR_SEM_LV_DEADLOCK1520 ? "Detected deadlock!"1521 : rc == VERR_SEM_LV_EXISTING_DEADLOCK1522 ? "Found existing deadlock!"1523 : "!unexpected rc!",1524 pSrcPos,1525 pThreadSelf,1526 pStack->a[0].pRec != pRec ? pRec : NULL);1527 rtLockValidatorComplainMore("---- start of deadlock chain - %u entries ----\n", pStack->c);1528 for (uint32_t i = 0; i < pStack->c; i++)1529 {1530 char szPrefix[24];1531 RTStrPrintf(szPrefix, sizeof(szPrefix), "#%02u: ", i);1532 PRTLOCKVALRECSHRDOWN pShrdOwner = NULL;1533 if (pStack->a[i].pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC)1534 pShrdOwner = pStack->a[i].pRec->Shared.papOwners[pStack->a[i].iEntry];1535 if (VALID_PTR(pShrdOwner) && pShrdOwner->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC)1536 rtLockValidatorComplainAboutLock(szPrefix, (PRTLOCKVALRECUNION)pShrdOwner, "\n");1537 else1538 rtLockValidatorComplainAboutLock(szPrefix, pStack->a[i].pRec, "\n");1539 }1540 rtLockValidatorComplainMore("---- end of deadlock chain ----\n");1541 }1542 1543 rtLockValidatorComplainPanic();1544 }1545 1546 1547 /**1548 * Perform deadlock detection.1549 *1550 * @retval VINF_SUCCESS1551 * @retval VERR_SEM_LV_DEADLOCK1552 * @retval VERR_SEM_LV_EXISTING_DEADLOCK1553 *1554 * @param pRec The record relating to the current thread's lock1555 * operation.1556 * @param pThreadSelf The current thread.1557 * @param pSrcPos The position of the current lock operation.1558 */1559 static int rtLockValidatorDeadlockDetection(PRTLOCKVALRECUNION pRec, PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos)1560 {1561 #ifdef DEBUG_bird1562 RTLOCKVALDDSTACK Stack;1563 int rc = rtLockValidatorDdDoDetection(&Stack, pRec, pThreadSelf);1564 if (RT_SUCCESS(rc))1565 return VINF_SUCCESS;1566 1567 if (rc == VERR_TRY_AGAIN)1568 {1569 for (uint32_t iLoop = 0; ; iLoop++)1570 {1571 rc = rtLockValidatorDdDoDetection(&Stack, pRec, pThreadSelf);1572 if (RT_SUCCESS_NP(rc))1573 return VINF_SUCCESS;1574 if (rc != VERR_TRY_AGAIN)1575 break;1576 RTThreadYield();1577 if (iLoop >= 3)1578 return VINF_SUCCESS;1579 }1580 }1581 1582 rcLockValidatorDoDeadlockComplaining(&Stack, pRec, pThreadSelf, pSrcPos, rc);1583 return rc;1584 #else1585 return VINF_SUCCESS;1586 #endif1587 }1588 1589 1590 1591 RTDECL(int) RTLockValidatorCheckWriteOrderBlocking(PRTLOCKVALRECEXCL pWrite, PRTLOCKVALRECSHRD pRead,1592 RTTHREAD hThread, RTTHREADSTATE enmState, bool fRecursiveOk,1593 PCRTLOCKVALSRCPOS pSrcPos)1594 {1595 /*1596 * Fend off wild life.1597 */1598 PRTLOCKVALRECUNION pWriteU = (PRTLOCKVALRECUNION)pWrite; /* (avoid break aliasing rules) */1599 AssertPtrReturn(pWriteU, VERR_SEM_LV_INVALID_PARAMETER);1600 AssertReturn(pWriteU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);1601 1602 PRTLOCKVALRECUNION pReadU = (PRTLOCKVALRECUNION)pRead;1603 AssertPtrReturn(pRead, VERR_SEM_LV_INVALID_PARAMETER);1604 AssertReturn(pReadU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);1605 1606 AssertReturn(pReadU->Shared.fEnabled == pWriteU->Excl.fEnabled, VERR_SEM_LV_INVALID_PARAMETER);1607 if (!pWriteU->Excl.fEnabled)1608 return VINF_SUCCESS;1609 1610 AssertReturn(RTTHREAD_IS_SLEEPING(enmState), VERR_SEM_LV_INVALID_PARAMETER);1611 1612 PRTTHREADINT pThread = hThread;1613 AssertPtrReturn(pThread, VERR_SEM_LV_INVALID_PARAMETER);1614 AssertReturn(pThread->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);1615 RTTHREADSTATE enmThreadState = rtThreadGetState(pThread);1616 AssertReturn( enmThreadState == RTTHREADSTATE_RUNNING1617 || enmThreadState == RTTHREADSTATE_TERMINATED /* rtThreadRemove uses locks too */1618 || enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */1619 , VERR_SEM_LV_INVALID_PARAMETER);1620 1621 /*1622 * Check for attempts at doing a read upgrade.1623 */1624 PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorRecSharedFindOwner(&pReadU->Shared, hThread, NULL);1625 if (pEntry)1626 {1627 rtLockValidatorComplainFirst("Read lock upgrade", pSrcPos, pThread, (PRTLOCKVALRECUNION)pEntry);1628 rtLockValidatorComplainPanic();1629 return VERR_SEM_LV_UPGRADE;1630 }1631 1632 1633 1634 return VINF_SUCCESS;1635 }1636 1637 1638 RTDECL(int) RTLockValidatorCheckReadOrderBlocking(PRTLOCKVALRECSHRD pRead, PRTLOCKVALRECEXCL pWrite,1639 RTTHREAD hThread, RTTHREADSTATE enmState, bool fRecursiveOk,1640 PCRTLOCKVALSRCPOS pSrcPos)1641 {1642 /*1643 * Fend off wild life.1644 */1645 AssertPtrReturn(pRead, VERR_SEM_LV_INVALID_PARAMETER);1646 AssertReturn(pRead->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);1647 AssertPtrReturn(pWrite, VERR_SEM_LV_INVALID_PARAMETER);1648 AssertReturn(pWrite->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);1649 AssertReturn(pRead->fEnabled == pWrite->fEnabled, VERR_SEM_LV_INVALID_PARAMETER);1650 if (!pRead->fEnabled)1651 return VINF_SUCCESS;1652 AssertReturn(RTTHREAD_IS_SLEEPING(enmState), VERR_SEM_LV_INVALID_PARAMETER);1653 PRTTHREADINT pThread = hThread;1654 AssertPtrReturn(pThread, VERR_SEM_LV_INVALID_PARAMETER);1655 AssertReturn(pThread->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);1656 RTTHREADSTATE enmThreadState = rtThreadGetState(pThread);1657 AssertReturn( enmThreadState == RTTHREADSTATE_RUNNING1658 || enmThreadState == RTTHREADSTATE_TERMINATED /* rtThreadRemove uses locks too */1659 || enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */1660 , VERR_SEM_LV_INVALID_PARAMETER);1661 Assert(pWrite->hThread != pThread);1662 1663 1664 return VINF_SUCCESS;1665 }1666 1667 1668 RTDECL(int) RTLockValidatorCheckBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThread,1669 RTTHREADSTATE enmState, bool fRecursiveOk,1670 PCRTLOCKVALSRCPOS pSrcPos)1671 {1672 /*1673 * Fend off wild life.1674 */1675 PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;1676 AssertPtrReturn(pRecU, VERR_SEM_LV_INVALID_PARAMETER);1677 AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);1678 if (!pRecU->Excl.fEnabled)1679 return VINF_SUCCESS;1680 1681 AssertReturn(RTTHREAD_IS_SLEEPING(enmState), VERR_SEM_LV_INVALID_PARAMETER);1682 1683 PRTTHREADINT pThreadSelf = hThread;1684 AssertPtrReturn(pThreadSelf, VERR_SEM_LV_INVALID_PARAMETER);1685 AssertReturn(pThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);1686 1687 RTTHREADSTATE enmThreadState = rtThreadGetState(pThreadSelf);1688 AssertReturn( enmThreadState == RTTHREADSTATE_RUNNING1689 || enmThreadState == RTTHREADSTATE_TERMINATED /* rtThreadRemove uses locks too */1690 || enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */1691 , VERR_SEM_LV_INVALID_PARAMETER);1692 1693 /*1694 * Record the location and everything before changing the state and1695 * performing deadlock detection.1696 */1697 rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, pRecU);1698 rtLockValidatorCopySrcPos(&pThreadSelf->LockValidator.SrcPos, pSrcPos);1699 1700 /*1701 * Don't do deadlock detection if we're recursing.1702 *1703 * On some hosts we don't do recursion accounting our selves and there1704 * isn't any other place to check for this. semmutex-win.cpp for instance.1705 */1706 if (rtLockValidatorReadThreadHandle(&pRecU->Excl.hThread) == pThreadSelf)1707 {1708 if (fRecursiveOk)1709 return VINF_SUCCESS;1710 rtLockValidatorComplainFirst("Recursion not allowed", pSrcPos, pThreadSelf, pRecU);1711 rtLockValidatorComplainPanic();1712 return VERR_SEM_LV_NESTED;1713 }1714 1715 /*1716 * Perform deadlock detection.1717 */1718 if (rtLockValidatorIsSimpleNoDeadlockCase(pRecU))1719 return VINF_SUCCESS;1720 return rtLockValidatorDeadlockDetection(pRecU, pThreadSelf, pSrcPos);1721 }1722 RT_EXPORT_SYMBOL(RTLockValidatorCheckBlocking);1723 1724 1725 1772 RTDECL(bool) RTLockValidatorSetEnabled(bool fEnabled) 1726 1773 {
Note:
See TracChangeset
for help on using the changeset viewer.