Changeset 25408 in vbox
- Timestamp:
- Dec 15, 2009 3:04:04 PM (15 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/AutoLock.cpp
r25368 r25408 1 1 /** @file 2 2 * 3 * Auto WriteLock/AutoReadLock: smart R/W semaphore wrappers3 * Automatic locks, implementation 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2006-200 0Sun Microsystems, Inc.7 * Copyright (C) 2006-2009 Sun Microsystems, Inc. 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 39 39 #include <iprt/path.h> 40 40 41 #include <VBox/com/string.h> 42 41 43 #include <vector> 42 44 #include <list> … … 47 49 //////////////////////////////////////////////////////////////////////////////// 48 50 // 49 // Global variables51 // Per-thread stacks for locking validation 50 52 // 51 53 //////////////////////////////////////////////////////////////////////////////// … … 82 84 83 85 typedef std::list<LockStackItem> LockHandlesList; 86 87 /** 88 * LockingStack class. One of these gets created for each thread 89 * that calls lock/unlock methods, and a pointer to this is 90 * stored in thread-local storage. 91 */ 84 92 struct LockingStack 85 93 { … … 97 105 98 106 LockHandlesList ll; 107 // first item (front) is newest, last item (back) is oldest; I'd do it 108 // the other way round but there is no implementation for erase(reverse_iterator) 109 // which I'd need otherwise 99 110 size_t c; 100 111 }; 101 112 113 /** 114 * Global helper that looks up the LockingStack structure for the 115 * current thread in thread-local storage, or creates one on the 116 * thread's first call. 117 */ 102 118 LockingStack* getThreadLocalLockingStack() 103 119 { … … 120 136 return pStack; 121 137 } 138 139 void dumpThreadLocalLockingStack(LockingStack *pStack) 140 { 141 uint32_t c = 0; 142 for (LockHandlesList::iterator it = pStack->ll.begin(); 143 it != pStack->ll.end(); 144 ++it) 145 { 146 LockStackItem lsi = *it; 147 LogFlow(("LOCKVAL: lock %d under top is [%s] locked by %s (%s:%u)\n", c, lsi.pLock->describe(), lsi.pcszFunction, lsi.pcszFile, lsi.uLine)); 148 ++c; 149 } 150 } 151 122 152 #endif 123 153 … … 129 159 130 160 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 161 162 /** 163 * If the lock validator is enabled, this gets called from the 164 * lock methods to push a LockStackItem onto the thread-local 165 * locking stack for tracing. 166 */ 131 167 void LockHandle::validateLock(LOCKVAL_SRC_POS_DECL) 132 168 { … … 134 170 LockingStack *pStack = getThreadLocalLockingStack(); 135 171 LockStackItem lsi(this, RT_SRC_POS_ARGS); 136 pStack->ll.push_ back(lsi);172 pStack->ll.push_front(lsi); 137 173 ++pStack->c; 138 174 139 LogFlow(("LOCKVAL: lock from %s (%s:%u), new count: %RI32\n", lsi.pcszFunction, lsi.pcszFile, lsi.uLine, (uint32_t)pStack->c)); 140 } 141 175 LogFlow(("LOCKVAL [%s]: lock from %s (%s:%u), new count: %RI32\n", describe(), lsi.pcszFunction, lsi.pcszFile, lsi.uLine, (uint32_t)pStack->c)); 176 } 177 178 /** 179 * If the lock validator is enabled, this gets called from the 180 * unlock methods to validate the unlock request. This pops the 181 * LockStackItem from the thread-local locking stack. 182 */ 142 183 void LockHandle::validateUnlock() 143 184 { … … 145 186 LockingStack *pStack = getThreadLocalLockingStack(); 146 187 147 LogFlow(("LOCKVAL: unlock, old count: %RI32\n", (uint32_t)pStack->c));148 149 188 AssertMsg(pStack->c == pStack->ll.size(), ("Locking size mismatch")); 150 189 AssertMsg(pStack->c > 0, ("Locking stack is empty when it should have current LockHandle on top")); 151 190 152 191 // validate that "this" is the top item on the stack 153 LockStackItem &lsiTop = pStack->ll. back();192 LockStackItem &lsiTop = pStack->ll.front(); 154 193 if (lsiTop.pLock != this) 155 194 { 156 // violation of unlocking order: "this" was not the last to be locked on this thread,195 // "this" was not the last to be locked on this thread; 157 196 // see if it's somewhere deep under the locks 197 dumpThreadLocalLockingStack(pStack); 198 158 199 bool fFound; 159 200 uint32_t c = 0; 160 201 for (LockHandlesList::iterator it = pStack->ll.begin(); 161 202 it != pStack->ll.end(); 162 ++it , ++c)203 ++it) 163 204 { 164 205 LockStackItem &lsiThis = *it; 165 206 if (lsiThis.pLock == this) 166 207 { 167 AssertMsgFailed(("Unlocking order violation: unlock attempted for LockHandle which is %d items under the top item\n", c));208 LogFlow(("LOCKVAL [%s]: unlock, stack item was %d items under the top item, corresponsing lock was at %s (%s:%u)\n", describe(), c, lsiThis.pcszFunction, lsiThis.pcszFile, lsiThis.uLine)); 168 209 pStack->ll.erase(it); 169 210 fFound = true; 170 211 break; 171 212 } 213 ++c; 172 214 } 173 215 174 216 if (!fFound) 217 { 218 LogFlow(("LOCKVAL [%s]: unlock, stack item not found!\n", describe())); 175 219 AssertMsgFailed(("Locking stack does not contain current LockHandle at all\n")); 220 } 176 221 } 177 222 else 178 pStack->ll.pop_back(); 223 { 224 pStack->ll.pop_front(); 225 LogFlow(("LOCKVAL [%s]: unlock, stack item was on top, old count: %RI32\n", describe(), (uint32_t)pStack->c)); 226 } 227 179 228 --pStack->c; 180 229 } 230 181 231 #endif // VBOX_WITH_DEBUG_LOCK_VALIDATOR 182 232 … … 193 243 194 244 RTSEMRW sem; 245 246 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 247 com::Utf8Str strDescription; 248 #endif 195 249 }; 196 250 … … 200 254 int vrc = RTSemRWCreate(&m->sem); 201 255 AssertRC(vrc); 256 257 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 258 m->strDescription = com::Utf8StrFmt("r/w %RCv", this); 259 #endif 202 260 } 203 261 … … 255 313 } 256 314 315 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 316 /*virtual*/ const char* RWLockHandle::describe() const 317 { 318 return m->strDescription.c_str(); 319 } 320 #endif 321 257 322 //////////////////////////////////////////////////////////////////////////////// 258 323 // … … 267 332 268 333 mutable RTCRITSECT sem; 334 335 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 336 com::Utf8Str strDescription; 337 #endif 269 338 }; 270 339 … … 273 342 m = new Data; 274 343 RTCritSectInit(&m->sem); 344 345 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 346 m->strDescription = com::Utf8StrFmt("crit %RCv", this); 347 #endif 275 348 } 276 349 … … 325 398 return RTCritSectGetRecursion(&m->sem); 326 399 } 400 401 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 402 /*virtual*/ const char* WriteLockHandle::describe() const 403 { 404 return m->strDescription.c_str(); 405 } 406 #endif 327 407 328 408 //////////////////////////////////////////////////////////////////////////////// … … 501 581 } 502 582 583 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 584 void AutoLockBase::dumpStack(const char *pcszMessage, RT_SRC_POS_DECL) 585 { 586 LockingStack *pStack = getThreadLocalLockingStack(); 587 LogFlow(("LOCKVAL DUMPSTACK at %s (%s:%u)\nLOCKVAL DUMPSTACK %s\n", pszFunction, pszFile, iLine, pcszMessage)); 588 dumpThreadLocalLockingStack(pStack); 589 } 590 #endif 591 503 592 //////////////////////////////////////////////////////////////////////////////// 504 593 // … … 611 700 612 701 // unlock in reverse order! 613 uint32_t i = 0;702 uint32_t i = m->aHandles.size(); 614 703 for (HandlesVector::reverse_iterator it = m->aHandles.rbegin(); 615 704 it != m->aHandles.rend(); 616 705 ++it) 617 706 { 707 --i; // array index is zero based, decrement with every loop since we iterate backwards 618 708 LockHandle *pHandle = *it; 619 709 if (pHandle) … … 623 713 AssertMsg(m->acUnlockedInLeave[i] >= 1, ("m->cUnlockedInLeave[%d] is %d, must be >=1!", i, m->acUnlockedInLeave[i])); 624 714 715 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 716 LogFlowFunc(("LOCKVAL: will unlock handle %d [%s] %d times\n", i, pHandle->describe(), m->acUnlockedInLeave[i])); 717 #endif 718 625 719 for (uint32_t left = m->acUnlockedInLeave[i]; 626 720 left; … … 628 722 callUnlockImpl(*pHandle); 629 723 } 630 ++i;631 724 } 632 725 } … … 652 745 AssertMsg(m->acUnlockedInLeave[i] != 0, ("m->cUnlockedInLeave[%d] is 0! enter() without leave()?", i)); 653 746 747 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 748 LogFlowFunc(("LOCKVAL: will lock handle %d [%s] %d times\n", i, pHandle->describe(), m->acUnlockedInLeave[i])); 749 #endif 750 654 751 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i]) 655 752 callLockImpl(*pHandle); … … 667 764 { 668 765 // unlock in reverse order! 669 uint32_t i = 0;766 uint32_t i = m->aHandles.size(); 670 767 for (HandlesVector::reverse_iterator it = m->aHandles.rbegin(); 671 768 it != m->aHandles.rend(); 672 769 ++it) 673 770 { 771 --i; // array index is zero based, decrement with every loop since we iterate backwards 674 772 LockHandle *pHandle = *it; 675 773 if (pHandle) … … 680 778 AssertMsg(m->acUnlockedInLeave[i] >= 1, ("m->cUnlockedInLeave[%d] is %d, must be >=1!", i, m->acUnlockedInLeave[i])); 681 779 780 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 781 LogFlowFunc(("LOCKVAL: will unlock handle %d [%s] %d times\n", i, pHandle->describe(), m->acUnlockedInLeave[i])); 782 #endif 783 682 784 for (uint32_t left = m->acUnlockedInLeave[i]; 683 785 left; … … 707 809 if (!pHandle->isWriteLockOnCurrentThread()) 708 810 { 811 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 812 LogFlowFunc(("LOCKVAL: will lock handle %d [%s] %d times\n", i, pHandle->describe(), m->acUnlockedInLeave[i])); 813 #endif 814 709 815 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i]) 710 816 callLockImpl(*pHandle); -
trunk/src/VBox/Main/include/AutoLock.h
r25310 r25408 1 1 /** @file 2 2 * 3 * Auto WriteLock/AutoReadLock: smart R/W semaphore wrappers3 * Automatic locks, implementation 4 4 */ 5 5 … … 25 25 #include <iprt/types.h> 26 26 27 // macros for automatic lock validation; 28 // use VBOX_WITH_LOCK_VALIDATOR to enable for debug mode 27 29 #ifdef DEBUG 28 30 # ifdef VBOX_WITH_LOCK_VALIDATOR … … 56 58 /** 57 59 * Abstract base class for semaphore handles (RWLockHandle and WriteLockHandle). 60 * Don't use this directly, but this implements lock validation for them. 58 61 */ 59 62 class LockHandle … … 79 82 virtual uint32_t writeLockLevel() const = 0; 80 83 81 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR82 void validateLock(LOCKVAL_SRC_POS_DECL);83 void validateUnlock();84 #endif85 86 84 virtual void lockWrite(LOCKVAL_SRC_POS_DECL) = 0; 87 85 virtual void unlockWrite() = 0; … … 89 87 virtual void unlockRead() = 0; 90 88 89 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 90 void validateLock(LOCKVAL_SRC_POS_DECL); 91 void validateUnlock(); 92 virtual const char* describe() const = 0; 93 #endif 94 91 95 static RTTLS s_lockingStackTlsIndex; 92 96 … … 119 123 120 124 virtual uint32_t writeLockLevel() const; 125 126 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 127 virtual const char* describe() const; 128 #endif 121 129 122 130 private: … … 151 159 virtual uint32_t writeLockLevel() const; 152 160 161 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 162 virtual const char* describe() const; 163 #endif 164 153 165 private: 154 166 struct Data; … … 235 247 void release(); 236 248 249 #ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR 250 void dumpStack(const char *pcszMessage, RT_SRC_POS_DECL); 251 #endif 252 237 253 private: 238 254 // prohibit copy + assignment … … 250 266 * Automatic read lock. Use this with a RWLockHandle to request a read/write 251 267 * semaphore in read mode. You can also use this with a WriteLockHandle but 252 * that makes little sense since they know no readmode.268 * that makes little sense since they treat read mode like write mode. 253 269 * 254 270 * If constructed with a RWLockHandle or an instance of Lockable (which in … … 342 358 * 343 359 * This cannot be used directly. Use AutoWriteLock or AutoMultiWriteLock2/3 344 * which d irectly and indirectly derive from this.360 * which derive from this. 345 361 * 346 362 * In addition to utility methods for subclasses, this implements the public
Note:
See TracChangeset
for help on using the changeset viewer.