Changeset 28503 in vbox for trunk/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp
- Timestamp:
- Apr 20, 2010 7:19:05 AM (15 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp
r28501 r28503 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - Semaphores, Ring-0 Driver, Darwin.3 * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Darwin. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2006-20 07Sun Microsystems, Inc.7 * Copyright (C) 2006-2010 Sun Microsystems, Inc. 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 50 50 * Structures and Typedefs * 51 51 *******************************************************************************/ 52 /**53 * Darwin event semaphore.54 */55 typedef struct RTSEMEVENTINTERNAL56 {57 /** Magic value (RTSEMEVENT_MAGIC). */58 uint32_t volatile u32Magic;59 /** The number of waiting threads. */60 uint32_t volatile cWaiters;61 /** Set if the event object is signaled. */62 uint8_t volatile fSignaled;63 /** The number of threads in the process of waking up. */64 uint32_t volatile cWaking;65 /** The spinlock protecting us. */66 lck_spin_t *pSpinlock;67 } RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;68 69 70 52 /** 71 53 * Darwin multiple release event semaphore. … … 84 66 lck_spin_t *pSpinlock; 85 67 } RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL; 86 87 88 #if 0 /** @todo */89 /**90 * Darwin mutex semaphore.91 */92 typedef struct RTSEMMUTEXINTERNAL93 {94 /** Magic value (RTSEMMUTEX_MAGIC). */95 uint32_t volatile u32Magic;96 /** The mutex. */97 lck_mtx_t *pMtx;98 } RTSEMMUTEXINTERNAL, *PRTSEMMUTEXINTERNAL;99 100 #endif101 102 103 /**104 * Wrapper for the darwin semaphore structure.105 */106 typedef struct RTSEMFASTMUTEXINTERNAL107 {108 /** Magic value (RTSEMFASTMUTEX_MAGIC). */109 uint32_t u32Magic;110 /** The mutex. */111 lck_mtx_t *pMtx;112 } RTSEMFASTMUTEXINTERNAL, *PRTSEMFASTMUTEXINTERNAL;113 114 115 116 RTDECL(int) RTSemEventCreate(PRTSEMEVENT phEventSem)117 {118 return RTSemEventCreateEx(phEventSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);119 }120 121 122 RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...)123 {124 AssertCompile(sizeof(RTSEMEVENTINTERNAL) > sizeof(void *));125 AssertReturn(!(fFlags & ~RTSEMEVENT_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);126 AssertPtrReturn(phEventSem, VERR_INVALID_POINTER);127 RT_ASSERT_PREEMPTIBLE();128 129 PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)RTMemAlloc(sizeof(*pThis));130 if (pThis)131 {132 pThis->u32Magic = RTSEMEVENT_MAGIC;133 pThis->cWaiters = 0;134 pThis->cWaking = 0;135 pThis->fSignaled = 0;136 Assert(g_pDarwinLockGroup);137 pThis->pSpinlock = lck_spin_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);138 if (pThis->pSpinlock)139 {140 *phEventSem = pThis;141 return VINF_SUCCESS;142 }143 144 pThis->u32Magic = 0;145 RTMemFree(pThis);146 }147 return VERR_NO_MEMORY;148 }149 150 151 RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem)152 {153 PRTSEMEVENTINTERNAL pThis = hEventSem;154 if (pThis == NIL_RTSEMEVENT)155 return VINF_SUCCESS;156 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);157 AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);158 RT_ASSERT_INTS_ON();159 160 lck_spin_lock(pThis->pSpinlock);161 ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */162 if (pThis->cWaiters > 0)163 {164 /* abort waiting thread, last man cleans up. */165 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);166 thread_wakeup_prim((event_t)pThis, FALSE /* all threads */, THREAD_RESTART);167 lck_spin_unlock(pThis->pSpinlock);168 }169 else if (pThis->cWaking)170 /* the last waking thread is gonna do the cleanup */171 lck_spin_unlock(pThis->pSpinlock);172 else173 {174 lck_spin_unlock(pThis->pSpinlock);175 lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);176 RTMemFree(pThis);177 }178 179 return VINF_SUCCESS;180 }181 182 183 RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)184 {185 PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;186 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);187 AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC,188 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),189 VERR_INVALID_HANDLE);190 RT_ASSERT_PREEMPT_CPUID_VAR();191 RT_ASSERT_INTS_ON();192 193 /** @todo should probably disable interrupts here... update194 * semspinmutex-r0drv-generic.c when done. */195 lck_spin_lock(pThis->pSpinlock);196 197 if (pThis->cWaiters > 0)198 {199 ASMAtomicDecU32(&pThis->cWaiters);200 ASMAtomicIncU32(&pThis->cWaking);201 thread_wakeup_prim((event_t)pThis, TRUE /* one thread */, THREAD_AWAKENED);202 /** @todo this isn't safe. a scheduling interrupt on the other cpu while we're in here203 * could cause the thread to be timed out before we manage to wake it up and the event204 * ends up in the wrong state. ditto for posix signals.205 * Update: check the return code; it will return KERN_NOT_WAITING if no one is around. */206 }207 else208 ASMAtomicXchgU8(&pThis->fSignaled, true);209 210 lck_spin_unlock(pThis->pSpinlock);211 212 RT_ASSERT_PREEMPT_CPUID();213 return VINF_SUCCESS;214 }215 216 217 static int rtSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies, wait_interrupt_t fInterruptible)218 {219 PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;220 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);221 AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);222 if (cMillies)223 RT_ASSERT_PREEMPTIBLE();224 225 lck_spin_lock(pThis->pSpinlock);226 227 int rc;228 if (pThis->fSignaled)229 {230 Assert(!pThis->cWaiters);231 ASMAtomicXchgU8(&pThis->fSignaled, false);232 rc = VINF_SUCCESS;233 }234 else if (!cMillies)235 rc = VERR_TIMEOUT;236 else237 {238 ASMAtomicIncU32(&pThis->cWaiters);239 240 wait_result_t rcWait;241 if (cMillies == RT_INDEFINITE_WAIT)242 rcWait = lck_spin_sleep(pThis->pSpinlock, LCK_SLEEP_DEFAULT, (event_t)pThis, fInterruptible);243 else244 {245 uint64_t u64AbsTime;246 nanoseconds_to_absolutetime(cMillies * UINT64_C(1000000), &u64AbsTime);247 u64AbsTime += mach_absolute_time();248 249 rcWait = lck_spin_sleep_deadline(pThis->pSpinlock, LCK_SLEEP_DEFAULT,250 (event_t)pThis, fInterruptible, u64AbsTime);251 }252 switch (rcWait)253 {254 case THREAD_AWAKENED:255 Assert(pThis->cWaking > 0);256 if ( !ASMAtomicDecU32(&pThis->cWaking)257 && pThis->u32Magic != RTSEMEVENT_MAGIC)258 {259 /* the event was destroyed after we woke up, as the last thread do the cleanup. */260 lck_spin_unlock(pThis->pSpinlock);261 Assert(g_pDarwinLockGroup);262 lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);263 RTMemFree(pThis);264 return VINF_SUCCESS;265 }266 rc = VINF_SUCCESS;267 break;268 269 case THREAD_TIMED_OUT:270 Assert(cMillies != RT_INDEFINITE_WAIT);271 ASMAtomicDecU32(&pThis->cWaiters);272 rc = VERR_TIMEOUT;273 break;274 275 case THREAD_INTERRUPTED:276 Assert(fInterruptible);277 ASMAtomicDecU32(&pThis->cWaiters);278 rc = VERR_INTERRUPTED;279 break;280 281 case THREAD_RESTART:282 /* Last one out does the cleanup. */283 if (!ASMAtomicDecU32(&pThis->cWaking))284 {285 lck_spin_unlock(pThis->pSpinlock);286 Assert(g_pDarwinLockGroup);287 lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);288 RTMemFree(pThis);289 return VERR_SEM_DESTROYED;290 }291 292 rc = VERR_SEM_DESTROYED;293 break;294 295 default:296 AssertMsgFailed(("rcWait=%d\n", rcWait));297 rc = VERR_GENERAL_FAILURE;298 break;299 }300 }301 302 lck_spin_unlock(pThis->pSpinlock);303 return rc;304 }305 306 307 RTDECL(int) RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)308 {309 return rtSemEventWait(hEventSem, cMillies, THREAD_UNINT);310 }311 312 313 RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)314 {315 return rtSemEventWait(hEventSem, cMillies, THREAD_ABORTSAFE);316 }317 68 318 69 … … 525 276 } 526 277 527 528 529 530 531 #if 0 /* need proper timeout lock function! */532 RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phFastMtx)533 {534 RT_ASSERT_PREEMPTIBLE();535 AssertCompile(sizeof(RTSEMMUTEXINTERNAL) > sizeof(void *));536 PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));537 if (pThis)538 {539 pThis->u32Magic = RTSEMMUTEX_MAGIC;540 Assert(g_pDarwinLockGroup);541 pThis->pMtx = lck_mtx_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);542 if (pThis->pMtx)543 {544 *phFastMtx = pThis;545 return VINF_SUCCESS;546 }547 RTMemFree(pThis);548 }549 return VERR_NO_MEMORY;550 }551 552 553 RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem)554 {555 /*556 * Validate input.557 */558 PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;559 if (!pThis)560 return VERR_INVALID_PARAMETER;561 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);562 AssertMsg(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);563 RT_ASSERT_INTS_ON();564 565 /*566 * Invalidate it and signal the object just in case.567 */568 ASMAtomicIncU32(&pThis->u32Magic);569 570 Assert(g_pDarwinLockGroup);571 lck_mtx_free(pThis->pMtx, g_pDarwinLockGroup);572 pThis->pMtx = NULL;573 574 RTMemFree(pThis);575 return VINF_SUCCESS;576 }577 578 579 RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)580 {581 /*582 * Validate input.583 */584 PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;585 if (!pThis)586 return VERR_INVALID_PARAMETER;587 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);588 AssertMsg(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);589 if (cMillies)590 RT_ASSERT_PREEMPTIBLE();591 592 /*593 * Get the mutex.594 */595 wait_result_t rc = lck_mtx_lock_deadlink596 #if 1597 #else598 NTSTATUS rcNt;599 if (cMillies == RT_INDEFINITE_WAIT)600 rcNt = KeWaitForSingleObject(&pThis->Mutex, Executive, KernelMode, TRUE, NULL);601 else602 {603 LARGE_INTEGER Timeout;604 Timeout.QuadPart = -(int64_t)cMillies * 10000;605 rcNt = KeWaitForSingleObject(&pThis->Mutex, Executive, KernelMode, TRUE, &Timeout);606 }607 switch (rcNt)608 {609 case STATUS_SUCCESS:610 if (pThis->u32Magic == RTSEMMUTEX_MAGIC)611 return VINF_SUCCESS;612 return VERR_SEM_DESTROYED;613 case STATUS_ALERTED:614 return VERR_INTERRUPTED; /** @todo VERR_INTERRUPTED isn't correct anylonger. please fix r0drv stuff! */615 case STATUS_USER_APC:616 return VERR_INTERRUPTED; /** @todo VERR_INTERRUPTED isn't correct anylonger. please fix r0drv stuff! */617 case STATUS_TIMEOUT:618 return VERR_TIMEOUT;619 default:620 AssertMsgFailed(("pThis->u32Magic=%RX32 pThis=%p: wait returned %lx!\n",621 pThis->u32Magic, pThis, (long)rcNt));622 return VERR_INTERNAL_ERROR;623 }624 #endif625 return VINF_SUCCESS;626 }627 628 629 RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem)630 {631 /*632 * Validate input.633 */634 PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;635 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);636 AssertMsg(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);637 RT_ASSERT_PREEMPTIBLE();638 639 /*640 * Release the mutex.641 */642 #ifdef RT_USE_FAST_MUTEX643 ExReleaseFastMutex(&pThis->Mutex);644 #else645 KeReleaseMutex(&pThis->Mutex, FALSE);646 #endif647 return VINF_SUCCESS;648 }649 650 #endif /* later */651 652 653 654 655 RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx)656 {657 AssertCompile(sizeof(RTSEMFASTMUTEXINTERNAL) > sizeof(void *));658 AssertPtrReturn(phFastMtx, VERR_INVALID_POINTER);659 RT_ASSERT_PREEMPTIBLE();660 661 PRTSEMFASTMUTEXINTERNAL pThis = (PRTSEMFASTMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));662 if (pThis)663 {664 pThis->u32Magic = RTSEMFASTMUTEX_MAGIC;665 Assert(g_pDarwinLockGroup);666 pThis->pMtx = lck_mtx_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);667 if (pThis->pMtx)668 {669 *phFastMtx = pThis;670 return VINF_SUCCESS;671 }672 673 RTMemFree(pThis);674 }675 return VERR_NO_MEMORY;676 }677 678 679 RTDECL(int) RTSemFastMutexDestroy(RTSEMFASTMUTEX hFastMtx)680 {681 PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;682 if (pThis == NIL_RTSEMFASTMUTEX)683 return VINF_SUCCESS;684 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);685 AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);686 RT_ASSERT_INTS_ON();687 688 ASMAtomicWriteU32(&pThis->u32Magic, RTSEMFASTMUTEX_MAGIC_DEAD);689 Assert(g_pDarwinLockGroup);690 lck_mtx_free(pThis->pMtx, g_pDarwinLockGroup);691 pThis->pMtx = NULL;692 RTMemFree(pThis);693 694 return VINF_SUCCESS;695 }696 697 698 RTDECL(int) RTSemFastMutexRequest(RTSEMFASTMUTEX hFastMtx)699 {700 PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;701 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);702 AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);703 RT_ASSERT_PREEMPTIBLE();704 705 lck_mtx_lock(pThis->pMtx);706 return VINF_SUCCESS;707 }708 709 710 RTDECL(int) RTSemFastMutexRelease(RTSEMFASTMUTEX hFastMtx)711 {712 PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;713 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);714 AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);715 RT_ASSERT_PREEMPTIBLE();716 717 lck_mtx_unlock(pThis->pMtx);718 return VINF_SUCCESS;719 }720
Note:
See TracChangeset
for help on using the changeset viewer.