semeventmulti-r0drv-linux.c revision 683eff3070b1b86fe71b71af7fda82766ea19d17
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Linux.
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2010 Oracle Corporation
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * available from http://www.virtualbox.org. This file is free software;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * you can redistribute it and/or modify it under the terms of the GNU
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * General Public License (GPL) as published by the Free Software
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * The contents of this file may alternatively be used under the terms
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync * of the Common Development and Distribution License Version 1.0
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync * VirtualBox OSE distribution, in which case the provisions of the
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync * CDDL are applicable instead of those of the GPL.
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync * You may elect to license modified versions of this file under the
1ce069685b24d243eb0464f46d4c56b250c64445vboxsync * terms and conditions of either the GPL or the CDDL or both.
a55af63ead2dcca370bfc0dfe49771d9dcc61b93vboxsync/*******************************************************************************
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync* Header Files *
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync*******************************************************************************/
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/*******************************************************************************
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync* Defined Constants And Macros *
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync*******************************************************************************/
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/** @name fStateAndGen values
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/** The state bit number. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/** The state mask. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#define RTSEMEVENTMULTILNX_STATE_MASK RT_BIT_32(RTSEMEVENTMULTILNX_STATE_BIT)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/** The generation mask. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#define RTSEMEVENTMULTILNX_GEN_MASK ~RTSEMEVENTMULTILNX_STATE_MASK
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/** The generation shift. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/** The initial variable value. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#define RTSEMEVENTMULTILNX_STATE_GEN_INIT UINT32_C(0xfffffffc)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/*******************************************************************************
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync* Structures and Typedefs *
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync*******************************************************************************/
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Linux event semaphore.
a0644dbbd30adb9bd2937110d6f016e56c4cc52bvboxsync /** Magic value (RTSEMEVENTMULTI_MAGIC). */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** The object state bit and generation counter.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * The generation counter is incremented every time the object is */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** Reference counter. */
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsync /** The wait queue. */
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsync} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
229a63857c5fd2e441a62206eacce4156d0b2a26vboxsyncRTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsyncRTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync const char *pszNameFmt, ...)
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync pThis->fStateAndGen = RTSEMEVENTMULTILNX_STATE_GEN_INIT;
4c8907a420ed66a42f729eb08cddf9c1e57f25eavboxsync * Retain a reference to the semaphore.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param pThis The semaphore.
824ae3158a8b8f8233fec3f5a12c81f139933698vboxsyncDECLINLINE(void) rtR0SemEventMultiLnxRetain(PRTSEMEVENTMULTIINTERNAL pThis)
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * Release a reference, destroy the thing if necessary.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param pThis The semaphore.
824ae3158a8b8f8233fec3f5a12c81f139933698vboxsyncDECLINLINE(void) rtR0SemEventMultiLnxRelease(PRTSEMEVENTMULTIINTERNAL pThis)
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsyncRTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Validate input.
824ae3158a8b8f8233fec3f5a12c81f139933698vboxsync PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * Invalidate it and signal the object just in case.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTILNX_GEN_MASK);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsyncRTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync * Validate input.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * Signal the event object. The cause of the parnoia here is racing to try
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * deal with racing RTSemEventMultiSignal calls (should probably be
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * forbidden, but it's relatively easy to handle).
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync fNew = fOld = ASMAtomicUoReadU32(&pThis->fStateAndGen);
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync while (!ASMAtomicCmpXchgU32(&pThis->fStateAndGen, fNew, fOld));
9bb98d54790a98dad0ad6d9bdc5d319b6fdf0bffvboxsyncRTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * Validate input.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * Reset it.
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTILNX_STATE_MASK);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * @returns VBox status code.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * @param pThis The event semaphore.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * @param fFlags See RTSemEventMultiWaitEx.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * @param uTimeout See RTSemEventMultiWaitEx.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * @param pSrcPos The source code position of the wait.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsyncstatic int rtR0SemEventMultiLnxWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * Validate the input.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Is the event already signalled or do we have to wait?
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
824ae3158a8b8f8233fec3f5a12c81f139933698vboxsync if (fOrgStateAndGen & RTSEMEVENTMULTILNX_STATE_MASK)
824ae3158a8b8f8233fec3f5a12c81f139933698vboxsync * We have to wait.
5704a317c3b6bdf4b59f6a6ebe45d443296b1995vboxsync rc = rtR0SemLnxWaitInit(&Wait, fFlags, uTimeout, &pThis->Head);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /* The destruction test. */
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
a0644dbbd30adb9bd2937110d6f016e56c4cc52bvboxsync /* Check the exit conditions. */
a0644dbbd30adb9bd2937110d6f016e56c4cc52bvboxsync if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
229a63857c5fd2e441a62206eacce4156d0b2a26vboxsync else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /* Do the wait and then recheck the conditions. */
3933885bc0c2c93436d858a14564c6179ec72872vboxsyncRTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync return rtR0SemEventMultiLnxWait(hEventMultiSem, fFlags, uTimeout, NULL);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
824ae3158a8b8f8233fec3f5a12c81f139933698vboxsync return rtR0SemEventMultiLnxWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsyncRTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();