- Timestamp:
- Jun 15, 2009 7:08:29 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 48648
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified trunk/src/VBox/Runtime/generic/semsrw-generic.cpp ¶
r13836 r20601 8 8 9 9 /* 10 * Copyright (C) 2006-200 7Sun Microsystems, Inc.10 * Copyright (C) 2006-2009 Sun Microsystems, Inc. 11 11 * 12 12 * This file is part of VirtualBox Open Source Edition (OSE), as … … 32 32 */ 33 33 34 /** @todo fix generic RW sems. (reimplement) */35 #define USE_CRIT_SECT36 34 37 35 … … 40 38 *******************************************************************************/ 41 39 #include <iprt/semaphore.h> 40 #include <iprt/critsect.h> 42 41 #include <iprt/alloc.h> 43 42 #include <iprt/time.h> … … 46 45 #include <iprt/thread.h> 47 46 #include <iprt/err.h> 48 #ifdef USE_CRIT_SECT 49 #include <iprt/critsect.h> 50 #endif 51 47 #include <iprt/stream.h> 48 49 #include "internal/magics.h" 52 50 53 51 … … 55 53 * Structures and Typedefs * 56 54 *******************************************************************************/ 55 57 56 /** Internal representation of a Read-Write semaphore for the 58 57 * Generic implementation. */ 59 58 struct RTSEMRWINTERNAL 60 59 { 61 #ifdef USE_CRIT_SECT 62 /** Critical section. */ 63 RTCRITSECT CritSect; 64 #else 65 /** Magic (RTSEMRW_MAGIC). */ 66 uint32_t u32Magic; 60 /** The usual magic. (RTSEMRW_MAGIC) */ 61 uint32_t u32Magic; 62 /* Alignment padding. */ 63 uint32_t u32Padding; 67 64 /** This critical section serializes the access to and updating of the structure members. */ 68 RTCRITSECT CritSect; 69 /** The current number of readers. */ 70 uint32_t cReaders; 71 /** The number of readers waiting. */ 72 uint32_t cReadersWaiting; 73 /** The current number of waiting writers. */ 74 uint32_t cWritersWaiting; 65 RTCRITSECT CritSect; 66 /** The current number of reads. (pure read recursion counts too) */ 67 uint32_t cReads; 68 /** The current number of writes. (recursion counts too) */ 69 uint32_t cWrites; 70 /** Number of read recursions by the writer. */ 71 uint32_t cWriterReads; 72 /** Number of writers waiting. */ 73 uint32_t cWritesWaiting; 74 /** The write owner of the lock. */ 75 RTTHREAD Writer; 75 76 /** The handle of the event object on which the waiting readers block. (manual reset). */ 76 RTSEMEVENTMULTI EventReaders; 77 /** The handle of the event object on which the waiting writers block. (manual reset). */ 78 RTSEMEVENTMULTI EventWriters; 79 /** The current state of the read-write lock. */ 80 KPRF_TYPE(,RWLOCKSTATE) enmState; 81 82 #endif 77 RTSEMEVENTMULTI ReadEvent; 78 /** The handle of the event object on which the waiting writers block. (automatic reset). */ 79 RTSEMEVENT WriteEvent; 83 80 }; 84 81 … … 89 86 * @returns true if valid. 90 87 * @returns false if invalid. 91 * @param p IntRWSemPointer to the read-write semaphore to validate.88 * @param pThis Pointer to the read-write semaphore to validate. 92 89 */ 93 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *p IntRWSem)94 { 95 if (!VALID_PTR(p IntRWSem))90 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pThis) 91 { 92 if (!VALID_PTR(pThis)) 96 93 return false; 97 94 98 #ifdef USE_CRIT_SECT 99 if (pIntRWSem->CritSect.u32Magic != RTCRITSECT_MAGIC) 95 if (pThis->u32Magic != RTSEMRW_MAGIC) 100 96 return false; 101 #else102 if (pIntRWSem->u32Check != (uint32_t)~0)103 return false;104 #endif105 97 return true; 106 98 } 107 99 108 100 109 RTDECL(int) 101 RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem) 110 102 { 111 103 int rc; … … 114 106 * Allocate memory. 115 107 */ 116 struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL)); 117 if (pIntRWSem) 118 { 119 #ifdef USE_CRIT_SECT 120 rc = RTCritSectInit(&pIntRWSem->CritSect); 108 struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL)); 109 if (pThis) 110 { 111 /* 112 * Create the semaphores. 113 */ 114 rc = RTSemEventCreate(&pThis->WriteEvent); 121 115 if (RT_SUCCESS(rc)) 122 116 { 123 *pRWSem = pIntRWSem; 124 return VINF_SUCCESS; 125 } 126 #else 127 /* 128 * Create the semaphores. 129 */ 130 rc = RTSemEventCreate(&pIntRWSem->WriteEvent); 131 if (RT_SUCCESS(rc)) 132 { 133 rc = RTSemEventMultiCreate(&pIntRWSem->ReadEvent); 117 rc = RTSemEventMultiCreate(&pThis->ReadEvent); 134 118 if (RT_SUCCESS(rc)) 135 119 { 136 rc = RT SemMutexCreate(&pIntRWSem->Mutex);120 rc = RTCritSectInit(&pThis->CritSect); 137 121 if (RT_SUCCESS(rc)) 138 122 { … … 140 124 * Signal the read semaphore and initialize other variables. 141 125 */ 142 rc = RTSemEventMultiSignal(p IntRWSem->ReadEvent);126 rc = RTSemEventMultiSignal(pThis->ReadEvent); 143 127 if (RT_SUCCESS(rc)) 144 128 { 145 pIntRWSem->cReaders = 0; 146 pIntRWSem->cWriters = 0; 147 pIntRWSem->WROwner = NIL_RTTHREAD; 148 pIntRWSem->u32Check = ~0; 149 *pRWSem = pIntRWSem; 129 pThis->u32Padding = 0xa5a55a5a; 130 pThis->cReads = 0; 131 pThis->cWrites = 0; 132 pThis->cWriterReads = 0; 133 pThis->cWritesWaiting = 0; 134 pThis->Writer = NIL_RTTHREAD; 135 pThis->u32Magic = RTSEMRW_MAGIC; 136 *pRWSem = pThis; 150 137 return VINF_SUCCESS; 151 138 } 152 RT SemMutexDestroy(pIntRWSem->Mutex);139 RTCritSectDelete(&pThis->CritSect); 153 140 } 154 RTSemEventMultiDestroy(p IntRWSem->ReadEvent);141 RTSemEventMultiDestroy(pThis->ReadEvent); 155 142 } 156 RTSemEventDestroy(pIntRWSem->WriteEvent); 157 } 158 #endif 159 RTMemFree(pIntRWSem); 143 RTSemEventDestroy(pThis->WriteEvent); 144 } 145 RTMemFree(pThis); 160 146 } 161 147 else … … 166 152 167 153 168 RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem) 169 { 170 /* 171 * Validate handle. 172 */ 173 if (!rtsemRWValid(RWSem)) 174 { 175 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 176 return VERR_INVALID_HANDLE; 177 } 178 179 #ifdef USE_CRIT_SECT 180 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 181 int rc = RTCritSectDelete(&pIntRWSem->CritSect); 154 RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem) 155 { 156 struct RTSEMRWINTERNAL *pThis = RWSem; 157 /* 158 * Validate handle. 159 */ 160 if (!rtsemRWValid(pThis)) 161 { 162 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 163 return VERR_INVALID_HANDLE; 164 } 165 166 /* 167 * Check if busy. 168 */ 169 int rc = RTCritSectTryEnter(&pThis->CritSect); 182 170 if (RT_SUCCESS(rc)) 183 RTMemFree(pIntRWSem); 184 return rc; 185 #else 186 187 /* 188 * Check if busy. 189 */ 190 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 191 int rc = RTSemMutexRequest(pIntRWSem->Mutex, 32); 192 if (RT_SUCCESS(rc)) 193 { 194 if (!pIntRWSem->cReaders && !pIntRWSem->cWriters) 171 { 172 if (!pThis->cReads && !pThis->cWrites) 195 173 { 196 174 /* 197 175 * Make it invalid and unusable. 198 176 */ 199 ASMAtomicXchgU32(&pIntRWSem->u32Check, 0);200 ASMAtomicXchgU32(&pIntRWSem->cReaders, ~0);177 pThis->u32Magic = ~RTSEMRW_MAGIC; 178 pThis->cReads = ~0; 201 179 202 180 /* 203 * Do actual cleanup. 204 * None of these can now fail excep for the mutex which 205 * can be a little bit busy. 181 * Do actual cleanup. None of these can now fail. 206 182 */ 207 rc = RTSemEventMultiDestroy(p IntRWSem->ReadEvent);183 rc = RTSemEventMultiDestroy(pThis->ReadEvent); 208 184 AssertMsgRC(rc, ("RTSemEventMultiDestroy failed! rc=%d\n", rc)); 209 p IntRWSem->ReadEvent = NIL_RTSEMEVENTMULTI;210 211 rc = RTSemEventDestroy(p IntRWSem->WriteEvent);185 pThis->ReadEvent = NIL_RTSEMEVENTMULTI; 186 187 rc = RTSemEventDestroy(pThis->WriteEvent); 212 188 AssertMsgRC(rc, ("RTSemEventDestroy failed! rc=%d\n", rc)); 213 pIntRWSem->WriteEvent = NIL_RTSEMEVENT; 214 215 RTSemMutexRelease(pIntRWSem->Mutex); 216 for (unsigned i = 32; i > 0; i--) 217 { 218 rc = RTSemMutexDestroy(pIntRWSem->Mutex); 219 if (RT_SUCCESS(rc)) 220 break; 221 RTThreadSleep(1); 222 } 223 AssertMsgRC(rc, ("RTSemMutexDestroy failed! rc=%d\n", rc)); 224 pIntRWSem->Mutex = (RTSEMMUTEX)0; 225 226 RTMemFree(pIntRWSem); 189 pThis->WriteEvent = NIL_RTSEMEVENT; 190 191 RTCritSectLeave(&pThis->CritSect); 192 rc = RTCritSectDelete(&pThis->CritSect); 193 AssertMsgRC(rc, ("RTCritSectDelete failed! rc=%d\n", rc)); 194 195 RTMemFree(pThis); 227 196 rc = VINF_SUCCESS; 228 197 } … … 230 199 { 231 200 rc = VERR_SEM_BUSY; 232 RT SemMutexRelease(pIntRWSem->Mutex);201 RTCritSectLeave(&pThis->CritSect); 233 202 } 234 203 } 235 204 else 236 rc = rc == VERR_TIMEOUT ? VERR_SEM_BUSY : rc; 237 238 return VINF_SUCCESS; 239 #endif 240 } 241 242 243 RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies) 244 { 245 /* 246 * Validate handle. 247 */ 248 if (!rtsemRWValid(RWSem)) 249 { 250 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 251 return VERR_INVALID_HANDLE; 252 } 253 254 #ifdef USE_CRIT_SECT 255 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 256 return RTCritSectEnter(&pIntRWSem->CritSect); 257 #else 258 259 /* 260 * Take mutex and check if already reader. 261 */ 262 //RTTHREAD Self = RTThreadSelf(); 205 { 206 AssertMsgRC(rc, ("RTCritSectTryEnter failed! rc=%d\n", rc)); 207 rc = VERR_SEM_BUSY; 208 } 209 210 return rc; 211 } 212 213 214 RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies) 215 { 216 struct RTSEMRWINTERNAL *pThis = RWSem; 217 /* 218 * Validate handle. 219 */ 220 if (!rtsemRWValid(pThis)) 221 { 222 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 223 return VERR_INVALID_HANDLE; 224 } 225 263 226 RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf(); 264 227 unsigned cMilliesInitial = cMillies; 265 228 uint64_t tsStart = 0; 266 if (cMillies != RT SEM_INDEFINITE_WAIT)229 if (cMillies != RT_INDEFINITE_WAIT) 267 230 tsStart = RTTimeNanoTS(); 268 231 269 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 270 int rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT); 232 /* 233 * Take critsect. 234 */ 235 int rc = RTCritSectEnter(&pThis->CritSect); 271 236 if (RT_FAILURE(rc)) 272 237 { 273 AssertMsgFailed(("RT SemMutexRequestfailed on rwsem %p, rc=%d\n", RWSem, rc));238 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%d\n", RWSem, rc)); 274 239 return rc; 275 240 } 276 241 277 unsigned i = pIntRWSem->cReaders;278 while (i-- > 0)279 {280 if (pIntRWSem->aReaders[i].Thread == Self)281 {282 if (pIntRWSem->aReaders[i].cNesting + 1 < (unsigned)~0)283 pIntRWSem->aReaders[i].cNesting++;284 else285 {286 AssertMsgFailed(("Too many requests for one thread!\n"));287 rc = RTSemMutexRelease(pIntRWSem->Mutex);288 AssertMsgRC(rc, ("RTSemMutexRelease failed rc=%d\n", rc));289 return VERR_TOO_MANY_SEM_REQUESTS;290 }291 }292 }293 294 295 242 for (;;) 296 243 { 297 244 /* 298 * Check if the stat of the affairs allow read access. 299 */ 300 if (pIntRWSem->u32Check == (uint32_t)~0) 301 { 302 if (pIntRWSem->cWriters == 0) 303 { 304 if (pIntRWSem->cReaders < RT_ELEMENTS(pIntRWSem->aReaders)) 305 { 306 /* 307 * Add ourselves to the list of readers and return. 308 */ 309 i = pIntRWSem->cReaders; 310 pIntRWSem->aReaders[i].Thread = Self; 311 pIntRWSem->aReaders[i].cNesting = 1; 312 ASMAtomicXchgU32(&pIntRWSem->cReaders, i + 1); 313 314 RTSemMutexRelease(pIntRWSem->Mutex); 315 return VINF_SUCCESS; 316 } 317 else 318 { 319 AssertMsgFailed(("Too many readers! How come we have so many threads!?!\n")); 320 rc = VERR_TOO_MANY_SEM_REQUESTS; 321 } 322 } 323 #if 0 /* any action here shouldn't be necessary */ 324 else 325 { 326 rc = RTSemEventMultiReset(pIntRWSem->ReadEvent); 327 AssertMsgRC(rc, ("RTSemEventMultiReset failed on RWSem %p, rc=%d\n", RWSem, rc)); 328 } 329 #endif 330 } 331 else 332 rc = VERR_SEM_DESTROYED; 333 RTSemMutexRelease(pIntRWSem->Mutex); 334 if (RT_FAILURE(rc)) 335 break; 336 245 * Check if the state of affairs allows read access. 246 * Do not block further readers if there is a writer waiting, as 247 * that will break/deadlock reader recursion. 248 */ 249 if (!pThis->cWrites) 250 { 251 pThis->cReads++; 252 253 RTCritSectLeave(&pThis->CritSect); 254 return VINF_SUCCESS; 255 } 256 else if (pThis->Writer == Self) 257 { 258 pThis->cWriterReads++; 259 260 RTCritSectLeave(&pThis->CritSect); 261 return VINF_SUCCESS; 262 } 263 264 RTCritSectLeave(&pThis->CritSect); 337 265 338 266 /* 339 267 * Wait till it's ready for reading. 340 268 */ 341 if (cMillies != RT SEM_INDEFINITE_WAIT)342 { 343 int64_t 269 if (cMillies != RT_INDEFINITE_WAIT) 270 { 271 int64_t tsDelta = RTTimeNanoTS() - tsStart; 344 272 if (tsDelta >= 1000000) 345 273 { … … 349 277 } 350 278 } 351 rc = RTSemEventMultiWait(pIntRWSem->ReadEvent, cMillies); 279 rc = RTSemEventMultiWait(pThis->ReadEvent, cMillies); 280 if (RT_FAILURE(rc) && rc != VERR_TIMEOUT) 281 { 282 AssertMsgRC(rc, ("RTSemEventMultiWait failed on rwsem %p, rc=%d\n", RWSem, rc)); 283 break; 284 } 285 286 if (pThis->u32Magic != RTSEMRW_MAGIC) 287 { 288 rc = VERR_SEM_DESTROYED; 289 break; 290 } 291 292 /* 293 * Re-take critsect. 294 */ 295 rc = RTCritSectEnter(&pThis->CritSect); 352 296 if (RT_FAILURE(rc)) 353 297 { 354 AssertMsg (rc == VERR_TIMEOUT, ("RTSemEventMultiWaitfailed on rwsem %p, rc=%d\n", RWSem, rc));298 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%d\n", RWSem, rc)); 355 299 break; 356 300 } 357 358 /*359 * Get Mutex.360 */361 rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);362 if (RT_FAILURE(rc))363 {364 AssertMsgFailed(("RTSemMutexRequest failed on rwsem %p, rc=%d\n", RWSem, rc));365 break;366 }367 301 } 368 302 369 303 return rc; 370 #endif 371 } 372 373 374 RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies) 304 } 305 306 307 RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies) 375 308 { 376 309 return RTSemRWRequestRead(RWSem, cMillies); … … 378 311 379 312 380 RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem) 381 { 382 /* 383 * Validate handle. 384 */ 385 if (!rtsemRWValid(RWSem)) 386 { 387 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 388 return VERR_INVALID_HANDLE; 389 } 390 391 #ifdef USE_CRIT_SECT 392 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 393 return RTCritSectLeave(&pIntRWSem->CritSect); 394 #else 395 396 /* 397 * Take Mutex. 398 */ 399 //RTTHREAD Self = RTThreadSelf(); 313 RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem) 314 { 315 struct RTSEMRWINTERNAL *pThis = RWSem; 316 /* 317 * Validate handle. 318 */ 319 if (!rtsemRWValid(pThis)) 320 { 321 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 322 return VERR_INVALID_HANDLE; 323 } 324 400 325 RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf(); 401 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 402 int rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT); 326 327 /* 328 * Take critsect. 329 */ 330 int rc = RTCritSectEnter(&pThis->CritSect); 403 331 if (RT_SUCCESS(rc)) 404 332 { 405 unsigned i = pIntRWSem->cReaders; 406 while (i-- > 0) 407 { 408 if (pIntRWSem->aReaders[i].Thread == Self) 333 if (pThis->Writer == Self) 334 { 335 pThis->cWriterReads--; 336 } 337 else 338 { 339 AssertMsg(pThis->Writer == NIL_RTTHREAD, ("Impossible! Writers and Readers are exclusive!\n")); 340 pThis->cReads--; 341 342 /* Kick off a writer if appropriate. */ 343 if ( pThis->cWritesWaiting > 0 344 && !pThis->cReads) 409 345 { 410 AssertMsg(pIntRWSem->WROwner == NIL_RTTHREAD, ("Impossible! Writers and Readers are exclusive!\n")); 411 412 if (pIntRWSem->aReaders[i].cNesting <= 1) 413 { 414 pIntRWSem->aReaders[i] = pIntRWSem->aReaders[pIntRWSem->cReaders - 1]; 415 ASMAtomicXchgU32(&pIntRWSem->cReaders, pIntRWSem->cReaders - 1); 416 417 /* Kick off writers? */ 418 if ( pIntRWSem->cWriters > 0 419 && pIntRWSem->cReaders == 0) 420 { 421 rc = RTSemEventSignal(pIntRWSem->WriteEvent); 422 AssertMsgRC(rc, ("Failed to signal writers on rwsem %p, rc=%d\n", RWSem, rc)); 423 } 424 } 425 else 426 pIntRWSem->aReaders[i].cNesting--; 427 428 RTSemMutexRelease(pIntRWSem->Mutex); 429 return VINF_SUCCESS; 346 rc = RTSemEventSignal(pThis->WriteEvent); 347 AssertMsgRC(rc, ("Failed to signal writers on rwsem %p, rc=%d\n", RWSem, rc)); 430 348 } 431 349 } 432 350 433 RTSemMutexRelease(pIntRWSem->Mutex); 434 rc = VERR_NOT_OWNER; 435 AssertMsgFailed(("Not reader of rwsem %p\n", RWSem)); 351 RTCritSectLeave(&pThis->CritSect); 352 return VINF_SUCCESS; 436 353 } 437 354 else 438 AssertMsgFailed(("RT SemMutexRequestfailed on rwsem %p, rc=%d\n", RWSem, rc));355 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%d\n", RWSem, rc)); 439 356 440 357 return rc; 441 #endif 442 } 443 358 } 444 359 445 360 446 361 RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies) 447 362 { 448 /* 449 * Validate handle. 450 */ 451 if (!rtsemRWValid(RWSem)) 452 { 453 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 454 return VERR_INVALID_HANDLE; 455 } 456 457 #ifdef USE_CRIT_SECT 458 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 459 return RTCritSectEnter(&pIntRWSem->CritSect); 460 #else 461 462 /* 463 * Get Mutex. 464 */ 465 //RTTHREAD Self = RTThreadSelf(); 363 struct RTSEMRWINTERNAL *pThis = RWSem; 364 /* 365 * Validate handle. 366 */ 367 if (!rtsemRWValid(pThis)) 368 { 369 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 370 return VERR_INVALID_HANDLE; 371 } 372 466 373 RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf(); 467 374 unsigned cMilliesInitial = cMillies; 468 375 uint64_t tsStart = 0; 469 if (cMillies != RT SEM_INDEFINITE_WAIT)376 if (cMillies != RT_INDEFINITE_WAIT) 470 377 tsStart = RTTimeNanoTS(); 471 378 472 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 473 int rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT); 379 /* 380 * Take critsect. 381 */ 382 int rc = RTCritSectEnter(&pThis->CritSect); 474 383 if (RT_FAILURE(rc)) 475 384 { 476 AssertMsgFailed(("RT SemMutexWaitfailed on rwsem %p, rc=%d\n", RWSem, rc));385 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%d\n", RWSem, rc)); 477 386 return rc; 478 387 } 479 388 480 389 /* 481 * Check that we're not a reader. 482 */ 483 unsigned i = pIntRWSem->cReaders; 484 while (i-- > 0) 485 { 486 if (pIntRWSem->aReaders[i].Thread == Self) 487 { 488 AssertMsgFailed(("Deadlock - requested write access while being a reader! rwsem %p.\n", RWSem)); 489 RTSemMutexRelease(pIntRWSem->Mutex); 490 return VERR_DEADLOCK; 491 } 492 } 493 494 495 /* 496 * Reset the reader event semaphore and increment number of readers. 497 */ 498 rc = RTSemEventMultiReset(pIntRWSem->ReadEvent); 499 if (RT_FAILURE(rc)) 500 { 501 AssertMsgFailed(("Failed to reset readers, rwsem %p, rc=%d.\n", RWSem, rc)); 502 RTSemMutexRelease(pIntRWSem->Mutex); 503 return rc; 504 } 505 ASMAtomicXchgU32(&pIntRWSem->cWriters, pIntRWSem->cWriters + 1); 506 507 /* 508 * Wait while there are other threads owning this sem. 509 */ 510 while ( pIntRWSem->WROwner != NIL_RTTHREAD 511 || pIntRWSem->cReaders > 0) 512 { 513 AssertMsg(pIntRWSem->WROwner == NIL_RTTHREAD || pIntRWSem->cWriters > 1, 514 ("The lock is write owned by there is only one waiter...\n")); 515 516 /* 517 * Release the mutex and wait on the writer semaphore. 518 */ 519 rc = RTSemMutexRelease(pIntRWSem->Mutex); 520 if (RT_FAILURE(rc)) 521 { 522 AssertMsgFailed(("RTSemMutexRelease failed on rwsem %p, rc=%d\n", RWSem, rc)); 523 return VERR_SEM_DESTROYED; 524 } 525 526 /* 527 * Wait. 528 */ 529 if (cMillies != RTSEM_INDEFINITE_WAIT) 530 { 531 int64_t tsDelta = RTTimeNanoTS() - tsStart; 390 * Signal writer presence. 391 */ 392 pThis->cWritesWaiting++; 393 394 for (;;) 395 { 396 /* 397 * Check if the state of affairs allows write access. 398 */ 399 if (!pThis->cReads && (!pThis->cWrites || pThis->Writer == Self)) 400 { 401 /* 402 * Reset the reader event semaphore. For write recursion this 403 * is redundant, but does not hurt. 404 */ 405 rc = RTSemEventMultiReset(pThis->ReadEvent); 406 AssertMsgRC(rc, ("Failed to reset readers, rwsem %p, rc=%d.\n", RWSem, rc)); 407 408 pThis->cWrites++; 409 pThis->Writer = Self; 410 /* We're not waiting, so decrease counter. */ 411 pThis->cWritesWaiting--; 412 RTCritSectLeave(&pThis->CritSect); 413 return VINF_SUCCESS; 414 } 415 416 RTCritSectLeave(&pThis->CritSect); 417 418 /* 419 * Wait till it's ready for writing. 420 */ 421 if (cMillies != RT_INDEFINITE_WAIT) 422 { 423 int64_t tsDelta = RTTimeNanoTS() - tsStart; 532 424 if (tsDelta >= 1000000) 533 425 { … … 537 429 } 538 430 } 539 rc = RTSemEventWait(pIntRWSem->WriteEvent, cMillies); 540 541 /* 542 * Check that the semaphore wasn't destroyed while we waited. 543 */ 544 if ( rc == VERR_SEM_DESTROYED 545 || pIntRWSem->u32Check != (uint32_t)~0) 546 return VERR_SEM_DESTROYED; 547 548 /* 549 * Attempt take the mutex. 550 */ 551 int rc2 = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT); 552 if (RT_FAILURE(rc) || RT_FAILURE(rc2)) 553 { 554 AssertMsgRC(rc2, ("RTSemMutexRequest failed on rwsem %p, rc=%d\n", RWSem, rc2)); 555 if (RT_SUCCESS(rc)) 556 rc = rc2; 557 else 558 AssertMsg(rc == VERR_TIMEOUT, ("RTSemEventWait failed on rwsem %p, rc=%d\n", RWSem, rc)); 559 560 /* 561 * Remove our selves from the writers queue. 562 */ 563 /** @todo write an atomic dec function! (it's too late for that kind of stuff tonight) */ 564 if (pIntRWSem->cWriters > 0) 565 ASMAtomicXchgU32(&pIntRWSem->cWriters, pIntRWSem->cWriters - 1); 566 if (!pIntRWSem->cWriters) 567 RTSemEventMultiSignal(pIntRWSem->ReadEvent); 568 if (RT_SUCCESS(rc2)) 569 RTSemMutexRelease(pIntRWSem->Mutex); 570 return rc; 571 } 572 573 AssertMsg(pIntRWSem->WROwner == NIL_RTTHREAD, ("We woke up an there is owner! %#x\n", pIntRWSem->WROwner)); 574 AssertMsg(!pIntRWSem->cReaders, ("We woke up an there are readers around!\n")); 575 } 576 577 /* 578 * If we get here we own the mutex and we are ready to take 579 * the read-write ownership. 580 */ 581 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)Self); 582 rc = RTSemMutexRelease(pIntRWSem->Mutex); 583 AssertMsgRC(rc, ("RTSemMutexRelease failed. rc=%d\n", rc)); 584 585 return VINF_SUCCESS; 586 #endif 431 rc = RTSemEventWait(pThis->WriteEvent, cMillies); 432 if (RT_FAILURE(rc) && rc != VERR_TIMEOUT) 433 { 434 AssertMsgRC(rc, ("RTSemEventWait failed on rwsem %p, rc=%d\n", RWSem, rc)); 435 break; 436 } 437 438 if (pThis->u32Magic != RTSEMRW_MAGIC) 439 { 440 rc = VERR_SEM_DESTROYED; 441 break; 442 } 443 444 /* 445 * Re-take critsect. 446 */ 447 rc = RTCritSectEnter(&pThis->CritSect); 448 if (RT_FAILURE(rc)) 449 { 450 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%d\n", RWSem, rc)); 451 break; 452 } 453 // AssertMsg(!pThis->cReads, ("We woke up and there are readers around!\n")); 454 } 455 456 /* 457 * Timeout/error case, clean up. 458 */ 459 if (pThis->u32Magic == RTSEMRW_MAGIC) 460 { 461 RTCritSectEnter(&pThis->CritSect); 462 /* Adjust this counter, whether we got the critsect or not. */ 463 pThis->cWritesWaiting--; 464 RTCritSectLeave(&pThis->CritSect); 465 } 466 return rc; 587 467 } 588 468 … … 594 474 595 475 596 597 RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem) 598 { 599 /* 600 * Validate handle. 601 */ 602 if (!rtsemRWValid(RWSem)) 603 { 604 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 605 return VERR_INVALID_HANDLE; 606 } 607 608 #ifdef USE_CRIT_SECT 609 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 610 return RTCritSectLeave(&pIntRWSem->CritSect); 611 #else 476 RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem) 477 { 478 struct RTSEMRWINTERNAL *pThis = RWSem; 479 /* 480 * Validate handle. 481 */ 482 if (!rtsemRWValid(pThis)) 483 { 484 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 485 return VERR_INVALID_HANDLE; 486 } 487 488 RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf(); 489 490 /* 491 * Take critsect. 492 */ 493 int rc = RTCritSectEnter(&pThis->CritSect); 494 if (RT_FAILURE(rc)) 495 { 496 AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%d\n", RWSem, rc)); 497 return rc; 498 } 612 499 613 500 /* 614 501 * Check if owner. 615 502 */ 616 //RTTHREAD Self = RTThreadSelf(); 617 RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf(); 618 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 619 if (pIntRWSem->WROwner != Self) 620 { 503 if (pThis->Writer != Self) 504 { 505 RTCritSectLeave(&pThis->CritSect); 621 506 AssertMsgFailed(("Not read-write owner of rwsem %p.\n", RWSem)); 622 507 return VERR_NOT_OWNER; 623 508 } 624 509 625 /* 626 * Request the mutex. 627 */ 628 int rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT); 629 if (RT_FAILURE(rc)) 630 { 631 AssertMsgFailed(("RTSemMutexWait failed on rwsem %p, rc=%d\n", RWSem, rc)); 632 return rc; 633 } 634 510 Assert(pThis->cWrites > 0); 635 511 /* 636 512 * Release ownership and remove ourselves from the writers count. 637 513 */ 638 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)NIL_RTTHREAD);639 Assert(pIntRWSem->cWriters > 0);640 ASMAtomicXchgU32(&pIntRWSem->cWriters, pIntRWSem->cWriters - 1);641 642 /* 643 * Release the readers if no more writers .644 */ 645 if (!p IntRWSem->cWriters)646 { 647 rc = RTSemEventMultiSignal(p IntRWSem->ReadEvent);514 pThis->cWrites--; 515 if (!pThis->cWrites) 516 pThis->Writer = NIL_RTTHREAD; 517 518 /* 519 * Release the readers if no more writers waiting, otherwise the writers. 520 */ 521 if (!pThis->cWritesWaiting) 522 { 523 rc = RTSemEventMultiSignal(pThis->ReadEvent); 648 524 AssertMsgRC(rc, ("RTSemEventMultiSignal failed for rwsem %p, rc=%d.\n", RWSem, rc)); 649 525 } 650 rc = RTSemMutexRelease(pIntRWSem->Mutex); 651 AssertMsgRC(rc, ("RTSemEventMultiSignal failed for rwsem %p, rc=%d.\n", RWSem, rc)); 652 653 return VINF_SUCCESS; 654 #endif 655 } 656 526 else 527 { 528 rc = RTSemEventSignal(pThis->WriteEvent); 529 AssertMsgRC(rc, ("Failed to signal writers on rwsem %p, rc=%d\n", RWSem, rc)); 530 } 531 RTCritSectLeave(&pThis->CritSect); 532 533 return rc; 534 } 535 536 537 RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW RWSem) 538 { 539 struct RTSEMRWINTERNAL *pThis = RWSem; 540 /* 541 * Validate handle. 542 */ 543 if (!rtsemRWValid(pThis)) 544 { 545 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 546 return VERR_INVALID_HANDLE; 547 } 548 549 /* 550 * Check ownership. 551 */ 552 RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf(); 553 RTTHREAD Writer; 554 ASMAtomicUoReadSize(&pThis->Writer, &Writer); 555 return Writer == Self; 556 } 557 558 559 RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW RWSem) 560 { 561 struct RTSEMRWINTERNAL *pThis = RWSem; 562 /* 563 * Validate handle. 564 */ 565 if (!rtsemRWValid(pThis)) 566 { 567 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 568 return VERR_INVALID_HANDLE; 569 } 570 571 /* 572 * Return the requested data. 573 */ 574 return pThis->cWrites; 575 } 576 577 578 RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW RWSem) 579 { 580 struct RTSEMRWINTERNAL *pThis = RWSem; 581 /* 582 * Validate handle. 583 */ 584 if (!rtsemRWValid(pThis)) 585 { 586 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 587 return VERR_INVALID_HANDLE; 588 } 589 590 /* 591 * Return the requested data. 592 */ 593 return pThis->cWriterReads; 594 }
Note:
See TracChangeset
for help on using the changeset viewer.