semevent-r0drv-darwin.cpp revision 8f9193a0c6db641a38d56ceba5747557f1e9927d
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * IPRT - Single Release Event Semaphores, Ring-0 Driver, Darwin.
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * Copyright (C) 2006-2010 Oracle Corporation
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * available from http://www.virtualbox.org. This file is free software;
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * General Public License (GPL) as published by the Free Software
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * The contents of this file may alternatively be used under the terms
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * of the Common Development and Distribution License Version 1.0
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * VirtualBox OSE distribution, in which case the provisions of the
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * CDDL are applicable instead of those of the GPL.
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * You may elect to license modified versions of this file under the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * terms and conditions of either the GPL or the CDDL or both.
ef1c003b45b1550236f47a2da7eea2e25f224b41vboxsync/*******************************************************************************
0486df2e670fa5d25ca947fd92b19dd54229692dvboxsync* Header Files *
0486df2e670fa5d25ca947fd92b19dd54229692dvboxsync*******************************************************************************/
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync/*******************************************************************************
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync* Structures and Typedefs *
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync*******************************************************************************/
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync * Waiter entry. Lives on the stack.
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync /** The list node. */
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync /** Flag set when waking up the thread by signal or destroy. */
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync bool volatile fWokenUp;
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync/** Pointer to waiter entry. */
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsynctypedef RTSEMEVENTDARWINENTRY *PRTSEMEVENTDARWINENTRY;
f4ccb18a71e0e531719734918583f84fbc72ebfevboxsync * Darwin event semaphore.
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync /** Magic value (RTSEMEVENT_MAGIC). */
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync /** Reference counter. */
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync /** Set if there are blocked threads. */
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync /** Set if the event object is signaled. */
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync bool volatile fSignaled;
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync /** List of waiting and woken up threads. */
771761cda2c81e899526a0dce22c8cd2510fff82vboxsync /** The spinlock protecting us. */
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsyncRTDECL(int) RTSemEventCreate(PRTSEMEVENT phEventSem)
b459362b1c9b5ce5e6bf4ceb32ffe1294c08be07vboxsync return RTSemEventCreateEx(phEventSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsyncRTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...)
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync AssertCompile(sizeof(RTSEMEVENTINTERNAL) > sizeof(void *));
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync AssertReturn(!(fFlags & ~RTSEMEVENT_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)RTMemAlloc(sizeof(*pThis));
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync pThis->pSpinlock = lck_spin_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync * Retain a reference to the semaphore.
cfd41a3683178a30bac4417128b4673806653797vboxsync * @param pThis The semaphore.
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsyncDECLINLINE(void) rtR0SemEventDarwinRetain(PRTSEMEVENTINTERNAL pThis)
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * Release a reference, destroy the thing if necessary.
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * @param pThis The semaphore.
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsyncDECLINLINE(void) rtR0SemEventDarwinRelease(PRTSEMEVENTINTERNAL pThis)
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
9c59bcefe2993070fafaf0d6cee9673f48479128vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENT_MAGIC); /* make the handle invalid */
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync /* abort waiting threads. */
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync RTListForEach(&pThis->WaitList, pWaiter, RTSEMEVENTDARWINENTRY, Node)
9c59bcefe2993070fafaf0d6cee9673f48479128vboxsync thread_wakeup_prim((event_t)pWaiter, FALSE /* all threads */, THREAD_RESTART);
2ebf77e955a41ebc4eaa4a0d2a9aaf05540d2e4dvboxsync PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
2ebf77e955a41ebc4eaa4a0d2a9aaf05540d2e4dvboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC,
2ebf77e955a41ebc4eaa4a0d2a9aaf05540d2e4dvboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync /** @todo should probably disable interrupts here... update
9c59bcefe2993070fafaf0d6cee9673f48479128vboxsync * Wake up one thread.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync RTListForEach(&pThis->WaitList, pWaiter, RTSEMEVENTDARWINENTRY, Node)
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync thread_wakeup_prim((event_t)pWaiter, FALSE /* all threads */, THREAD_AWAKENED);
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug.
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync * @returns VBox status code.
62e5c2cfabb91397405d7bfe7908ec2b3a483831vboxsync * @param pThis The event semaphore.
62e5c2cfabb91397405d7bfe7908ec2b3a483831vboxsync * @param fFlags See RTSemEventWaitEx.
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync * @param uTimeout See RTSemEventWaitEx.
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync * @param pSrcPos The source code position of the wait.
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsyncstatic int rtR0SemEventDarwinWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync * Validate the input.
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * In the signaled state?
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync if (ASMAtomicCmpXchgBool(&pThis->fSignaled, false, true))
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * We have to wait. So, we'll need to convert the timeout and figure
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * out if it's indefinite or not.
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync uTimeout = u64Now < uTimeout ? uTimeout - u64Now : 0;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * Poll call, we already checked the condition above so no need to
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync * wait for anything.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * Do the actual waiting.
9ced981a0263f6280ccbf5dc64c0e81fbe4a2fdavboxsync ASMAtomicWriteBool(&pThis->fHaveBlockedThreads, true);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync wait_interrupt_t fInterruptible = fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE ? THREAD_ABORTSAFE : THREAD_UNINT;
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync rcWait = lck_spin_sleep(pThis->pSpinlock, LCK_SLEEP_DEFAULT, (event_t)&Waiter, fInterruptible);
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync nanoseconds_to_absolutetime(uNsAbsTimeout, &u64AbsTime);
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync rcWait = lck_spin_sleep_deadline(pThis->pSpinlock, LCK_SLEEP_DEFAULT,
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync * Deal with the wait result.
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync if (RT_LIKELY(pThis->u32Magic == RTSEMEVENT_MAGIC))
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync continue; /* Seen this happen after fork/exec/something. */
9ced981a0263f6280ccbf5dc64c0e81fbe4a2fdavboxsync rc = !Waiter.fWokenUp ? VERR_TIMEOUT : VINF_SUCCESS;
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync rc = !Waiter.fWokenUp ? VERR_INTERRUPTED : VINF_SUCCESS;
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync AssertMsg(pThis->u32Magic == ~RTSEMEVENT_MAGIC, ("%#x\n", pThis->u32Magic));
674c51d0cb8c72a2852b315b70f76d11d82b20f5vboxsyncRTDECL(int) RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout)
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync return rtR0SemEventDarwinWait(hEventSem, fFlags, uTimeout, NULL);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync return rtR0SemEventDarwinWait(hEventSem, fFlags, uTimeout, &SrcPos);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsyncRTDECL(int) RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout,
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();