- Timestamp:
- Jun 25, 2009 12:27:02 PM (16 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/AutoLock.cpp
r16310 r20932 20 20 */ 21 21 22 #ifdef VBOX_MAIN_AUTOLOCK_TRAP23 // workaround for compile problems on gcc 4.124 # ifdef __GNUC__25 # pragma GCC visibility push(default)26 # endif27 #endif28 29 22 #include "AutoLock.h" 30 23 … … 33 26 #include <iprt/string.h> 34 27 35 #ifdef VBOX_MAIN_AUTOLOCK_TRAP36 # if defined (RT_OS_LINUX)37 # include <signal.h>38 # include <execinfo.h>39 /* get REG_EIP from ucontext.h */40 # ifndef __USE_GNU41 # define __USE_GNU42 # endif43 # include <ucontext.h>44 # ifdef RT_ARCH_AMD6445 # define REG_PC REG_RIP46 # else47 # define REG_PC REG_EIP48 # endif49 # endif50 #endif /* VBOX_MAIN_AUTOLOCK_TRAP */51 28 52 29 namespace util 53 30 { 54 31 55 #ifdef VBOX_MAIN_AUTOLOCK_TRAP56 57 namespace internal58 {59 60 struct TLS61 {62 struct Uint32_t63 {64 Uint32_t() : raw (0) {}65 operator uint32_t &() { return raw; }66 uint32_t raw;67 };68 69 typedef std::map <RWLockHandle *, Uint32_t> HandleMap;70 HandleMap handles; /*< handle reference counter on the current thread */71 };72 73 /**74 * Global module initialization structure.75 *76 * The constructor and destructor of this structure are used to perform global77 * module initiaizaton and cleanup. Thee must be only one global variable of78 * this structure.79 */80 static81 class Global82 {83 public:84 85 Global() : tlsID (NIL_RTTLS)86 {87 #if defined (RT_OS_LINUX) /** @todo r=bird: Why only linux? All but windows supports destructors... */88 int vrc = RTTlsAllocEx (&tlsID, TLSDestructor);89 AssertRC (vrc);90 #else91 tlsID = RTTlsAlloc();92 Assert (tlsID != NIL_RTTLS);93 #endif94 }95 96 ~Global()97 {98 RTTlsFree (tlsID);99 }100 101 TLS *tls() const102 {103 TLS *tls = NULL;104 if (tlsID != NIL_RTTLS)105 {106 tls = static_cast <TLS *> (RTTlsGet (tlsID));107 if (tls == NULL)108 {109 tls = new TLS();110 RTTlsSet (tlsID, tls);111 }112 }113 114 return tls;115 }116 117 RTTLS tlsID;118 }119 gGlobal;120 121 DECLCALLBACK(void) TLSDestructor (void *aValue)122 {123 if (aValue != NULL)124 {125 TLS *tls = static_cast <TLS *> (aValue);126 RWLockHandle::TLSDestructor (tls);127 delete tls;128 }129 }130 131 } /* namespace internal */132 133 #endif /* VBOX_MAIN_AUTOLOCK_TRAP */134 135 136 32 RWLockHandle::RWLockHandle() 137 33 { 138 #ifdef VBOX_MAIN_USE_SEMRW139 140 34 int vrc = RTSemRWCreate (&mSemRW); 141 35 AssertRC (vrc); 142 143 #else /* !VBOX_MAIN_USE_SEMRW */144 145 int vrc = RTCritSectInit (&mCritSect);146 AssertRC (vrc);147 vrc = RTSemEventCreate (&mGoWriteSem);148 AssertRC (vrc);149 vrc = RTSemEventMultiCreate (&mGoReadSem);150 AssertRC (vrc);151 152 mWriteLockThread = NIL_RTNATIVETHREAD;153 154 mReadLockCount = 0;155 mSelfReadLockCount = 0;156 157 mWriteLockLevel = 0;158 mWriteLockPending = 0;159 160 #endif /* !VBOX_MAIN_USE_SEMRW */161 36 } 162 37 … … 164 39 RWLockHandle::~RWLockHandle() 165 40 { 166 #ifdef VBOX_MAIN_USE_SEMRW167 168 41 RTSemRWDestroy (mSemRW); 169 170 #else /* !VBOX_MAIN_USE_SEMRW */171 172 RTSemEventMultiDestroy (mGoReadSem);173 RTSemEventDestroy (mGoWriteSem);174 RTCritSectDelete (&mCritSect);175 176 #endif /* !VBOX_MAIN_USE_SEMRW */177 42 } 178 43 … … 180 45 bool RWLockHandle::isWriteLockOnCurrentThread() const 181 46 { 182 #ifdef VBOX_MAIN_USE_SEMRW183 184 47 return RTSemRWIsWriteOwner (mSemRW); 185 186 #else /* !VBOX_MAIN_USE_SEMRW */187 188 RTCritSectEnter (&mCritSect);189 bool locked = mWriteLockThread == RTThreadNativeSelf();190 RTCritSectLeave (&mCritSect);191 return locked;192 193 #endif /* !VBOX_MAIN_USE_SEMRW */194 48 } 195 49 … … 197 51 void RWLockHandle::lockWrite() 198 52 { 199 #ifdef VBOX_MAIN_USE_SEMRW200 201 53 int vrc = RTSemRWRequestWrite (mSemRW, RT_INDEFINITE_WAIT); 202 54 AssertRC (vrc); 203 204 #else /* !VBOX_MAIN_USE_SEMRW */205 206 RTCritSectEnter (&mCritSect);207 208 RTNATIVETHREAD threadSelf = RTThreadNativeSelf();209 210 if (mWriteLockThread != threadSelf)211 {212 # ifdef VBOX_MAIN_AUTOLOCK_TRAP213 if (mReadLockCount != 0)214 {215 using namespace internal;216 TLS *tls = gGlobal.tls();217 if (tls != NULL)218 {219 TLS::HandleMap::const_iterator it = tls->handles.find (this);220 if (it != tls->handles.end() && it->second.raw != 0)221 {222 /* if there is a writer then the handle reference counter equals223 * to the number of readers on the current thread plus 1 */224 225 uint32_t readers = it->second.raw;226 if (mWriteLockThread != NIL_RTNATIVETHREAD)227 -- readers;228 229 std::string info;230 gatherInfo (info);231 232 AssertReleaseMsgFailedReturnVoid ((233 "DETECTED SELF DEADLOCK on Thread %08x: lockWrite() after "234 "lockRead(): reader count = %d!\n%s\n",235 threadSelf, readers, info.c_str()));236 }237 }238 }239 # endif /* VBOX_MAIN_AUTOLOCK_TRAP */240 241 if (mReadLockCount != 0 || mWriteLockThread != NIL_RTNATIVETHREAD ||242 mWriteLockPending != 0 /* respect other pending writers */)243 {244 /* wait until all read locks or another write lock is released */245 ++ mWriteLockPending;246 Assert (mWriteLockPending != 0 /* pending writer overflow? */);247 RTCritSectLeave (&mCritSect);248 RTSemEventWait (mGoWriteSem, RT_INDEFINITE_WAIT);249 RTCritSectEnter (&mCritSect);250 -- mWriteLockPending;251 }252 253 Assert (mWriteLockLevel == 0);254 Assert (mWriteLockThread == NIL_RTNATIVETHREAD);255 Assert (mSelfReadLockCount == 0 /* missing unlockRead()? */);256 257 mWriteLockThread = threadSelf;258 }259 260 ++ mWriteLockLevel;261 Assert (mWriteLockLevel != 0 /* overflow */);262 263 # ifdef VBOX_MAIN_AUTOLOCK_TRAP264 logOp (LockWrite);265 # endif266 267 RTCritSectLeave (&mCritSect);268 269 # ifdef DEBUG270 if (mWriteLockLevel == 1)271 {272 RTTHREAD iprtThreadSelf = RTThreadSelf();273 if (iprtThreadSelf != NIL_RTTHREAD)274 RTThreadWriteLockInc (iprtThreadSelf);275 }276 # endif277 278 #endif /* !VBOX_MAIN_USE_SEMRW */279 55 } 280 56 … … 282 58 void RWLockHandle::unlockWrite() 283 59 { 284 #ifdef VBOX_MAIN_USE_SEMRW285 286 60 int vrc = RTSemRWReleaseWrite (mSemRW); 287 61 AssertRC (vrc); 288 289 #else /* !VBOX_MAIN_USE_SEMRW */290 291 RTCritSectEnter (&mCritSect);292 293 RTNATIVETHREAD threadSelf = RTThreadNativeSelf();294 295 Assert (mWriteLockLevel != 0 /* unlockWrite() w/o preceding lockWrite()? */);296 if (mWriteLockLevel != 0)297 {298 Assert (mWriteLockThread == threadSelf299 /* unlockWrite() w/o preceding lockWrite()? */);300 if (mWriteLockThread == threadSelf)301 {302 -- mWriteLockLevel;303 if (mWriteLockLevel == 0)304 {305 Assert (mSelfReadLockCount == 0306 /* mixed unlockWrite()/unlockRead() order? */);307 308 mWriteLockThread = NIL_RTNATIVETHREAD;309 310 /* no write locks, let writers go if there are any (top priority),311 * otherwise let readers go if there are any */312 if (mWriteLockPending != 0)313 RTSemEventSignal (mGoWriteSem);314 else if (mReadLockCount != 0)315 RTSemEventMultiSignal (mGoReadSem);316 317 # ifdef DEBUG318 RTTHREAD iprtThreadSelf = RTThreadSelf();319 if (iprtThreadSelf != NIL_RTTHREAD)320 RTThreadWriteLockDec (iprtThreadSelf);321 # endif322 }323 }324 }325 326 # ifdef VBOX_MAIN_AUTOLOCK_TRAP327 logOp (UnlockWrite);328 # endif329 330 RTCritSectLeave (&mCritSect);331 332 #endif /* !VBOX_MAIN_USE_SEMRW */333 62 } 334 63 … … 336 65 void RWLockHandle::lockRead() 337 66 { 338 #ifdef VBOX_MAIN_USE_SEMRW339 340 67 int vrc = RTSemRWRequestRead (mSemRW, RT_INDEFINITE_WAIT); 341 68 AssertRC (vrc); 342 343 #else /* !VBOX_MAIN_USE_SEMRW */344 345 RTCritSectEnter (&mCritSect);346 347 RTNATIVETHREAD threadSelf = RTThreadNativeSelf();348 349 # ifdef VBOX_MAIN_AUTOLOCK_TRAP350 logOp (LockRead);351 # endif /* VBOX_MAIN_AUTOLOCK_TRAP */352 353 bool isWriteLock = mWriteLockLevel != 0;354 bool isFirstReadLock = mReadLockCount == 0;355 356 if (isWriteLock && mWriteLockThread == threadSelf)357 {358 /* read lock nested into the write lock */359 ++ mSelfReadLockCount;360 Assert (mSelfReadLockCount != 0 /* self read lock overflow? */);361 362 /* cause to return immediately */363 isWriteLock = false;364 }365 else366 {367 ++ mReadLockCount;368 Assert (mReadLockCount != 0 /* read lock overflow? */);369 370 if (!isWriteLock)371 {372 Assert (mSelfReadLockCount == 0 /* missing unlockRead()? */);373 374 /* write locks are top priority, so let them go if they are375 * pending and we're the only reader so far */376 if (mWriteLockPending != 0 && isFirstReadLock)377 {378 isWriteLock = true;379 /* note that we must not signal mGoWriteSem here because it380 * has been already signaled by unlockWrite() or by381 * unlockRead() */382 }383 }384 385 /* the first waiting reader resets the semaphore before letting it be386 * posted (i.e. before leaving the critical section) */387 if (isWriteLock && isFirstReadLock)388 RTSemEventMultiReset (mGoReadSem);389 }390 391 RTCritSectLeave (&mCritSect);392 393 /* wait until the write lock is released */394 if (isWriteLock)395 RTSemEventMultiWait (mGoReadSem, RT_INDEFINITE_WAIT);396 397 # ifdef DEBUG398 RTTHREAD iprtThreadSelf = RTThreadSelf();399 if (iprtThreadSelf != NIL_RTTHREAD)400 RTThreadReadLockInc (iprtThreadSelf);401 # endif402 403 #endif /* !VBOX_MAIN_USE_SEMRW */404 69 } 405 70 … … 407 72 void RWLockHandle::unlockRead() 408 73 { 409 #ifdef VBOX_MAIN_USE_SEMRW410 411 74 int vrc = RTSemRWReleaseRead (mSemRW); 412 75 AssertRC (vrc); 413 414 #else /* !VBOX_MAIN_USE_SEMRW */415 416 RTCritSectEnter (&mCritSect);417 418 RTNATIVETHREAD threadSelf = RTThreadNativeSelf();419 420 if (mWriteLockLevel != 0)421 {422 /* read unlock nested into the write lock */423 Assert (mWriteLockThread == threadSelf424 /* unlockRead() after lockWrite()? */);425 if (mWriteLockThread == threadSelf)426 {427 Assert (mSelfReadLockCount != 0428 /* unlockRead() w/o preceding lockRead()? */);429 if (mSelfReadLockCount != 0)430 {431 -- mSelfReadLockCount;432 433 # ifdef VBOX_MAIN_AUTOLOCK_TRAP434 logOp (UnlockRead);435 # endif /* VBOX_MAIN_AUTOLOCK_TRAP */436 }437 }438 }439 else440 {441 Assert (mReadLockCount != 0442 /* unlockRead() w/o preceding lockRead()? */);443 if (mReadLockCount != 0)444 {445 -- mReadLockCount;446 if (mReadLockCount == 0)447 {448 /* no read locks, let writers go if there are any */449 if (mWriteLockPending != 0)450 RTSemEventSignal (mGoWriteSem);451 }452 453 # ifdef VBOX_MAIN_AUTOLOCK_TRAP454 logOp (UnlockRead);455 # endif /* VBOX_MAIN_AUTOLOCK_TRAP */456 }457 }458 459 RTCritSectLeave (&mCritSect);460 461 # ifdef DEBUG462 RTTHREAD iprtThreadSelf = RTThreadSelf();463 if (iprtThreadSelf != NIL_RTTHREAD)464 RTThreadReadLockDec (iprtThreadSelf);465 # endif466 467 #endif /* !VBOX_MAIN_USE_SEMRW */468 76 } 469 77 … … 471 79 uint32_t RWLockHandle::writeLockLevel() const 472 80 { 473 #ifdef VBOX_MAIN_USE_SEMRW474 475 81 return RTSemRWGetWriteRecursion (mSemRW); 476 477 #else /* !VBOX_MAIN_USE_SEMRW */478 479 Assert (mWriteLockLevel != 0);480 481 return mWriteLockLevel;482 483 #endif /* !VBOX_MAIN_USE_SEMRW */484 82 } 485 486 487 #ifdef VBOX_MAIN_AUTOLOCK_TRAP488 489 void RWLockHandle::logOp (Operation aOp)490 {491 std::string info;492 493 char buf [256];494 RTStrPrintf (buf, sizeof (buf), "[%c] Thread %08x (%s)\n",495 aOp == LockRead ? 'r' : aOp == LockWrite ? 'w' : '?',496 RTThreadNativeSelf(), RTThreadGetName (RTThreadSelf()));497 info += buf;498 499 # if defined (RT_OS_LINUX)500 501 void *trace [16];502 char **messages = (char **) NULL;503 int i, trace_size = 0;504 trace_size = backtrace (trace, 16);505 506 messages = backtrace_symbols (trace, trace_size);507 /* skip first stack frame (points here) and the second stack frame (points508 * to lockRead()/lockWrite() */509 for (i = 2; i < trace_size; ++i)510 (info += messages[i]) += "\n";511 512 free (messages);513 514 # endif /* defined (RT_OS_LINUX) */515 516 internal::TLS *tls = internal::gGlobal.tls();517 if (tls != NULL)518 {519 520 switch (aOp)521 {522 case LockRead:523 {524 mReaderInfo.push_back (info);525 ++ tls->handles [this];526 break;527 }528 case UnlockRead:529 {530 mReaderInfo.pop_back();531 -- tls->handles [this];532 break;533 }534 case LockWrite:535 {536 mWriterInfo = info;537 ++ tls->handles [this];538 break;539 }540 case UnlockWrite:541 {542 mWriterInfo.clear();;543 -- tls->handles [this];544 break;545 }546 }547 }548 }549 550 void RWLockHandle::gatherInfo (std::string &aInfo)551 {552 char buf [256];553 RTStrPrintf (buf, sizeof (buf),554 "[*] RWLockHandle %x:\n", this,555 RTThreadNativeSelf(), RTThreadGetName (RTThreadSelf()));556 aInfo += buf;557 558 /* add reader info */559 for (ReaderInfo::const_iterator it = mReaderInfo.begin();560 it != mReaderInfo.end(); ++ it)561 {562 aInfo += *it;563 }564 /* add writer info */565 if (!mWriterInfo.empty())566 aInfo += mWriterInfo;567 }568 569 /* static */570 void RWLockHandle::TLSDestructor (internal::TLS *aTLS)571 {572 using namespace internal;573 574 if (aTLS != NULL && aTLS->handles.size())575 {576 std::string info;577 size_t cnt = 0;578 579 for (TLS::HandleMap::const_iterator it = aTLS->handles.begin();580 it != aTLS->handles.end(); ++ it)581 {582 if (it->second.raw != 0)583 {584 it->first->gatherInfo (info);585 ++ cnt;586 }587 }588 589 if (cnt != 0)590 {591 AssertReleaseMsgFailed ((592 "DETECTED %d HELD RWLockHandle's on Thread %08x!\n%s\n",593 cnt, RTThreadNativeSelf(), info.c_str()));594 }595 }596 }597 598 #endif /* ifdef VBOX_MAIN_AUTOLOCK_TRAP */599 600 83 601 84 } /* namespace util */ -
trunk/src/VBox/Main/Makefile.kmk
r20928 r20932 64 64 $(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \ 65 65 $(if $(VBOX_WITH_HOSTNETIF_API),VBOX_WITH_HOSTNETIF_API,) 66 67 # Unconditionally use the RW semaphores from IPRT in AutoLock68 VBOX_MAIN_DEFS += VBOX_MAIN_USE_SEMRW69 66 70 67 # Unconditionally enable the new semaphore key generation code -
trunk/src/VBox/Main/include/AutoLock.h
r14949 r20932 36 36 #endif 37 37 38 #ifdef VBOX_MAIN_USE_SEMRW 39 # include <iprt/semaphore.h> 40 #else 41 # ifdef VBOX_MAIN_AUTOLOCK_TRAP 42 # include <map> 43 # include <list> 44 # include <string> 45 # endif 46 #endif 38 #include <iprt/semaphore.h> 47 39 48 40 namespace util 49 41 { 50 51 #ifdef VBOX_MAIN_AUTOLOCK_TRAP52 namespace internal53 {54 struct TLS;55 DECLCALLBACK(void) TLSDestructor (void *aValue);56 }57 #endif /* VBOX_MAIN_AUTOLOCK_TRAP */58 42 59 43 /** … … 195 179 uint32_t writeLockLevel() const; 196 180 197 #ifdef VBOX_MAIN_USE_SEMRW198 199 181 RTSEMRW mSemRW; 200 201 #else /* VBOX_MAIN_USE_SEMRW */202 203 mutable RTCRITSECT mCritSect;204 RTSEMEVENT mGoWriteSem;205 RTSEMEVENTMULTI mGoReadSem;206 207 RTNATIVETHREAD mWriteLockThread;208 209 uint32_t mReadLockCount; /*< Number of read locks */210 uint32_t mSelfReadLockCount; /*< Number of read locks nested in write lock */211 212 uint32_t mWriteLockLevel;213 uint32_t mWriteLockPending;214 215 # ifdef VBOX_MAIN_AUTOLOCK_TRAP216 217 enum Operation { LockRead, UnlockRead, LockWrite, UnlockWrite };218 void logOp (Operation aOp);219 void gatherInfo (std::string &aInfo);220 221 friend DECLCALLBACK(void) internal::TLSDestructor (void *aValue);222 static void TLSDestructor (internal::TLS *aTLS);223 224 typedef std::list <std::string> ReaderInfo;225 ReaderInfo mReaderInfo;226 std::string mWriterInfo;227 228 # endif /* VBOX_MAIN_AUTOLOCK_TRAP */229 230 #endif /* VBOX_MAIN_USE_SEMRW */231 182 }; 232 183
Note:
See TracChangeset
for help on using the changeset viewer.