Changeset 25406 in vbox for trunk/src/VBox/Runtime/common
- Timestamp:
- Dec 15, 2009 2:23:53 PM (15 years ago)
- Location:
- trunk/src/VBox/Runtime/common/misc
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp
r25373 r25406 43 43 #include <iprt/thread.h> 44 44 45 #include "internal/lockvalidator.h" 45 46 #include "internal/magics.h" 47 #include "internal/thread.h" 46 48 47 49 … … 69 71 pRec->hClass = hClass; 70 72 pRec->uSubClass = uSubClass; 71 pRec-> u32Reserved = UINT32_MAX;73 pRec->cRecursion = 0; 72 74 pRec->hLock = hLock; 73 75 pRec->pszName = pszName; … … 84 86 85 87 RTLockValidatorInit(pRec, hClass, uSubClass, pszName, pvLock); 86 pRec->u32Reserved = UINT32_MAX / 2;87 88 88 89 return VINF_SUCCESS; … … 93 94 { 94 95 Assert(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC); 95 Assert(pRec->u32Reserved == UINT32_MAX);96 96 97 97 ASMAtomicWriteU32(&pRec->u32Magic, RTLOCKVALIDATORREC_MAGIC_DEAD); 98 98 ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD); 99 99 ASMAtomicWriteHandle(&pRec->hClass, NIL_RTLOCKVALIDATORCLASS); 100 ASMAtomicWriteU32(&pRec->u32Reserved, 0);101 100 } 102 101 … … 108 107 if (pRec) 109 108 { 110 Assert(pRec->u32Reserved == UINT32_MAX / 2);111 pRec->u32Reserved = UINT32_MAX;112 109 RTLockValidatorDelete(pRec); 113 110 RTMemFree(pRec); … … 136 133 { 137 134 AssertReturn(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC, NIL_RTTHREAD); 138 Assert(pRec->hThread == NIL_RTTHREAD);139 140 /*141 * Update the record.142 */143 ASMAtomicUoWriteU32(&pRec->uLine, iLine);144 ASMAtomicUoWritePtr((void * volatile *)&pRec->pszFile, pszFile);145 ASMAtomicUoWritePtr((void * volatile *)&pRec->pszFunction, pszFunction);146 ASMAtomicUoWritePtr((void * volatile *)&pRec->uId, (void *)uId);147 135 148 136 if (hThread == NIL_RTTHREAD) 149 #ifdef IN_RING3150 137 hThread = RTThreadSelfAutoAdopt(); 151 #else 152 hThread = RTThreadSelf(); 153 #endif 154 ASMAtomicWriteHandle(&pRec->hThread, hThread); 155 156 /* 157 * Push the lock onto the lock stack. 158 */ 159 /** @todo push it onto the per-thread lock stack. */ 138 if (pRec->hThread == hThread) 139 pRec->cRecursion++; 140 else 141 { 142 Assert(pRec->hThread == NIL_RTTHREAD); 143 144 /* 145 * Update the record. 146 */ 147 ASMAtomicUoWriteU32(&pRec->uLine, iLine); 148 ASMAtomicUoWritePtr((void * volatile *)&pRec->pszFile, pszFile); 149 ASMAtomicUoWritePtr((void * volatile *)&pRec->pszFunction, pszFunction); 150 ASMAtomicUoWritePtr((void * volatile *)&pRec->uId, (void *)uId); 151 ASMAtomicUoWriteU32(&pRec->cRecursion, 1); 152 153 ASMAtomicWriteHandle(&pRec->hThread, hThread); 154 155 /* 156 * Push the lock onto the lock stack. 157 */ 158 /** @todo push it onto the per-thread lock stack. */ 159 } 160 160 161 161 return hThread; … … 168 168 RTTHREAD hThread = pRec->hThread; 169 169 AssertReturn(hThread != NIL_RTTHREAD, hThread); 170 171 /* 172 * Pop (remove) the lock. 173 */ 174 /** @todo remove it from the per-thread stack/whatever. */ 175 176 /* 177 * Update the record. 178 */ 179 ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD); 170 AssertReturn(pRec->hThread == hThread, hThread); 171 172 if (ASMAtomicDecU32(&pRec->cRecursion) == 0) 173 { 174 /* 175 * Pop (remove) the lock. 176 */ 177 /** @todo remove it from the per-thread stack/whatever. */ 178 179 /* 180 * Update the record. 181 */ 182 ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD); 183 } 180 184 181 185 return hThread; 182 186 } 183 187 188 189 /** 190 * Bitch about a deadlock. 191 * 192 * @param pRec The lock validator record we're going to block on. 193 * @param pThread This thread. 194 * @param pCur The thread we're deadlocking with. 195 * @param enmState The sleep state. 196 * @param RT_SRC_POS_DECL Where we are going to deadlock. 197 * @param uId Where we are going to deadlock. 198 */ 199 static void rtLockValidatorComplainAboutDeadlock(PRTLOCKVALIDATORREC pRec, PRTTHREADINT pThread, RTTHREADSTATE enmState, 200 PRTTHREADINT pCur, RTHCUINTPTR uId, RT_SRC_POS_DECL) 201 { 202 AssertMsg1(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", iLine, pszFile, pszFunction); 203 204 /* 205 * Print the threads and locks involved. 206 */ 207 PRTTHREADINT apSeenThreads[8] = {0,0,0,0,0,0,0,0}; 208 unsigned iSeenThread = 0; 209 pCur = pThread; 210 for (unsigned iEntry = 0; pCur && iEntry < 256; iEntry++) 211 { 212 /* 213 * Print info on pCur. Determin next while doing so. 214 */ 215 AssertMsg2(" #%u: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n", 216 iEntry, pCur, pCur->Core.Key, pCur->szName, 217 pCur->LockValidator.pszBlockFile, pCur->LockValidator.uBlockLine, 218 pCur->LockValidator.pszBlockFunction, pCur->LockValidator.uBlockId); 219 PRTTHREADINT pNext = NULL; 220 RTTHREADSTATE enmCurState = rtThreadGetState(pCur); 221 switch (enmCurState) 222 { 223 case RTTHREADSTATE_CRITSECT: 224 case RTTHREADSTATE_EVENT: 225 case RTTHREADSTATE_EVENT_MULTI: 226 case RTTHREADSTATE_FAST_MUTEX: 227 case RTTHREADSTATE_MUTEX: 228 case RTTHREADSTATE_RW_READ: 229 case RTTHREADSTATE_RW_WRITE: 230 case RTTHREADSTATE_SPIN_MUTEX: 231 { 232 PRTLOCKVALIDATORREC pCurRec = pCur->LockValidator.pRec; 233 RTTHREADSTATE enmCurState2 = rtThreadGetState(pCur); 234 if (enmCurState2 != enmCurState) 235 { 236 AssertMsg2(" Impossible!!! enmState=%s -> %s (%d)\n", 237 RTThreadStateName(enmCurState), RTThreadStateName(enmCurState2), enmCurState2); 238 break; 239 } 240 if ( VALID_PTR(pCurRec) 241 && pCurRec->u32Magic == RTLOCKVALIDATORREC_MAGIC) 242 { 243 AssertMsg2(" Waiting on %s %p [%s]: Entered %s(%u) %s %p\n", 244 RTThreadStateName(enmCurState), pCurRec->hLock, pCurRec->pszName, 245 pCurRec->pszFile, pCurRec->uLine, pCurRec->pszFunction, pCurRec->uId); 246 pNext = pCurRec->hThread; 247 } 248 else if (VALID_PTR(pCurRec)) 249 AssertMsg2(" Waiting on %s pCurRec=%p: invalid magic number: %#x\n", 250 RTThreadStateName(enmCurState), pCurRec, pCurRec->u32Magic); 251 else 252 AssertMsg2(" Waiting on %s pCurRec=%p: invalid pointer\n", 253 RTThreadStateName(enmCurState), pCurRec); 254 break; 255 } 256 257 default: 258 AssertMsg2(" Impossible!!! enmState=%s (%d)\n", RTThreadStateName(enmCurState), enmCurState); 259 break; 260 } 261 262 /* 263 * Check for cycle. 264 */ 265 if (iEntry && pCur == pThread) 266 break; 267 for (unsigned i = 0; i < RT_ELEMENTS(apSeenThreads); i++) 268 if (apSeenThreads[i] == pCur) 269 { 270 AssertMsg2(" Cycle!\n"); 271 pNext = NULL; 272 break; 273 } 274 275 /* 276 * Advance to the next thread. 277 */ 278 iSeenThread = (iSeenThread + 1) % RT_ELEMENTS(apSeenThreads); 279 apSeenThreads[iSeenThread] = pCur; 280 pCur = pNext; 281 } 282 AssertBreakpoint(); 283 } 284 285 286 /** 287 * Change the thread state to blocking and do deadlock detection. 288 * 289 * @param pRec The validator record we're blocing on. 290 * @param hThread The current thread. Shall not be NIL_RTTHREAD! 291 * @param enmState The sleep state. 292 * @param pvBlock Pointer to a RTLOCKVALIDATORREC structure. 293 * @param fRecursiveOk Whether it's ok to recurse. 294 * @param uId Where we are blocking. 295 * @param RT_SRC_POS_DECL Where we are blocking. 296 */ 297 RTDECL(void) RTLockValidatorCheckBlocking(PRTLOCKVALIDATORREC pRec, RTTHREAD hThread, 298 RTTHREADSTATE enmState, bool fRecursiveOk, 299 RTHCUINTPTR uId, RT_SRC_POS_DECL) 300 { 301 /* 302 * Fend off wild life. 303 */ 304 AssertReturnVoid(RTTHREAD_IS_SLEEPING(enmState)); 305 AssertPtrReturnVoid(pRec); 306 AssertReturnVoid(pRec->u32Magic == RTLOCKVALIDATORREC_MAGIC); 307 PRTTHREADINT pThread = hThread; 308 AssertPtrReturnVoid(pThread); 309 AssertReturnVoid(pThread->u32Magic == RTTHREADINT_MAGIC); 310 AssertReturnVoid(rtThreadGetState(pThread) == RTTHREADSTATE_RUNNING); 311 312 /* 313 * Record the location and everything before changing the state and 314 * performing deadlock detection. 315 */ 316 /** @todo This has to be serialized! The deadlock detection isn't 100% safe!!! */ 317 pThread->LockValidator.pRec = pRec; 318 pThread->LockValidator.pszBlockFunction = pszFunction; 319 pThread->LockValidator.pszBlockFile = pszFile; 320 pThread->LockValidator.uBlockLine = iLine; 321 pThread->LockValidator.uBlockId = uId; 322 323 RTThreadBlocking(hThread, enmState); 324 325 /* 326 * Don't do deadlock detection if we're recursing and that's OK. 327 * 328 * On some hosts we don't do recursion accounting our selves and there 329 * isn't any other place to check for this. semmutex-win.cpp for instance. 330 */ 331 if ( !fRecursiveOk 332 || pRec->hThread != pThread) 333 { 334 /* 335 * Do deadlock detection. 336 * 337 * Since we're missing proper serialization, we don't declare it a 338 * deadlock until we've got three runs with the same list length. 339 * While this isn't perfect, it should avoid out the most obvious 340 * races on SMP boxes. 341 */ 342 PRTTHREADINT pCur; 343 unsigned cPrevLength = ~0U; 344 unsigned cEqualRuns = 0; 345 unsigned iParanoia = 256; 346 do 347 { 348 unsigned cLength = 0; 349 pCur = pThread; 350 for (;;) 351 { 352 /* 353 * Get the next thread. 354 */ 355 PRTTHREADINT pNext = NULL; 356 for (;;) 357 { 358 RTTHREADSTATE enmCurState = rtThreadGetState(pCur); 359 switch (enmCurState) 360 { 361 case RTTHREADSTATE_CRITSECT: 362 case RTTHREADSTATE_EVENT: 363 case RTTHREADSTATE_EVENT_MULTI: 364 case RTTHREADSTATE_FAST_MUTEX: 365 case RTTHREADSTATE_MUTEX: 366 case RTTHREADSTATE_RW_READ: 367 case RTTHREADSTATE_RW_WRITE: 368 case RTTHREADSTATE_SPIN_MUTEX: 369 { 370 PRTLOCKVALIDATORREC pCurRec = pCur->LockValidator.pRec; 371 if ( rtThreadGetState(pCur) != enmCurState 372 || !VALID_PTR(pCurRec) 373 || pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC) 374 continue; 375 pNext = pCurRec->hThread; 376 if ( rtThreadGetState(pCur) != enmCurState 377 || pCurRec->u32Magic != RTLOCKVALIDATORREC_MAGIC 378 || pCurRec->hThread != pNext) 379 continue; 380 break; 381 } 382 383 default: 384 pNext = NULL; 385 break; 386 } 387 break; 388 } 389 390 /* 391 * If we arrive at the end of the list we're good. 392 */ 393 pCur = pNext; 394 if (!pCur) 395 return; 396 397 /* 398 * If we've got back to the blocking thread id we've 399 * got a deadlock. 400 */ 401 if (pCur == pThread) 402 break; 403 404 /* 405 * If we've got a chain of more than 256 items, there is some 406 * kind of cycle in the list, which means that there is already 407 * a deadlock somewhere. 408 */ 409 if (cLength >= 256) 410 break; 411 412 cLength++; 413 } 414 415 /* compare with previous list run. */ 416 if (cLength != cPrevLength) 417 { 418 cPrevLength = cLength; 419 cEqualRuns = 0; 420 } 421 else 422 cEqualRuns++; 423 } while (cEqualRuns < 3 && --iParanoia > 0); 424 425 /* 426 * Ok, if we ever get here, it's most likely a genuine deadlock. 427 */ 428 rtLockValidatorComplainAboutDeadlock(pRec, pThread, enmState, pCur, uId, RT_SRC_POS_ARGS); 429 } 430 } 431 RT_EXPORT_SYMBOL(RTThreadBlocking); 432 -
trunk/src/VBox/Runtime/common/misc/thread.cpp
r25398 r25406 194 194 AssertMsg2("WARNING: g_ThreadTree=%p\n", g_ThreadTree); 195 195 #endif 196 }197 198 199 /**200 * Gets the thread state.201 *202 * @returns The thread state.203 * @param pThread The thread.204 */205 DECLINLINE(RTTHREADSTATE) rtThreadGetState(PRTTHREADINT pThread)206 {207 return pThread->enmState;208 196 } 209 197 … … 1229 1217 * @returns Number of locks on success (0+) and VERR_INVALID_HANDLER on failure 1230 1218 * @param Thread The thread we're inquiring about. 1219 * 1220 * @todo Move this. 1231 1221 */ 1232 1222 RTDECL(int32_t) RTThreadGetWriteLockCount(RTTHREAD Thread) … … 1238 1228 if (!pThread) 1239 1229 return VERR_INVALID_HANDLE; 1240 int32_t cWriteLocks = ASMAtomicReadS32(&pThread-> cWriteLocks);1230 int32_t cWriteLocks = ASMAtomicReadS32(&pThread->LockValidator.cWriteLocks); 1241 1231 rtThreadRelease(pThread); 1242 1232 return cWriteLocks; … … 1249 1239 * 1250 1240 * @param Thread The current thread. 1241 * 1242 * @todo Move this. 1251 1243 */ 1252 1244 RTDECL(void) RTThreadWriteLockInc(RTTHREAD Thread) … … 1254 1246 PRTTHREADINT pThread = rtThreadGet(Thread); 1255 1247 AssertReturnVoid(pThread); 1256 ASMAtomicIncS32(&pThread-> cWriteLocks);1248 ASMAtomicIncS32(&pThread->LockValidator.cWriteLocks); 1257 1249 rtThreadRelease(pThread); 1258 1250 } … … 1264 1256 * 1265 1257 * @param Thread The current thread. 1258 * 1259 * @todo Move this. 1266 1260 */ 1267 1261 RTDECL(void) RTThreadWriteLockDec(RTTHREAD Thread) … … 1269 1263 PRTTHREADINT pThread = rtThreadGet(Thread); 1270 1264 AssertReturnVoid(pThread); 1271 ASMAtomicDecS32(&pThread-> cWriteLocks);1265 ASMAtomicDecS32(&pThread->LockValidator.cWriteLocks); 1272 1266 rtThreadRelease(pThread); 1273 1267 } … … 1285 1279 * @returns Number of read locks on success (0+) and VERR_INVALID_HANDLER on failure 1286 1280 * @param Thread The thread we're inquiring about. 1281 * 1282 * @todo Move this. 1287 1283 */ 1288 1284 RTDECL(int32_t) RTThreadGetReadLockCount(RTTHREAD Thread) … … 1294 1290 if (!pThread) 1295 1291 return VERR_INVALID_HANDLE; 1296 int32_t cReadLocks = ASMAtomicReadS32(&pThread-> cReadLocks);1292 int32_t cReadLocks = ASMAtomicReadS32(&pThread->LockValidator.cReadLocks); 1297 1293 rtThreadRelease(pThread); 1298 1294 return cReadLocks; … … 1305 1301 * 1306 1302 * @param Thread The current thread. 1303 * 1304 * @todo Move this. 1307 1305 */ 1308 1306 RTDECL(void) RTThreadReadLockInc(RTTHREAD Thread) … … 1310 1308 PRTTHREADINT pThread = rtThreadGet(Thread); 1311 1309 Assert(pThread); 1312 ASMAtomicIncS32(&pThread-> cReadLocks);1310 ASMAtomicIncS32(&pThread->LockValidator.cReadLocks); 1313 1311 rtThreadRelease(pThread); 1314 1312 } … … 1320 1318 * 1321 1319 * @param Thread The current thread. 1320 * 1321 * @todo Move this. 1322 1322 */ 1323 1323 RTDECL(void) RTThreadReadLockDec(RTTHREAD Thread) … … 1325 1325 PRTTHREADINT pThread = rtThreadGet(Thread); 1326 1326 Assert(pThread); 1327 ASMAtomicDecS32(&pThread-> cReadLocks);1327 ASMAtomicDecS32(&pThread->LockValidator.cReadLocks); 1328 1328 rtThreadRelease(pThread); 1329 1329 } … … 1421 1421 1422 1422 /** 1423 * Change the thread state to blocking. 1424 * 1425 * @param hThread The current thread. 1426 * @param enmState The sleep state. 1427 */ 1428 RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState) 1429 { 1430 Assert(RTTHREAD_IS_SLEEPING(enmState)); 1431 PRTTHREADINT pThread = hThread; 1432 if (hThread && rtThreadGetState(pThread) != RTTHREADSTATE_RUNNING) 1433 rtThreadSetState(pThread, enmState); 1434 } 1435 RT_EXPORT_SYMBOL(RTThreadBlocking); 1436 1437 1438 /** 1439 * Unblocks a thread. 1440 * 1441 * This function is paired with rtThreadBlocking. 1442 * 1443 * @param hThread The current thread. 1444 * @param enmCurState The current state, used to check for nested blocking. 1445 * The new state will be running. 1446 */ 1447 RTDECL(void) RTThreadUnblocked(RTTHREAD hThread, RTTHREADSTATE enmCurState) 1448 { 1449 if (hThread && rtThreadGetState(hThread) == enmCurState) 1450 rtThreadSetState(hThread, RTTHREADSTATE_RUNNING); 1451 } 1452 RT_EXPORT_SYMBOL(RTThreadUnblocked); 1453 1454 1455 /** 1423 1456 * Translate a thread state into a string. 1424 1457 * … … 1426 1459 * @param enmState The state. 1427 1460 */ 1428 static const char *rtThreadStateName(RTTHREADSTATE enmState)1461 RTDECL(const char *) RTThreadStateName(RTTHREADSTATE enmState) 1429 1462 { 1430 1463 switch (enmState) … … 1446 1479 } 1447 1480 } 1448 1449 1450 /** 1451 * Bitch about a deadlock. 1452 * 1453 * @param pThread This thread. 1454 * @param pCur The thread we're deadlocking with. 1455 * @param enmState The sleep state. 1456 * @param pRec The lock validator record we're going to block on. 1457 * @param RT_SRC_POS_DECL Where we are going to deadlock. 1458 * @param uId Where we are going to deadlock. 1459 */ 1460 static void rtThreadDeadlock(PRTTHREADINT pThread, PRTTHREADINT pCur, RTTHREADSTATE enmState, 1461 PRTLOCKVALIDATORREC pRec, RTHCUINTPTR uId, RT_SRC_POS_DECL) 1462 { 1463 AssertMsg1(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", iLine, pszFile, pszFunction); 1464 1465 /* 1466 * Print the threads and locks involved. 1467 */ 1468 PRTTHREADINT apSeenThreads[8] = {0,0,0,0,0,0,0,0}; 1469 unsigned iSeenThread = 0; 1470 pCur = pThread; 1471 for (unsigned iEntry = 0; pCur && iEntry < 256; iEntry++) 1472 { 1473 /* 1474 * Print info on pCur. Determin next while doing so. 1475 */ 1476 AssertMsg2(" #%u: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n", 1477 iEntry, pCur, pCur->Core.Key, pCur->szName, 1478 pCur->pszBlockFile, pCur->uBlockLine, pCur->pszBlockFunction, pCur->uBlockId); 1479 PRTTHREADINT pNext = NULL; 1480 RTTHREADSTATE enmCurState = rtThreadGetState(pCur); 1481 switch (enmCurState) 1482 { 1483 case RTTHREADSTATE_CRITSECT: 1484 case RTTHREADSTATE_EVENT: 1485 case RTTHREADSTATE_EVENT_MULTI: 1486 case RTTHREADSTATE_FAST_MUTEX: 1487 case RTTHREADSTATE_MUTEX: 1488 case RTTHREADSTATE_RW_READ: 1489 case RTTHREADSTATE_RW_WRITE: 1490 case RTTHREADSTATE_SPIN_MUTEX: 1491 { 1492 PRTLOCKVALIDATORREC pCurRec = pCur->Block.pRec; 1493 RTTHREADSTATE enmCurState2 = rtThreadGetState(pCur); 1494 if (enmCurState2 != enmCurState) 1495 { 1496 AssertMsg2(" Impossible!!! enmState=%s -> %s (%d)\n", 1497 rtThreadStateName(enmCurState), rtThreadStateName(enmCurState2), enmCurState2); 1498 break; 1499 } 1500 if ( VALID_PTR(pCurRec) 1501 && pCurRec->u32Magic == RTLOCKVALIDATORREC_MAGIC) 1502 { 1503 AssertMsg2(" Waiting on %s %p [%s]: Entered %s(%u) %s %p\n", 1504 rtThreadStateName(enmCurState), pCurRec->hLock, pCurRec->pszName, 1505 pCurRec->pszFile, pCurRec->uLine, pCurRec->pszFunction, pCurRec->uId); 1506 pNext = pCurRec->hThread; 1507 } 1508 else if (VALID_PTR(pCurRec)) 1509 AssertMsg2(" Waiting on %s pCurRec=%p: invalid magic number: %#x\n", 1510 rtThreadStateName(enmCurState), pCurRec, pCurRec->u32Magic); 1511 else 1512 AssertMsg2(" Waiting on %s pCurRec=%p: invalid pointer\n", 1513 rtThreadStateName(enmCurState), pCurRec); 1514 break; 1515 } 1516 1517 default: 1518 AssertMsg2(" Impossible!!! enmState=%s (%d)\n", rtThreadStateName(enmCurState), enmCurState); 1519 break; 1520 } 1521 1522 /* 1523 * Check for cycle. 1524 */ 1525 if (iEntry && pCur == pThread) 1526 break; 1527 for (unsigned i = 0; i < RT_ELEMENTS(apSeenThreads); i++) 1528 if (apSeenThreads[i] == pCur) 1529 { 1530 AssertMsg2(" Cycle!\n"); 1531 pNext = NULL; 1532 break; 1533 } 1534 1535 /* 1536 * Advance to the next thread. 1537 */ 1538 iSeenThread = (iSeenThread + 1) % RT_ELEMENTS(apSeenThreads); 1539 apSeenThreads[iSeenThread] = pCur; 1540 pCur = pNext; 1541 } 1542 AssertBreakpoint(); 1543 } 1544 1545 1546 /** 1547 * Change the thread state to blocking. 1548 * 1549 * @param hThread The current thread. 1550 * @param enmState The sleep state. 1551 */ 1552 RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState) 1553 1554 { 1555 Assert(RTTHREAD_IS_SLEEPING(enmState)); 1556 1557 /* 1558 * Fend off wild life. 1559 */ 1560 PRTTHREADINT pThread = hThread; 1561 if (!pThread) 1562 return; 1563 if (rtThreadGetState(pThread) != RTTHREADSTATE_RUNNING) 1564 return; 1565 1566 /* 1567 * Do the job. 1568 */ 1569 rtThreadSetState(pThread, enmState); 1570 } 1571 1572 1573 /** 1574 * Change the thread state to blocking and do deadlock detection. 1575 * 1576 * This is a RT_STRICT method for debugging locks and detecting deadlocks. 1577 * 1578 * @param hThread The current thread. 1579 * @param enmState The sleep state. 1580 * @param pvBlock Pointer to a RTLOCKVALIDATORREC structure. 1581 * @param fRecursiveOk Whether it's ok to recurse. 1582 * @param uId Where we are blocking. 1583 * @param RT_SRC_POS_DECL Where we are blocking. 1584 * 1585 * @todo Move this to RTLockValidator. 1586 */ 1587 RTDECL(void) RTThreadBlockingDebug(RTTHREAD hThread, RTTHREADSTATE enmState, bool fRecursiveOk, 1588 PRTLOCKVALIDATORREC pValidatorRec, RTHCUINTPTR uId, RT_SRC_POS_DECL) 1589 1590 { 1591 /* 1592 * Fend off wild life. 1593 */ 1594 AssertReturnVoid(RTTHREAD_IS_SLEEPING(enmState)); 1595 AssertPtrReturnVoid(pValidatorRec); 1596 AssertReturnVoid(pValidatorRec->u32Magic == RTLOCKVALIDATORREC_MAGIC); 1597 PRTTHREADINT pThread = hThread; 1598 AssertPtrReturnVoid(pThread); 1599 AssertReturnVoid(pThread->u32Magic == RTTHREADINT_MAGIC); 1600 AssertReturnVoid(rtThreadGetState(pThread) == RTTHREADSTATE_RUNNING); 1601 1602 /* 1603 * Record the location and everything before changing the state and 1604 * performing deadlock detection. 1605 */ 1606 /** @todo This has to be serialized! The deadlock detection isn't 100% safe!!! */ 1607 pThread->Block.pRec = pValidatorRec; 1608 pThread->pszBlockFunction = pszFunction; 1609 pThread->pszBlockFile = pszFile; 1610 pThread->uBlockLine = iLine; 1611 pThread->uBlockId = uId; 1612 rtThreadSetState(pThread, enmState); 1613 1614 /* 1615 * Don't do deadlock detection if we're recursing and that's OK. 1616 * 1617 * On some hosts we don't do recursion accounting our selves and there 1618 * isn't any other place to check for this. semmutex-win.cpp for instance. 1619 */ 1620 if ( !fRecursiveOk 1621 || pValidatorRec->hThread != pThread) 1622 { 1623 /* 1624 * Do deadlock detection. 1625 * 1626 * Since we're missing proper serialization, we don't declare it a 1627 * deadlock until we've got three runs with the same list length. 1628 * While this isn't perfect, it should avoid out the most obvious 1629 * races on SMP boxes. 1630 */ 1631 PRTTHREADINT pCur; 1632 unsigned cPrevLength = ~0U; 1633 unsigned cEqualRuns = 0; 1634 unsigned iParanoia = 256; 1635 do 1636 { 1637 unsigned cLength = 0; 1638 pCur = pThread; 1639 for (;;) 1640 { 1641 /* 1642 * Get the next thread. 1643 */ 1644 PRTTHREADINT pNext = NULL; 1645 for (;;) 1646 { 1647 RTTHREADSTATE enmCurState = rtThreadGetState(pCur); 1648 switch (enmCurState) 1649 { 1650 case RTTHREADSTATE_CRITSECT: 1651 case RTTHREADSTATE_EVENT: 1652 case RTTHREADSTATE_EVENT_MULTI: 1653 case RTTHREADSTATE_FAST_MUTEX: 1654 case RTTHREADSTATE_MUTEX: 1655 case RTTHREADSTATE_RW_READ: 1656 case RTTHREADSTATE_RW_WRITE: 1657 case RTTHREADSTATE_SPIN_MUTEX: 1658 { 1659 PRTLOCKVALIDATORREC pRec = pCur->Block.pRec; 1660 if ( rtThreadGetState(pCur) != enmCurState 1661 || !VALID_PTR(pRec) 1662 || pRec->u32Magic != RTLOCKVALIDATORREC_MAGIC) 1663 continue; 1664 pNext = pRec->hThread; 1665 if ( rtThreadGetState(pCur) != enmCurState 1666 || pRec->u32Magic != RTLOCKVALIDATORREC_MAGIC 1667 || pRec->hThread != pNext) 1668 continue; 1669 break; 1670 } 1671 1672 default: 1673 pNext = NULL; 1674 break; 1675 } 1676 break; 1677 } 1678 1679 /* 1680 * If we arrive at the end of the list we're good. 1681 */ 1682 pCur = pNext; 1683 if (!pCur) 1684 return; 1685 1686 /* 1687 * If we've got back to the blocking thread id we've 1688 * got a deadlock. 1689 */ 1690 if (pCur == pThread) 1691 break; 1692 1693 /* 1694 * If we've got a chain of more than 256 items, there is some 1695 * kind of cycle in the list, which means that there is already 1696 * a deadlock somewhere. 1697 */ 1698 if (cLength >= 256) 1699 break; 1700 1701 cLength++; 1702 } 1703 1704 /* compare with previous list run. */ 1705 if (cLength != cPrevLength) 1706 { 1707 cPrevLength = cLength; 1708 cEqualRuns = 0; 1709 } 1710 else 1711 cEqualRuns++; 1712 } while (cEqualRuns < 3 && --iParanoia > 0); 1713 1714 /* 1715 * Ok, if we ever get here, it's most likely a genuine deadlock. 1716 */ 1717 rtThreadDeadlock(pThread, pCur, enmState, pValidatorRec, uId, RT_SRC_POS_ARGS); 1718 } 1719 } 1720 RT_EXPORT_SYMBOL(RTThreadBlocking); 1721 1722 1723 /** 1724 * Unblocks a thread. 1725 * 1726 * This function is paired with rtThreadBlocking. 1727 * 1728 * @param hThread The current thread. 1729 * @param enmCurState The current state, used to check for nested blocking. 1730 * The new state will be running. 1731 */ 1732 RTDECL(void) RTThreadUnblocked(RTTHREAD hThread, RTTHREADSTATE enmCurState) 1733 { 1734 if (hThread && rtThreadGetState(hThread) == enmCurState) 1735 rtThreadSetState(hThread, RTTHREADSTATE_RUNNING); 1736 } 1737 RT_EXPORT_SYMBOL(RTThreadUnblocked); 1481 RT_EXPORT_SYMBOL(RTThreadStateName); 1738 1482 1739 1483 #endif /* IN_RING3 */ 1740 1741 1742 1484 #ifdef IPRT_WITH_GENERIC_TLS 1743 1485
Note:
See TracChangeset
for help on using the changeset viewer.