- Timestamp:
- Oct 12, 2010 2:43:05 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r0drv/solaris/semeventmulti-r0drv-solaris.c
r30711 r33070 39 39 #endif 40 40 #include <iprt/err.h> 41 #include <iprt/lockvalidator.h> 41 42 #include <iprt/mem.h> 42 43 #include <iprt/mp.h> 43 44 #include <iprt/thread.h> 45 #include <iprt/time.h> 44 46 #include "internal/magics.h" 47 48 49 /******************************************************************************* 50 * Defined Constants And Macros * 51 *******************************************************************************/ 52 /** @name fStateAndGen values 53 * @{ */ 54 /** The state bit number. */ 55 #define RTSEMEVENTMULTISOL_STATE_BIT 0 56 /** The state mask. */ 57 #define RTSEMEVENTMULTISOL_STATE_MASK RT_BIT_32(RTSEMEVENTMULTISOL_STATE_BIT) 58 /** The generation mask. */ 59 #define RTSEMEVENTMULTISOL_GEN_MASK ~RTSEMEVENTMULTISOL_STATE_MASK 60 /** The generation shift. */ 61 #define RTSEMEVENTMULTISOL_GEN_SHIFT 1 62 /** The initial variable value. */ 63 #define RTSEMEVENTMULTISOL_STATE_GEN_INIT UINT32_C(0xfffffffc) 64 /** @} */ 45 65 46 66 … … 56 76 uint32_t volatile u32Magic; 57 77 /** The number of references. */ 58 int32_t volatile cRefs; 59 /** Set if the event object is signaled. */ 60 bool fSignaled; 61 /** Object generation. 62 * This is incremented every time the object is signalled and used to 63 * check for spurious wake-ups. */ 64 uint32_t uSignalGen; 78 uint32_t volatile cRefs; 79 /** The object state bit and generation counter. 80 * The generation counter is incremented every time the object is 81 * signalled. */ 82 uint32_t volatile fStateAndGen; 65 83 /** The Solaris mutex protecting this structure and pairing up the with the cv. */ 66 84 kmutex_t Mtx; … … 90 108 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC; 91 109 pThis->cRefs = 1; 92 pThis->fSignaled = false; 93 pThis->uSignalGen = 0; 110 pThis->fStateAndGen = RTSEMEVENTMULTISOL_STATE_GEN_INIT; 94 111 mutex_init(&pThis->Mtx, "IPRT Multiple Release Event Semaphore", MUTEX_DRIVER, (void *)ipltospl(DISP_LEVEL)); 95 112 cv_init(&pThis->Cnd, "IPRT CV", CV_DRIVER, NULL); … … 103 120 104 121 /** 122 * Retain a reference to the semaphore. 123 * 124 * @param pThis The semaphore. 125 */ 126 DECLINLINE(void) rtR0SemEventMultiSolRetain(PRTSEMEVENTMULTIINTERNAL pThis) 127 { 128 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs); 129 Assert(cRefs && cRefs < 100000); 130 } 131 132 133 /** 105 134 * Destructor that is called when cRefs == 0. 106 * @param pThis The instance to destroy. 135 * 136 * @param pThis The instance to destroy. 107 137 */ 108 138 static void rtSemEventMultiDtor(PRTSEMEVENTMULTIINTERNAL pThis) 109 139 { 140 Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC); 110 141 cv_destroy(&pThis->Cnd); 111 142 mutex_destroy(&pThis->Mtx); 112 143 RTMemFree(pThis); 113 144 } 145 146 147 /** 148 * Release a reference, destroy the thing if necessary. 149 * 150 * @param pThis The semaphore. 151 */ 152 DECLINLINE(void) rtR0SemEventMultiSolRelease(PRTSEMEVENTMULTIINTERNAL pThis) 153 { 154 if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0)) 155 rtSemEventMultiDtor(pThis); 156 } 157 114 158 115 159 … … 128 172 /* Invalidate the handle and wake up all threads that might be waiting on the semaphore. */ 129 173 Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC); 130 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC_DEAD; 174 ASMAtomicWriteU32(&pThis->u32Magic, RTSEMEVENTMULTI_MAGIC_DEAD); 175 ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTISOL_GEN_MASK); 131 176 cv_broadcast(&pThis->Cnd); 132 177 133 178 /* Drop the reference from RTSemEventMultiCreateEx. */ 134 if (ASMAtomicDecS32(&pThis->cRefs)) 135 mutex_exit(&pThis->Mtx); 136 else 137 rtSemEventMultiDtor(pThis); 179 mutex_exit(&pThis->Mtx); 180 rtR0SemEventMultiSolRelease(pThis); 181 138 182 return VINF_SUCCESS; 139 140 183 } 141 184 … … 151 194 VERR_INVALID_HANDLE); 152 195 RT_ASSERT_INTS_ON(); 196 rtR0SemEventMultiSolRetain(pThis); 153 197 154 198 /* … … 175 219 * Do the job. 176 220 */ 177 pThis->fSignaled = true; 178 pThis->uSignalGen++; 221 uint32_t fNew = ASMAtomicUoReadU32(&pThis->fStateAndGen); 222 fNew += 1 << RTSEMEVENTMULTISOL_GEN_SHIFT; 223 fNew |= RTSEMEVENTMULTISOL_STATE_MASK; 224 ASMAtomicWriteU32(&pThis->fStateAndGen, fNew); 225 179 226 cv_broadcast(&pThis->Cnd); 180 227 181 228 mutex_exit(&pThis->Mtx); 182 229 230 rtR0SemEventMultiSolRelease(pThis); 183 231 RT_ASSERT_PREEMPT_CPUID(); 184 232 return VINF_SUCCESS; … … 196 244 VERR_INVALID_HANDLE); 197 245 RT_ASSERT_INTS_ON(); 246 rtR0SemEventMultiSolRetain(pThis); 198 247 199 248 /* … … 218 267 219 268 /* 220 * Do the job .269 * Do the job (could be done without the lock, but play safe). 221 270 */ 222 pThis->fSignaled = false;271 ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTISOL_STATE_MASK); 223 272 224 273 mutex_exit(&pThis->Mtx); 225 274 275 rtR0SemEventMultiSolRelease(pThis); 226 276 RT_ASSERT_PREEMPT_CPUID(); 227 277 return VINF_SUCCESS; 228 278 } 229 279 280 #if 0 /* NEW_STUFF - not working yet :-) */ 281 282 typedef struct RTR0SEMSOLWAIT 283 { 284 /** The absolute timeout given as nano seconds since the start of the 285 * monotonic clock. */ 286 uint64_t uNsAbsTimeout; 287 /** The timeout in nano seconds relative to the start of the wait. */ 288 uint64_t cNsRelTimeout; 289 /** The native timeout value. */ 290 union 291 { 292 /** The timeout (abs lbolt) when fHighRes is false. */ 293 clock_t lTimeout; 294 } u; 295 /** Set if we use high resolution timeouts. */ 296 bool fHighRes; 297 /** Set if it's an indefinite wait. */ 298 bool fIndefinite; 299 /** Set if we've already timed out. 300 * Set by rtR0SemSolWaitDoIt or rtR0SemSolWaitHighResTimeout, read by 301 * rtR0SemSolWaitHasTimedOut. */ 302 bool volatile fTimedOut; 303 /** Whether the wait was interrupted. */ 304 bool fInterrupted; 305 /** Interruptible or uninterruptible wait. */ 306 bool fInterruptible; 307 /** The thread to wake up. */ 308 kthread_t *pThread; 309 } RTR0SEMSOLWAIT; 310 typedef RTR0SEMSOLWAIT *PRTR0SEMSOLWAIT; 311 312 313 /** 314 * Initializes a wait. 315 * 316 * The caller MUST check the wait condition BEFORE calling this function or the 317 * timeout logic will be flawed. 318 * 319 * @returns VINF_SUCCESS or VERR_TIMEOUT. 320 * @param pWait The wait structure. 321 * @param fFlags The wait flags. 322 * @param uTimeout The timeout. 323 * @param pWaitQueue The wait queue head. 324 */ 325 DECLINLINE(int) rtR0SemSolWaitInit(PRTR0SEMSOLWAIT pWait, uint32_t fFlags, uint64_t uTimeout) 326 { 327 /* 328 * Process the flags and timeout. 329 */ 330 if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE)) 331 { 332 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS) 333 uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000) 334 ? uTimeout * UINT32_C(1000000) 335 : UINT64_MAX; 336 if (uTimeout == UINT64_MAX) 337 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE; 338 else 339 { 340 uint64_t u64Now; 341 if (fFlags & RTSEMWAIT_FLAGS_RELATIVE) 342 { 343 if (uTimeout == 0) 344 return VERR_TIMEOUT; 345 346 u64Now = RTTimeSystemNanoTS(); 347 pWait->cNsRelTimeout = uTimeout; 348 pWait->uNsAbsTimeout = u64Now + uTimeout; 349 if (pWait->uNsAbsTimeout < u64Now) /* overflow */ 350 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE; 351 } 352 else 353 { 354 u64Now = RTTimeSystemNanoTS(); 355 if (u64Now >= uTimeout) 356 return VERR_TIMEOUT; 357 358 pWait->cNsRelTimeout = uTimeout - u64Now; 359 pWait->uNsAbsTimeout = uTimeout; 360 } 361 } 362 } 363 364 if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE)) 365 { 366 pWait->fIndefinite = false; 367 if ( (fFlags & (RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE)) 368 || pWait->cNsRelTimeout < UINT32_C(1000000000) / 100 /*Hz*/ * 4) 369 pWait->fHighRes = true; 370 else 371 { 372 #if 1 373 uint64_t cTicks = NSEC_TO_TICK_ROUNDUP(uTimeout); 374 #else 375 uint64_t cTicks = drv_usectohz((clock_t)(uTimeout / 1000)); 376 #endif 377 if (cTicks >= LONG_MAX) 378 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE; 379 else 380 { 381 pWait->u.lTimeout = ddi_get_lbolt() + cTicks; 382 pWait->fHighRes = false; 383 } 384 } 385 } 386 387 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE) 388 { 389 pWait->fIndefinite = true; 390 pWait->fHighRes = false; 391 pWait->uNsAbsTimeout = UINT64_MAX; 392 pWait->cNsRelTimeout = UINT64_MAX; 393 pWait->u.lTimeout = LONG_MAX; 394 } 395 396 pWait->fTimedOut = false; 397 pWait->fInterrupted = false; 398 pWait->fInterruptible = !!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE); 399 pWait->pThread = curthread; 400 401 return VINF_SUCCESS; 402 } 403 404 405 /** 406 * Cyclic timeout callback that sets the timeout indicator and wakes up the 407 * waiting thread. 408 * 409 * @param pvUser The wait structure. 410 */ 411 static void rtR0SemSolWaitHighResTimeout(void *pvUser) 412 { 413 PRTR0SEMSOLWAIT pWait = (PRTR0SEMSOLWAIT)pvUser; 414 kthread_t *pThread = pWait->pThread; 415 if (VALID_PTR(pThread)) /* paranoia */ 416 { 417 ASMAtomicWriteBool(&pWait->fTimedOut, true); 418 setrun(pThread); 419 } 420 } 421 422 423 /** 424 * Do the actual wait. 425 * 426 * @param pWait The wait structure. 427 * @param pCnd The condition variable to wait on. 428 * @param pMtx The mutex related to the condition variable. 429 * The caller has entered this. 430 */ 431 DECLINLINE(void) rtR0SemSolWaitDoIt(PRTR0SEMSOLWAIT pWait, kcondvar_t *pCnd, kmutex_t *pMtx) 432 { 433 int rc = 1; 434 if (pWait->fIndefinite) 435 { 436 /* 437 * No timeout - easy. 438 */ 439 if (pWait->fInterruptible) 440 rc = cv_wait_sig(pCnd, pMtx); 441 else 442 cv_wait(pCnd, pMtx); 443 } 444 else if (pWait->fHighRes) 445 { 446 /* 447 * High resolution timeout - arm a one-shot cyclic for waking up 448 * the thread at the desired time. 449 */ 450 cyc_handler_t Cyh; 451 Cyh.cyh_arg = pWait; 452 Cyh.cyh_func = rtR0SemSolWaitHighResTimeout; 453 Cyh.cyh_level = CY_LOW_LEVEL; /// @todo try CY_LOCK_LEVEL and CY_HIGH_LEVEL? 454 455 cyc_time_t Cyt; 456 Cyt.cyt_when = pWait->uNsAbsTimeout; 457 Cyt.cyt_interval = 0; 458 459 mutex_enter(&cpu_lock); 460 cyclic_id_t idCy = cyclic_add(&Cyh, &Cyt); 461 mutex_exit(&cpu_lock); 462 463 if (pWait->fInterruptible) 464 rc = cv_wait_sig(pCnd, pMtx); 465 else 466 cv_wait(pCnd, pMtx); 467 468 mutex_enter(&cpu_lock); 469 cyclic_remove(idCy); 470 mutex_exit(&cpu_lock); 471 } 472 else 473 { 474 /* 475 * Normal timeout. 476 */ 477 if (pWait->fInterruptible) 478 rc = cv_timedwait_sig(pCnd, pMtx, pWait->u.lTimeout); 479 else 480 rc = cv_timedwait(pCnd, pMtx, pWait->u.lTimeout); 481 } 482 483 /* Above zero means normal wake-up. */ 484 if (rc > 0) 485 return; 486 487 /* Timeout is signalled by -1. */ 488 if (rc == -1) 489 pWait->fTimedOut = true; 490 /* Interruption is signalled by 0. */ 491 else 492 { 493 AssertMsg(rc == 0, ("rc=%d\n", rc)); 494 pWait->fInterrupted = true; 495 } 496 } 497 498 499 /** 500 * Checks if a solaris wait was interrupted. 501 * 502 * @returns true / false 503 * @param pWait The wait structure. 504 * @remarks This shall be called before the first rtR0SemSolWaitDoIt(). 505 */ 506 DECLINLINE(bool) rtR0SemSolWaitWasInterrupted(PRTR0SEMSOLWAIT pWait) 507 { 508 return pWait->fInterrupted; 509 } 510 511 512 /** 513 * Checks if a solaris wait has timed out. 514 * 515 * @returns true / false 516 * @param pWait The wait structure. 517 */ 518 DECLINLINE(bool) rtR0SemSolWaitHasTimedOut(PRTR0SEMSOLWAIT pWait) 519 { 520 return pWait->fTimedOut; 521 } 522 523 524 /** 525 * Deletes a solaris wait. 526 * 527 * @param pWait The wait structure. 528 */ 529 DECLINLINE(void) rtR0SemSolWaitDelete(PRTR0SEMSOLWAIT pWait) 530 { 531 pWait->pThread = NULL; 532 } 533 534 535 536 /** 537 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug. 538 * 539 * @returns VBox status code. 540 * @param pThis The event semaphore. 541 * @param fFlags See RTSemEventMultiWaitEx. 542 * @param uTimeout See RTSemEventMultiWaitEx. 543 * @param pSrcPos The source code position of the wait. 544 */ 545 static int rtR0SemEventMultiSolWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, 546 PCRTLOCKVALSRCPOS pSrcPos) 547 { 548 uint32_t fOrgStateAndGen; 549 int rc; 550 551 /* 552 * Validate the input. 553 */ 554 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); 555 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); 556 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); 557 rtR0SemEventMultiSolRetain(pThis); 558 mutex_enter(&pThis->Mtx); /* this could be moved down to the else, but play safe for now. */ 559 560 /* 561 * Is the event already signalled or do we have to wait? 562 */ 563 fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen); 564 if (fOrgStateAndGen & RTSEMEVENTMULTISOL_STATE_MASK) 565 rc = VINF_SUCCESS; 566 else 567 { 568 /* 569 * We have to wait. 570 */ 571 RTR0SEMSOLWAIT Wait; 572 rtR0SemSolWaitInit(&Wait, fFlags, uTimeout); 573 for (;;) 574 { 575 /* The destruction test. */ 576 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)) 577 rc = VERR_SEM_DESTROYED; 578 else 579 { 580 /* Check the exit conditions. */ 581 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)) 582 rc = VERR_SEM_DESTROYED; 583 else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen) 584 rc = VINF_SUCCESS; 585 else if (rtR0SemSolWaitHasTimedOut(&Wait)) 586 rc = VERR_TIMEOUT; 587 else if (rtR0SemSolWaitWasInterrupted(&Wait)) 588 rc = VERR_INTERRUPTED; 589 else 590 { 591 /* Do the wait and then recheck the conditions. */ 592 rtR0SemSolWaitDoIt(&Wait, &pThis->Cnd, &pThis->Mtx); 593 continue; 594 } 595 } 596 break; 597 } 598 rtR0SemSolWaitDelete(&Wait); 599 } 600 601 mutex_exit(&pThis->Mtx); 602 rtR0SemEventMultiSolRelease(pThis); 603 return rc; 604 } 605 606 607 608 #undef RTSemEventMultiWaitEx 609 RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout) 610 { 611 #ifndef RTSEMEVENT_STRICT 612 return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, NULL); 613 #else 614 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API(); 615 return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos); 616 #endif 617 } 618 619 620 RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout, 621 RTHCUINTPTR uId, RT_SRC_POS_DECL) 622 { 623 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API(); 624 return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos); 625 } 626 627 628 #include "../../generic/RTSemEventMultiWait-2-ex-generic.cpp" 629 #include "../../generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp" 630 631 #else /* OLD_STUFF */ 230 632 231 633 /** … … 271 673 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), 272 674 VERR_INVALID_HANDLE); 675 rtR0SemEventMultiSolRetain(pThis); 273 676 if (cMillies) 274 677 RT_ASSERT_PREEMPTIBLE(); … … 276 679 mutex_enter(&pThis->Mtx); 277 680 Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC); 278 ASMAtomicIncS32(&pThis->cRefs); 279 280 if (pThis->fSignaled) 681 682 if (pThis->fStateAndGen & RTSEMEVENTMULTISOL_STATE_MASK) 281 683 rc = VINF_SUCCESS; 282 684 else if (!cMillies) … … 287 689 for (;;) 288 690 { 289 uint32_t const uSignalGenBeforeWait = pThis-> uSignalGen;691 uint32_t const uSignalGenBeforeWait = pThis->fStateAndGen; 290 692 rc = rtSemEventMultiWaitWorker(pThis, cMillies, fInterruptible); 291 693 if (rc > 0) … … 293 695 if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC)) 294 696 { 295 if (pThis-> uSignalGen == uSignalGenBeforeWait)697 if (pThis->fStateAndGen == uSignalGenBeforeWait) 296 698 continue; /* Spurious wake-up, go back to waiting. */ 297 699 … … 313 715 } 314 716 315 if (RT_LIKELY(ASMAtomicDecS32(&pThis->cRefs))) 316 mutex_exit(&pThis->Mtx); 317 else 318 rtSemEventMultiDtor(pThis); 717 mutex_exit(&pThis->Mtx); 718 rtR0SemEventMultiSolRelease(pThis); 319 719 return rc; 320 720 } … … 332 732 } 333 733 734 #endif
Note:
See TracChangeset
for help on using the changeset viewer.