Changeset 25682 in vbox for trunk/src/VBox/Runtime/common
- Timestamp:
- Jan 7, 2010 3:23:30 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp
r25662 r25682 5 5 6 6 /* 7 * Copyright (C) 2009 Sun Microsystems, Inc.7 * Copyright (C) 2009-2010 Sun Microsystems, Inc. 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 88 88 89 89 90 /** 91 * Reference to another class. 92 */ 93 typedef struct RTLOCKVALCLASSREF 94 { 95 /** The class. */ 96 RTLOCKVALCLASS hClass; 97 /** The number of lookups of this class. */ 98 uint32_t volatile cLookups; 99 /** Indicates whether the entry was added automatically during order checking 100 * (true) or manually via the API (false). */ 101 bool fAutodidacticism; 102 /** Reserved / explicit alignment padding. */ 103 bool afReserved[3]; 104 } RTLOCKVALCLASSREF; 105 /** Pointer to a class reference. */ 106 typedef RTLOCKVALCLASSREF *PRTLOCKVALCLASSREF; 107 108 109 /** Pointer to a chunk of class references. */ 110 typedef struct RTLOCKVALCLASSREFCHUNK *PRTLOCKVALCLASSREFCHUNK; 111 /** 112 * Chunk of class references. 113 */ 114 typedef struct RTLOCKVALCLASSREFCHUNK 115 { 116 /** Array of refs. */ 117 #if 0 /** @todo for testing alloction of new chunks. */ 118 RTLOCKVALCLASSREF aRefs[ARCH_BITS == 32 ? 10 : 8]; 119 #else 120 RTLOCKVALCLASSREF aRefs[2]; 121 #endif 122 /** Pointer to the next chunk. */ 123 PRTLOCKVALCLASSREFCHUNK volatile pNext; 124 } RTLOCKVALCLASSREFCHUNK; 125 126 127 /** 128 * Lock class. 129 */ 130 typedef struct RTLOCKVALCLASSINT 131 { 132 /** AVL node core. */ 133 AVLLU32NODECORE Core; 134 /** Magic value (RTLOCKVALCLASS_MAGIC). */ 135 uint32_t volatile u32Magic; 136 /** Reference counter. See RTLOCKVALCLASS_MAX_REFS. */ 137 uint32_t volatile cRefs; 138 /** Whether the class is allowed to teach it self new locking order rules. */ 139 bool fAutodidact; 140 /** Whether this class is in the tree. */ 141 bool fInTree; 142 bool afReserved[2]; /**< Explicit padding */ 143 /** The minimum wait interval for which we do deadlock detection 144 * (milliseconds). */ 145 RTMSINTERVAL cMsMinDeadlock; 146 /** The minimum wait interval for which we do order checks (milliseconds). */ 147 RTMSINTERVAL cMsMinOrder; 148 /** More padding. */ 149 uint32_t au32Reserved[ARCH_BITS == 32 ? 6 : 3]; 150 /** Classes that may be taken prior to this one. 151 * This is a linked list where each node contains a chunk of locks so that we 152 * reduce the number of allocations as well as localize the data. */ 153 RTLOCKVALCLASSREFCHUNK PriorLocks; 154 /** Hash table containing frequently encountered prior locks. */ 155 PRTLOCKVALCLASSREF apPriorLocksHash[11]; 156 #define RTLOCKVALCLASS_HASH_STATS 157 #ifdef RTLOCKVALCLASS_HASH_STATS 158 /** Hash hits. */ 159 uint32_t volatile cHashHits; 160 /** Hash misses. */ 161 uint32_t volatile cHashMisses; 162 #endif 163 /** Where this class was created. 164 * This is mainly used for finding automatically created lock classes. 165 * @remarks The strings are stored after this structure so we won't crash 166 * if the class lives longer than the module (dll/so/dylib) that 167 * spawned it. */ 168 RTLOCKVALSRCPOS CreatePos; 169 } RTLOCKVALCLASSINT; 170 AssertCompileSize(AVLLU32NODECORE, ARCH_BITS == 32 ? 20 : 32); 171 AssertCompileMemberOffset(RTLOCKVALCLASSINT, PriorLocks, 64); 172 173 90 174 /******************************************************************************* 91 175 * Defined Constants And Macros * … … 94 178 * Only used when fighting bugs. */ 95 179 #if 1 96 # define RTLOCKVAL_ASSERT_PTR_ALIGN(p) 180 # define RTLOCKVAL_ASSERT_PTR_ALIGN(p) \ 97 181 AssertMsg(!((uintptr_t)(p) & (sizeof(uintptr_t) - 1)), ("%p\n", (p))); 98 182 #else 99 183 # define RTLOCKVAL_ASSERT_PTR_ALIGN(p) do { } while (0) 100 184 #endif 185 186 /** Hashes the class handle (pointer) into an apPriorLocksHash index. */ 187 #define RTLOCKVALCLASS_HASH(hClass) \ 188 ( (uintptr_t)(hClass) \ 189 % ( RT_SIZEOFMEMB(RTLOCKVALCLASSINT, apPriorLocksHash) \ 190 / sizeof(PRTLOCKVALCLASSREF)) ) 191 192 /** The max value for RTLOCKVALCLASSINT::cRefs. */ 193 #define RTLOCKVALCLASS_MAX_REFS UINT32_C(0xffff0000) 194 /** The max value for RTLOCKVALCLASSREF::cLookups. */ 195 #define RTLOCKVALCLASSREF_MAX_LOOKUPS UINT32_C(0xfffe0000) 196 /** The absolute max value for RTLOCKVALCLASSREF::cLookups at which it will 197 * be set back to RTLOCKVALCLASSREF_MAX_LOOKUPS. */ 198 #define RTLOCKVALCLASSREF_MAX_LOOKUPS_FIX UINT32_C(0xffff0000) 101 199 102 200 … … 129 227 static bool volatile g_fLockValidatorMayPanic = false; 130 228 #endif 229 /** Serializing class tree insert and lookups. */ 230 static RTSEMRW g_hLockValClassTreeRWLock = NIL_RTSEMRW; 231 /** Class tree. */ 232 static PAVLLU32NODECORE g_LockValClassTree = NULL; 233 /** Critical section serializing the teaching new rules to the classes. */ 234 static RTCRITSECT g_LockValClassTeachCS; 235 236 237 /******************************************************************************* 238 * Internal Functions * 239 *******************************************************************************/ 240 static void rtLockValidatorClassDestroy(RTLOCKVALCLASSINT *pClass); 241 242 243 /** 244 * Lazy initialization of the lock validator globals. 245 */ 246 static void rtLockValidatorLazyInit(void) 247 { 248 static uint32_t volatile s_fInitializing = false; 249 if (ASMAtomicCmpXchgU32(&s_fInitializing, true, false)) 250 { 251 if (!RTCritSectIsInitialized(&g_LockValClassTeachCS)) 252 RTCritSectInit(&g_LockValClassTeachCS); 253 254 if (g_hLockValClassTreeRWLock == NIL_RTSEMRW) 255 { 256 RTSEMRW hSemRW; 257 int rc = RTSemRWCreate(&hSemRW); 258 if (RT_SUCCESS(rc)) 259 ASMAtomicWriteHandle(&g_hLockValClassTreeRWLock, hSemRW); 260 } 261 262 if (g_hLockValidatorXRoads == NIL_RTSEMXROADS) 263 { 264 RTSEMXROADS hXRoads; 265 int rc = RTSemXRoadsCreate(&hXRoads); 266 if (RT_SUCCESS(rc)) 267 ASMAtomicWriteHandle(&g_hLockValidatorXRoads, hXRoads); 268 } 269 270 /** @todo register some cleanup callback if we care. */ 271 272 ASMAtomicWriteU32(&s_fInitializing, false); 273 } 274 else 275 RTThreadYield(); 276 } 277 131 278 132 279 … … 321 468 * @param pSrc The source. Can be NULL. 322 469 */ 323 DECL_FORCE_INLINE(void) rtLockValidator CopySrcPos(PRTLOCKVALSRCPOS pDst, PCRTLOCKVALSRCPOS pSrc)470 DECL_FORCE_INLINE(void) rtLockValidatorSrcPosCopy(PRTLOCKVALSRCPOS pDst, PCRTLOCKVALSRCPOS pSrc) 324 471 { 325 472 if (pSrc) … … 345 492 * @param pSrcPos The source position record. 346 493 */ 347 DECL_FORCE_INLINE(void) rtLockValidator InitSrcPos(PRTLOCKVALSRCPOS pSrcPos)494 DECL_FORCE_INLINE(void) rtLockValidatorSrcPosInit(PRTLOCKVALSRCPOS pSrcPos) 348 495 { 349 496 pSrcPos->pszFile = NULL; … … 357 504 358 505 506 /* sdbm: 507 This algorithm was created for sdbm (a public-domain reimplementation of 508 ndbm) database library. it was found to do well in scrambling bits, 509 causing better distribution of the keys and fewer splits. it also happens 510 to be a good general hashing function with good distribution. the actual 511 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below 512 is the faster version used in gawk. [there is even a faster, duff-device 513 version] the magic constant 65599 was picked out of thin air while 514 experimenting with different constants, and turns out to be a prime. 515 this is one of the algorithms used in berkeley db (see sleepycat) and 516 elsewhere. */ 517 DECL_FORCE_INLINE(uint32_t) sdbm(const char *str, uint32_t hash) 518 { 519 uint8_t *pu8 = (uint8_t *)str; 520 int c; 521 522 while ((c = *pu8++)) 523 hash = c + (hash << 6) + (hash << 16) - hash; 524 525 return hash; 526 } 527 528 529 /** 530 * Hashes the specified source position. 531 * 532 * @returns Hash. 533 * @param pSrcPos The source position record. 534 */ 535 static uint32_t rtLockValidatorSrcPosHash(PCRTLOCKVALSRCPOS pSrcPos) 536 { 537 uint32_t uHash; 538 if ( ( pSrcPos->pszFile 539 || pSrcPos->pszFunction) 540 && pSrcPos->uLine != 0) 541 { 542 uHash = 0; 543 if (pSrcPos->pszFile) 544 uHash = sdbm(pSrcPos->pszFile, uHash); 545 if (pSrcPos->pszFunction) 546 uHash = sdbm(pSrcPos->pszFunction, uHash); 547 uHash += pSrcPos->uLine; 548 } 549 else 550 { 551 Assert(pSrcPos->uId); 552 uHash = (uint32_t)pSrcPos->uId; 553 } 554 555 return uHash; 556 } 557 558 559 /** 560 * Compares two source positions. 561 * 562 * @returns 0 if equal, < 0 if pSrcPos1 is smaller than pSrcPos2, > 0 if 563 * otherwise. 564 * @param pSrcPos1 The first source position. 565 * @param pSrcPos2 The second source position. 566 */ 567 static int rtLockValidatorSrcPosCompare(PCRTLOCKVALSRCPOS pSrcPos1, PCRTLOCKVALSRCPOS pSrcPos2) 568 { 569 if (pSrcPos1->uLine != pSrcPos2->uLine) 570 return pSrcPos1->uLine < pSrcPos2->uLine ? -1 : 1; 571 572 int iDiff = RTStrCmp(pSrcPos1->pszFile, pSrcPos2->pszFile); 573 if (iDiff != 0) 574 return iDiff; 575 576 iDiff = RTStrCmp(pSrcPos1->pszFunction, pSrcPos2->pszFunction); 577 if (iDiff != 0) 578 return iDiff; 579 580 if (pSrcPos1->uId != pSrcPos2->uId) 581 return pSrcPos1->uId < pSrcPos2->uId ? -1 : 1; 582 return 0; 583 } 584 585 586 359 587 /** 360 588 * Serializes destruction of RTLOCKVALREC* and RTTHREADINT structures. … … 416 644 Assert(pPerThread->cReadLocks == 0); 417 645 Assert(pPerThread->fInValidator == false); 646 } 647 648 649 RTDECL(int) RTLockValidatorClassCreateEx(PRTLOCKVALCLASS phClass, PCRTLOCKVALSRCPOS pSrcPos, 650 bool fAutodidact, RTMSINTERVAL cMsMinDeadlock, RTMSINTERVAL cMsMinOrder) 651 { 652 Assert(cMsMinDeadlock >= 1); 653 Assert(cMsMinOrder >= 1); 654 AssertPtr(pSrcPos); 655 656 size_t const cbFile = pSrcPos->pszFile ? strlen(pSrcPos->pszFile) + 1 : 0; 657 size_t const cbFunction = pSrcPos->pszFile ? strlen(pSrcPos->pszFunction) + 1 : 0; 658 RTLOCKVALCLASSINT *pThis = (RTLOCKVALCLASSINT *)RTMemAlloc(sizeof(*pThis) + cbFile + cbFunction); 659 if (!pThis) 660 return VERR_NO_MEMORY; 661 662 pThis->Core.Key = rtLockValidatorSrcPosHash(pSrcPos); 663 pThis->Core.uchHeight = 0; 664 pThis->Core.pLeft = NULL; 665 pThis->Core.pRight = NULL; 666 pThis->Core.pList = NULL; 667 pThis->u32Magic = RTLOCKVALCLASS_MAGIC; 668 pThis->cRefs = 1; 669 pThis->fAutodidact = fAutodidact; 670 pThis->fInTree = false; 671 for (unsigned i = 0; i < RT_ELEMENTS(pThis->afReserved); i++) 672 pThis->afReserved[i] = false; 673 pThis->cMsMinDeadlock = cMsMinDeadlock; 674 pThis->cMsMinOrder = cMsMinOrder; 675 for (unsigned i = 0; i < RT_ELEMENTS(pThis->au32Reserved); i++) 676 pThis->au32Reserved[i] = 0; 677 for (unsigned i = 0; i < RT_ELEMENTS(pThis->au32Reserved); i++) 678 { 679 pThis->PriorLocks.aRefs[i].hClass = NIL_RTLOCKVALCLASS; 680 pThis->PriorLocks.aRefs[i].cLookups = 0; 681 pThis->PriorLocks.aRefs[i].fAutodidacticism = false; 682 pThis->PriorLocks.aRefs[i].afReserved[0] = false; 683 pThis->PriorLocks.aRefs[i].afReserved[1] = false; 684 pThis->PriorLocks.aRefs[i].afReserved[2] = false; 685 } 686 pThis->PriorLocks.pNext = NULL; 687 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apPriorLocksHash); i++) 688 pThis->apPriorLocksHash[i] = NULL; 689 rtLockValidatorSrcPosCopy(&pThis->CreatePos, pSrcPos); 690 char *pszDst = (char *)(pThis + 1); 691 pThis->CreatePos.pszFile = pSrcPos->pszFile ? (char *)memcpy(pszDst, pSrcPos->pszFile, cbFile) : NULL; 692 pszDst += cbFile; 693 pThis->CreatePos.pszFunction= pSrcPos->pszFunction ? (char *)memcpy(pszDst, pSrcPos->pszFunction, cbFunction) : NULL; 694 Assert(rtLockValidatorSrcPosHash(&pThis->CreatePos) == pThis->Core.Key); 695 696 *phClass = pThis; 697 return VINF_SUCCESS; 698 } 699 700 701 RTDECL(int) RTLockValidatorClassCreate(PRTLOCKVALCLASS phClass, bool fAutodidact, RT_SRC_POS_DECL) 702 { 703 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_POS_NO_ID(); 704 return RTLockValidatorClassCreateEx(phClass, &SrcPos, fAutodidact, 705 1 /*cMsMinDeadlock*/, 1 /*cMsMinOrder*/); 706 } 707 708 709 /** 710 * Internal class retainer. 711 * @returns The new reference count. 712 * @param pClass The class. 713 */ 714 DECL_FORCE_INLINE(uint32_t) rtLockValidatorClassRetain(RTLOCKVALCLASSINT *pClass) 715 { 716 uint32_t cRefs = ASMAtomicIncU32(&pClass->cRefs); 717 if (cRefs > RTLOCKVALCLASS_MAX_REFS) 718 ASMAtomicWriteU32(&pClass->cRefs, RTLOCKVALCLASS_MAX_REFS); 719 return cRefs; 720 } 721 722 723 /** 724 * Validates and retains a lock validator class. 725 * 726 * @returns @a hClass on success, NIL_RTLOCKVALCLASS on failure. 727 * @param hClass The class handle. NIL_RTLOCKVALCLASS is ok. 728 */ 729 DECL_FORCE_INLINE(RTLOCKVALCLASS) rtLockValidatorClassValidateAndRetain(RTLOCKVALCLASS hClass) 730 { 731 if (hClass == NIL_RTLOCKVALCLASS) 732 return hClass; 733 AssertPtrReturn(hClass, NIL_RTLOCKVALCLASS); 734 AssertReturn(hClass->u32Magic == RTLOCKVALCLASS_MAGIC, NIL_RTLOCKVALCLASS); 735 rtLockValidatorClassRetain(hClass); 736 return hClass; 737 } 738 739 740 /** 741 * Internal class releaser. 742 * @returns The new reference count. 743 * @param pClass The class. 744 */ 745 DECL_FORCE_INLINE(uint32_t) rtLockValidatorClassRelease(RTLOCKVALCLASSINT *pClass) 746 { 747 uint32_t cRefs = ASMAtomicDecU32(&pClass->cRefs); 748 if (cRefs + 1 == RTLOCKVALCLASS_MAX_REFS) 749 ASMAtomicWriteU32(&pClass->cRefs, RTLOCKVALCLASS_MAX_REFS); 750 else if (!cRefs) 751 rtLockValidatorClassDestroy(pClass); 752 return cRefs; 753 } 754 755 756 /** 757 * Destroys a class once there are not more references to it. 758 * 759 * @param Class The class. 760 */ 761 static void rtLockValidatorClassDestroy(RTLOCKVALCLASSINT *pClass) 762 { 763 AssertReturnVoid(pClass->fInTree); 764 ASMAtomicWriteU32(&pClass->u32Magic, RTLOCKVALCLASS_MAGIC_DEAD); 765 766 PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks; 767 while (pChunk) 768 { 769 for (uint32_t i = 0; i < RT_ELEMENTS(pChunk->aRefs); i++) 770 { 771 RTLOCKVALCLASSINT *pClass2 = pChunk->aRefs[i].hClass; 772 if (pClass2 != NIL_RTLOCKVALCLASS) 773 { 774 pChunk->aRefs[i].hClass = NIL_RTLOCKVALCLASS; 775 rtLockValidatorClassRelease(pClass2); 776 } 777 } 778 779 PRTLOCKVALCLASSREFCHUNK pNext = pChunk->pNext; 780 pChunk->pNext = NULL; 781 if (pChunk != &pClass->PriorLocks) 782 RTMemFree(pChunk); 783 pNext = pChunk; 784 } 785 786 RTMemFree(pClass); 787 } 788 789 790 RTDECL(RTLOCKVALCLASS) RTLockValidatorClassFindForSrcPos(PRTLOCKVALSRCPOS pSrcPos) 791 { 792 if (g_hLockValClassTreeRWLock == NIL_RTSEMRW) 793 rtLockValidatorLazyInit(); 794 int rcLock = RTSemRWRequestRead(g_hLockValClassTreeRWLock, RT_INDEFINITE_WAIT); 795 796 uint32_t uSrcPosHash = rtLockValidatorSrcPosHash(pSrcPos); 797 RTLOCKVALCLASSINT *pClass = (RTLOCKVALCLASSINT *)RTAvllU32Get(&g_LockValClassTree, uSrcPosHash); 798 while (pClass) 799 { 800 if (rtLockValidatorSrcPosCompare(&pClass->CreatePos, pSrcPos) == 0) 801 { 802 rtLockValidatorClassRetain(pClass); 803 break; 804 } 805 pClass = (RTLOCKVALCLASSINT *)pClass->Core.pList; 806 } 807 808 if (RT_SUCCESS(rcLock)) 809 RTSemRWReleaseRead(g_hLockValClassTreeRWLock); 810 return pClass; 811 } 812 813 814 RTDECL(RTLOCKVALCLASS) RTLockValidatorClassForSrcPos(RT_SRC_POS_DECL) 815 { 816 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_POS_NO_ID(); 817 RTLOCKVALCLASS hClass = RTLockValidatorClassFindForSrcPos(&SrcPos); 818 if (hClass == NIL_RTLOCKVALCLASS) 819 { 820 /* 821 * Create a new class and insert it into the tree. 822 */ 823 int rc = RTLockValidatorClassCreateEx(&hClass, &SrcPos, true /*fAutodidact*/, 824 1 /*cMsMinDeadlock*/, 1 /*cMsMinOrder*/); 825 if (RT_SUCCESS(rc)) 826 { 827 if (g_hLockValClassTreeRWLock == NIL_RTSEMRW) 828 rtLockValidatorLazyInit(); 829 int rcLock = RTSemRWRequestWrite(g_hLockValClassTreeRWLock, RT_INDEFINITE_WAIT); 830 831 Assert(!hClass->fInTree); 832 hClass->fInTree = RTAvllU32Insert(&g_LockValClassTree, &hClass->Core); 833 Assert(hClass->fInTree); 834 835 if (RT_SUCCESS(rcLock)) 836 RTSemRWReleaseWrite(g_hLockValClassTreeRWLock); 837 return hClass; 838 } 839 } 840 return hClass; 841 } 842 843 844 RTDECL(uint32_t) RTLockValidatorClassRetain(RTLOCKVALCLASS hClass) 845 { 846 RTLOCKVALCLASSINT *pClass = hClass; 847 AssertPtrReturn(pClass, UINT32_MAX); 848 AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, UINT32_MAX); 849 return rtLockValidatorClassRetain(pClass); 850 } 851 852 853 RTDECL(uint32_t) RTLockValidatorClassRelease(RTLOCKVALCLASS hClass) 854 { 855 RTLOCKVALCLASSINT *pClass = hClass; 856 AssertPtrReturn(pClass, UINT32_MAX); 857 AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, UINT32_MAX); 858 return rtLockValidatorClassRelease(pClass); 859 } 860 861 862 /** 863 * Worker for rtLockValidatorClassIsPriorClass that does a linear search thru 864 * all the chunks for @a pPriorClass. 865 * 866 * @returns true / false. 867 * @param pClass The class to search. 868 * @param pPriorClass The class to search for. 869 */ 870 static bool rtLockValidatorClassIsPriorClassByLinearSearch(RTLOCKVALCLASSINT *pClass, RTLOCKVALCLASSINT *pPriorClass) 871 { 872 for (PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks; pChunk; pChunk = pChunk->pNext) 873 for (uint32_t i = 0; i < RT_ELEMENTS(pChunk->aRefs); i++) 874 { 875 if (pChunk->aRefs[i].hClass == pPriorClass) 876 { 877 uint32_t cLookups = ASMAtomicIncU32(&pChunk->aRefs[i].cLookups); 878 if (RT_UNLIKELY(cLookups >= RTLOCKVALCLASSREF_MAX_LOOKUPS_FIX)) 879 { 880 ASMAtomicWriteU32(&pChunk->aRefs[i].cLookups, RTLOCKVALCLASSREF_MAX_LOOKUPS); 881 cLookups = RTLOCKVALCLASSREF_MAX_LOOKUPS; 882 } 883 884 /* update the hash table entry. */ 885 PRTLOCKVALCLASSREF *ppHashEntry = &pClass->apPriorLocksHash[RTLOCKVALCLASS_HASH(pPriorClass)]; 886 if ( !(*ppHashEntry) 887 || (*ppHashEntry)->cLookups + 128 < cLookups) 888 ASMAtomicWritePtr((void * volatile *)ppHashEntry, &pChunk->aRefs[i]); 889 890 #ifdef RTLOCKVALCLASS_HASH_STATS 891 ASMAtomicIncU32(&pClass->cHashMisses); 892 #endif 893 return true; 894 } 895 } 896 897 return false; 898 } 899 900 901 /** 902 * Checks if @a pPriorClass is a known prior class. 903 * 904 * @returns true / false. 905 * @param pClass The class to search. 906 * @param pPriorClass The class to search for. 907 */ 908 DECL_FORCE_INLINE(bool) rtLockValidatorClassIsPriorClass(RTLOCKVALCLASSINT *pClass, RTLOCKVALCLASSINT *pPriorClass) 909 { 910 /* 911 * Hash lookup here. 912 */ 913 PRTLOCKVALCLASSREF pRef = pClass->apPriorLocksHash[RTLOCKVALCLASS_HASH(pPriorClass)]; 914 if ( pRef 915 && pRef->hClass == pPriorClass) 916 { 917 uint32_t cLookups = ASMAtomicIncU32(&pRef->cLookups); 918 if (RT_UNLIKELY(cLookups >= RTLOCKVALCLASSREF_MAX_LOOKUPS_FIX)) 919 ASMAtomicWriteU32(&pRef->cLookups, RTLOCKVALCLASSREF_MAX_LOOKUPS); 920 #ifdef RTLOCKVALCLASS_HASH_STATS 921 ASMAtomicIncU32(&pClass->cHashHits); 922 #endif 923 return true; 924 } 925 926 return rtLockValidatorClassIsPriorClassByLinearSearch(pClass, pPriorClass); 927 } 928 929 930 /** 931 * Adds a class to the prior list. 932 * 933 * @returns VINF_SUCCESS, VERR_NO_MEMORY or VERR_SEM_LV_WRONG_ORDER. 934 * @param pClass The class to work on. 935 * @param pPriorClass The class to add. 936 * @param fAutodidacticism Whether we're teaching ourselfs (true) or 937 * somebody is teaching us via the API (false). 938 */ 939 static int rtLockValidatorClassAddPriorClass(RTLOCKVALCLASSINT *pClass, RTLOCKVALCLASSINT *pPriorClass, bool fAutodidacticism) 940 { 941 if (!RTCritSectIsInitialized(&g_LockValClassTeachCS)) 942 rtLockValidatorLazyInit(); 943 int rcLock = RTCritSectEnter(&g_LockValClassTeachCS); 944 945 /* 946 * Check that there are no conflict (no assert since we might race each other). 947 */ 948 int rc = VERR_INTERNAL_ERROR_5; 949 if (!rtLockValidatorClassIsPriorClass(pPriorClass, pClass)) 950 { 951 if (!rtLockValidatorClassIsPriorClass(pClass, pPriorClass)) 952 { 953 /* 954 * Scan the table for a free entry, allocating a new chunk if necessary. 955 */ 956 for (PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks; ; pChunk = pChunk->pNext) 957 { 958 bool fDone = false; 959 for (uint32_t i = 0; i < RT_ELEMENTS(pChunk->aRefs); i++) 960 { 961 ASMAtomicCmpXchgHandle(&pChunk->aRefs[i].hClass, pPriorClass, NIL_RTLOCKVALCLASS, fDone); 962 if (fDone) 963 { 964 pChunk->aRefs[i].fAutodidacticism = fAutodidacticism; 965 rc = VINF_SUCCESS; 966 break; 967 } 968 } 969 if (fDone) 970 break; 971 972 /* If no more chunks, allocate a new one and insert the class before linking it. */ 973 if (!pChunk->pNext) 974 { 975 PRTLOCKVALCLASSREFCHUNK pNew = (PRTLOCKVALCLASSREFCHUNK)RTMemAlloc(sizeof(*pNew)); 976 if (!pNew) 977 { 978 rc = VERR_NO_MEMORY; 979 break; 980 } 981 pNew->pNext = NULL; 982 for (uint32_t i = 0; i < RT_ELEMENTS(pNew->aRefs); i++) 983 { 984 pNew->aRefs[i].hClass = NIL_RTLOCKVALCLASS; 985 pNew->aRefs[i].cLookups = 0; 986 pNew->aRefs[i].fAutodidacticism = false; 987 pNew->aRefs[i].afReserved[0] = false; 988 pNew->aRefs[i].afReserved[1] = false; 989 pNew->aRefs[i].afReserved[2] = false; 990 } 991 992 pNew->aRefs[0].hClass = pPriorClass; 993 pNew->aRefs[0].fAutodidacticism = fAutodidacticism; 994 995 ASMAtomicWritePtr((void * volatile *)&pChunk->pNext, pNew); 996 rc = VINF_SUCCESS; 997 break; 998 } 999 } /* chunk loop */ 1000 } 1001 else 1002 rc = VINF_SUCCESS; 1003 } 1004 else 1005 rc = VERR_SEM_LV_WRONG_ORDER; 1006 1007 if (RT_SUCCESS(rcLock)) 1008 RTCritSectLeave(&g_LockValClassTeachCS); 1009 return rc; 1010 } 1011 1012 1013 RTDECL(int) RTLockValidatorClassAddPriorClass(RTLOCKVALCLASS hClass, RTLOCKVALCLASS hPriorClass) 1014 { 1015 RTLOCKVALCLASSINT *pClass = hClass; 1016 AssertPtrReturn(pClass, VERR_INVALID_HANDLE); 1017 AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, VERR_INVALID_HANDLE); 1018 1019 RTLOCKVALCLASSINT *pPriorClass = hPriorClass; 1020 AssertPtrReturn(pPriorClass, VERR_INVALID_HANDLE); 1021 AssertReturn(pPriorClass->u32Magic == RTLOCKVALCLASS_MAGIC, VERR_INVALID_HANDLE); 1022 1023 return rtLockValidatorClassAddPriorClass(pClass, pPriorClass, false /*fAutodidacticism*/); 418 1024 } 419 1025 … … 457 1063 return true; 458 1064 } 459 460 461 1065 462 1066 … … 960 1564 961 1565 962 963 964 RTDECL(void) RTLockValidatorRecExclInit(PRTLOCKVALRECEXCL pRec, RTLOCKVALIDATORCLASS hClass, 1566 RTDECL(void) RTLockValidatorRecExclInit(PRTLOCKVALRECEXCL pRec, RTLOCKVALCLASS hClass, 965 1567 uint32_t uSubClass, const char *pszName, void *hLock) 966 1568 { … … 973 1575 pRec->afReserved[1] = 0; 974 1576 pRec->afReserved[2] = 0; 975 rtLockValidator InitSrcPos(&pRec->SrcPos);1577 rtLockValidatorSrcPosInit(&pRec->SrcPos); 976 1578 pRec->hThread = NIL_RTTHREAD; 977 1579 pRec->pDown = NULL; 978 pRec->hClass = hClass;1580 pRec->hClass = rtLockValidatorClassValidateAndRetain(hClass); 979 1581 pRec->uSubClass = uSubClass; 980 1582 pRec->cRecursion = 0; … … 983 1585 pRec->pSibling = NULL; 984 1586 985 /* Lazily initialize the crossroads semaphore. */ 986 static uint32_t volatile s_fInitializing = false; 987 if (RT_UNLIKELY( g_hLockValidatorXRoads == NIL_RTSEMXROADS 988 && ASMAtomicCmpXchgU32(&s_fInitializing, true, false))) 989 { 990 RTSEMXROADS hXRoads; 991 int rc = RTSemXRoadsCreate(&hXRoads); 992 if (RT_SUCCESS(rc)) 993 ASMAtomicWriteHandle(&g_hLockValidatorXRoads, hXRoads); 994 ASMAtomicWriteU32(&s_fInitializing, false); 995 } 996 } 997 998 999 RTDECL(int) RTLockValidatorRecExclCreate(PRTLOCKVALRECEXCL *ppRec, RTLOCKVALIDATORCLASS hClass, 1587 /* Lazy initialization. */ 1588 if (RT_UNLIKELY(g_hLockValidatorXRoads == NIL_RTSEMXROADS)) 1589 rtLockValidatorLazyInit(); 1590 } 1591 1592 1593 RTDECL(int) RTLockValidatorRecExclCreate(PRTLOCKVALRECEXCL *ppRec, RTLOCKVALCLASS hClass, 1000 1594 uint32_t uSubClass, const char *pszName, void *pvLock) 1001 1595 { … … 1019 1613 ASMAtomicWriteU32(&pRec->Core.u32Magic, RTLOCKVALRECEXCL_MAGIC_DEAD); 1020 1614 ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD); 1021 ASMAtomicWriteHandle(&pRec->hClass, NIL_RTLOCKVAL IDATORCLASS);1615 ASMAtomicWriteHandle(&pRec->hClass, NIL_RTLOCKVALCLASS); 1022 1616 if (pRec->pSibling) 1023 1617 rtLockValidatorUnlinkAllSiblings(&pRec->Core); … … 1065 1659 * Update the record. 1066 1660 */ 1067 rtLockValidator CopySrcPos(&pRec->SrcPos, pSrcPos);1661 rtLockValidatorSrcPosCopy(&pRec->SrcPos, pSrcPos); 1068 1662 ASMAtomicUoWriteU32(&pRec->cRecursion, 1); 1069 1663 ASMAtomicWriteHandle(&pRec->hThread, hThreadSelf); … … 1232 1826 */ 1233 1827 rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, pRecU); 1234 rtLockValidator CopySrcPos(&pThreadSelf->LockValidator.SrcPos, pSrcPos);1828 rtLockValidatorSrcPosCopy(&pThreadSelf->LockValidator.SrcPos, pSrcPos); 1235 1829 ASMAtomicWriteBool(&pThreadSelf->LockValidator.fInValidator, true); 1236 1830 pThreadSelf->LockValidator.enmRecState = enmSleepState; … … 1284 1878 1285 1879 1286 RTDECL(void) RTLockValidatorRecSharedInit(PRTLOCKVALRECSHRD pRec, RTLOCKVAL IDATORCLASS hClass, uint32_t uSubClass,1880 RTDECL(void) RTLockValidatorRecSharedInit(PRTLOCKVALRECSHRD pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass, 1287 1881 const char *pszName, void *hLock, bool fSignaller) 1288 1882 { … … 1292 1886 pRec->Core.u32Magic = RTLOCKVALRECSHRD_MAGIC; 1293 1887 pRec->uSubClass = uSubClass; 1294 pRec->hClass = hClass;1888 pRec->hClass = rtLockValidatorClassValidateAndRetain(hClass); 1295 1889 pRec->hLock = hLock; 1296 1890 pRec->pszName = pszName; … … 1331 1925 1332 1926 ASMAtomicWriteU32(&pRec->Core.u32Magic, RTLOCKVALRECSHRD_MAGIC_DEAD); 1333 ASMAtomicUoWriteHandle(&pRec->hClass, NIL_RTLOCKVAL IDATORCLASS);1927 ASMAtomicUoWriteHandle(&pRec->hClass, NIL_RTLOCKVALCLASS); 1334 1928 if (pRec->papOwners) 1335 1929 { … … 1437 2031 */ 1438 2032 rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, pRecU); 1439 rtLockValidator CopySrcPos(&pThreadSelf->LockValidator.SrcPos, pSrcPos);2033 rtLockValidatorSrcPosCopy(&pThreadSelf->LockValidator.SrcPos, pSrcPos); 1440 2034 ASMAtomicWriteBool(&pThreadSelf->LockValidator.fInValidator, true); 1441 2035 pThreadSelf->LockValidator.enmRecState = enmSleepState; … … 1536 2130 pEntry->SrcPos = *pSrcPos; 1537 2131 else 1538 rtLockValidator InitSrcPos(&pEntry->SrcPos);2132 rtLockValidatorSrcPosInit(&pEntry->SrcPos); 1539 2133 return pEntry; 1540 2134 } … … 1880 2474 * Check the release order. 1881 2475 */ 1882 if (pRec->hClass != NIL_RTLOCKVAL IDATORCLASS)2476 if (pRec->hClass != NIL_RTLOCKVALCLASS) 1883 2477 { 1884 2478 /** @todo order validation */
Note:
See TracChangeset
for help on using the changeset viewer.