5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, FreeBSD.
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * Permission is hereby granted, free of charge, to any person
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * obtaining a copy of this software and associated documentation
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * files (the "Software"), to deal in the Software without
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * restriction, including without limitation the rights to use,
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * copy, modify, merge, publish, distribute, sublicense, and/or sell
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * copies of the Software, and to permit persons to whom the
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * Software is furnished to do so, subject to the following
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * conditions:
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * The above copyright notice and this permission notice shall be
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * included in all copies or substantial portions of the Software.
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * OTHER DEALINGS IN THE SOFTWARE.
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync/*******************************************************************************
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync* Header Files *
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync*******************************************************************************/
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync/*******************************************************************************
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync* Defined Constants And Macros *
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync*******************************************************************************/
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync/** @name fStateAndGen values
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync/** The state bit number. */
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync/** The state mask. */
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync#define RTSEMEVENTMULTIBSD_STATE_MASK RT_BIT_32(RTSEMEVENTMULTIBSD_STATE_BIT)
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync/** The generation mask. */
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync#define RTSEMEVENTMULTIBSD_GEN_MASK ~RTSEMEVENTMULTIBSD_STATE_MASK
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync/** The generation shift. */
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync/** The initial variable value. */
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync#define RTSEMEVENTMULTIBSD_STATE_GEN_INIT UINT32_C(0xfffffffc)
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync/*******************************************************************************
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync* Structures and Typedefs *
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync*******************************************************************************/
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync * FreeBSD multiple release event semaphore.
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync /** Magic value (RTSEMEVENTMULTI_MAGIC). */
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync /** The object state bit and generation counter.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * The generation counter is incremented every time the object is
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * signalled. */
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync /** Reference counter. */
1f1986470af9f0bb750dd859b142dc2e952deb20vboxsync} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
ab93606043a9881487aa83be04191d2f4ea24071vboxsyncRTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
ab93606043a9881487aa83be04191d2f4ea24071vboxsync return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
ab93606043a9881487aa83be04191d2f4ea24071vboxsyncRTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
ab93606043a9881487aa83be04191d2f4ea24071vboxsync const char *pszNameFmt, ...)
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync pThis->fStateAndGen = RTSEMEVENTMULTIBSD_STATE_GEN_INIT;
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * Retain a reference to the semaphore.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * @param pThis The semaphore.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsyncDECLINLINE(void) rtR0SemEventMultiBsdRetain(PRTSEMEVENTMULTIINTERNAL pThis)
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * Release a reference, destroy the thing if necessary.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * @param pThis The semaphore.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsyncDECLINLINE(void) rtR0SemEventMultiBsdRelease(PRTSEMEVENTMULTIINTERNAL pThis)
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsyncRTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * Validate input.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * Invalidate it and signal the object just in case.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTIBSD_GEN_MASK);
ab93606043a9881487aa83be04191d2f4ea24071vboxsyncRTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * Validate input.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * Signal the event object. The cause of the parnoia here is racing to try
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * deal with racing RTSemEventMultiSignal calls (should probably be
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * forbidden, but it's relatively easy to handle).
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync fNew = fOld = ASMAtomicUoReadU32(&pThis->fStateAndGen);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync while (!ASMAtomicCmpXchgU32(&pThis->fStateAndGen, fNew, fOld));
ab93606043a9881487aa83be04191d2f4ea24071vboxsyncRTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * Validate input.
ab93606043a9881487aa83be04191d2f4ea24071vboxsync PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * Reset it.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTIBSD_STATE_MASK);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * @returns VBox status code.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * @param pThis The event semaphore.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * @param fFlags See RTSemEventMultiWaitEx.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * @param uTimeout See RTSemEventMultiWaitEx.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * @param pSrcPos The source code position of the wait.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsyncstatic int rtR0SemEventMultiBsdWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * Validate the input.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * Is the event already signalled or do we have to wait?
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync if (fOrgStateAndGen & RTSEMEVENTMULTIBSD_STATE_MASK)
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync * We have to wait.
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync rc = rtR0SemBsdWaitInit(&Wait, fFlags, uTimeout, pThis);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync /* The destruction test. */
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync /* Check the exit conditions. */
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync /* Do the wait and then recheck the conditions. */
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsyncRTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, NULL);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsyncRTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
9837b5326a44772e824a15f2d5d937ddfd627d54vboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();