semeventmulti-linux.cpp revision ab93606043a9881487aa83be04191d2f4ea24071
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * IPRT - Multiple Release Event Semaphore, Linux (2.6.x+).
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * available from http://www.virtualbox.org. This file is free software;
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * General Public License (GPL) as published by the Free Software
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * The contents of this file may alternatively be used under the terms
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * of the Common Development and Distribution License Version 1.0
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * VirtualBox OSE distribution, in which case the provisions of the
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * CDDL are applicable instead of those of the GPL.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * You may elect to license modified versions of this file under the
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * terms and conditions of either the GPL or the CDDL or both.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * additional information or have any questions.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync#if __GLIBC_PREREQ(2,6) && !defined(IPRT_WITH_FUTEX_BASED_SEMS)
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * glibc 2.6 fixed a serious bug in the mutex implementation. We wrote this
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * linux specific event semaphores code in order to work around the bug. As it
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * turns out, this code seems to have an unresolved issue (#2599), so we'll
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * fall back on the pthread based implementation if glibc is known to contain
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * the bug fix.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * The external refernce to epoll_pwait is a hack which prevents that we link
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * against glibc < 2.6.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsyncasm volatile (".global epoll_pwait");
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync#else /* glibc < 2.6 */
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync/*******************************************************************************
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync* Header Files *
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync*******************************************************************************/
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync#if 0 /* With 2.6.17 futex.h has become C++ unfriendly. */
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync/*******************************************************************************
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync* Structures and Typedefs *
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync*******************************************************************************/
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Linux multiple wakup event semaphore.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync /** Magic value. */
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync /** The futex state variable.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * -1 means signaled.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * 0 means not signaled, no waiters.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * 1 means not signaled and that someone is waiting.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync /** Signallers. */
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync /** Indicates that lock validation should be performed. */
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Wrapper for the futex syscall.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsyncstatic long sys_futex(int32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync long rc = syscall(__NR_futex, uaddr, op, val, utime, uaddr2, val3);
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsyncRTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsyncRTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync const char *pszNameFmt, ...)
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Allocate semaphore handle.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync struct RTSEMEVENTMULTIINTERNAL *pThis = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTMULTIINTERNAL));
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL),
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsyncRTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Validate input.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
ac91d9d0626a52f79cf554c81b1fdf5f262092bbvboxsync * Invalidate the semaphore and wake up anyone waiting on it.
ac91d9d0626a52f79cf554c81b1fdf5f262092bbvboxsync ASMAtomicWriteSize(&pThis->u32Magic, RTSEMEVENTMULTI_MAGIC + 1);
ac91d9d0626a52f79cf554c81b1fdf5f262092bbvboxsync sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
ac91d9d0626a52f79cf554c81b1fdf5f262092bbvboxsync * Free the semaphore memory and be gone.
ac91d9d0626a52f79cf554c81b1fdf5f262092bbvboxsync RTLockValidatorRecSharedDelete(&pThis->Signallers);
ac91d9d0626a52f79cf554c81b1fdf5f262092bbvboxsyncRTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
ac91d9d0626a52f79cf554c81b1fdf5f262092bbvboxsync * Validate input.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync AssertReturn(VALID_PTR(pThis) && pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Signal it.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync int32_t iOld = ASMAtomicXchgS32(&pThis->iState, -1);
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync /* wake up sleeping threads. */
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync long cWoken = sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync AssertMsg(cWoken >= 0, ("%ld\n", cWoken)); NOREF(cWoken);
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsyncRTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Validate input.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync AssertReturn(VALID_PTR(pThis) && pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Reset it.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsyncstatic int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, unsigned cMillies, bool fAutoResume)
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Validate input.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync AssertReturn(VALID_PTR(pThis) && pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
c6383709c15c809f8cfb09b5cfe670760f06e2b9vboxsync * Quickly check whether it's signaled.
c6383709c15c809f8cfb09b5cfe670760f06e2b9vboxsync * Convert the timeout value.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync /* If the timeout is zero, then we're done. */
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsync ts.tv_nsec = (cMillies % 1000) * UINT32_C(1000000);
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsync u64End = RTTimeSystemNanoTS() + cMillies * UINT64_C(1000000);
270236340676d2385b27ea992e07fcb643bb78b6vboxsync * The wait loop.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync for (unsigned i = 0;; i++)
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * Start waiting. We only account for there being or having been
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync * threads waiting on the semaphore to keep things simple.
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync /* adjust the relative timeout */
51ef69064b4ea4d571ed129ab883b0c08967c901vboxsync ts.tv_sec = (uint64_t)i64Diff / UINT32_C(1000000000);
51ef69064b4ea4d571ed129ab883b0c08967c901vboxsync ts.tv_nsec = (uint64_t)i64Diff % UINT32_C(1000000000);
51ef69064b4ea4d571ed129ab883b0c08967c901vboxsync int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsync RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsync long rc = sys_futex(&pThis->iState, FUTEX_WAIT, 1, pTimeout, NULL, 0);
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsync RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsync if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsync * Act on the wakup code.
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsync/** @todo something is broken here. shows up every now and again in the ata
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsync * code. Should try to run the timeout against RTTimeMilliTS to
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsync * check that it's doing the right thing... */
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsync /* retry, the value changed. */;
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsync /* this shouldn't happen! */
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsyncRTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, unsigned cMillies)
0ab80a5f847b8c908ee2d9db5cc37da8e8dd5697vboxsync int rc = rtSemEventMultiWait(hEventMultiSem, cMillies, true);
917f4ee9f101c9786cf09ea0fe7923a7f6dfe40cvboxsyncRTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, unsigned cMillies)
270236340676d2385b27ea992e07fcb643bb78b6vboxsync return rtSemEventMultiWait(hEventMultiSem, cMillies, false);
270236340676d2385b27ea992e07fcb643bb78b6vboxsyncRTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
270236340676d2385b27ea992e07fcb643bb78b6vboxsync struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
e2ba4c7fd718dba1d5b73cd9e40486df3ce06e77vboxsync AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
6cd3c708987d8c77397659c5a80ef0eea7ef1fd1vboxsync ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
6cd3c708987d8c77397659c5a80ef0eea7ef1fd1vboxsync RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
f372af8e6ee2a011213b11cc69f4a29530ff7ce5vboxsyncRTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
f372af8e6ee2a011213b11cc69f4a29530ff7ce5vboxsync struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
c6383709c15c809f8cfb09b5cfe670760f06e2b9vboxsync AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
f372af8e6ee2a011213b11cc69f4a29530ff7ce5vboxsync ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
f372af8e6ee2a011213b11cc69f4a29530ff7ce5vboxsync RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
f372af8e6ee2a011213b11cc69f4a29530ff7ce5vboxsyncRTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
e2ba4c7fd718dba1d5b73cd9e40486df3ce06e77vboxsync struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
e2ba4c7fd718dba1d5b73cd9e40486df3ce06e77vboxsync AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
e2ba4c7fd718dba1d5b73cd9e40486df3ce06e77vboxsync RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
e2ba4c7fd718dba1d5b73cd9e40486df3ce06e77vboxsync#endif /* glibc < 2.6 || IPRT_WITH_FUTEX_BASED_SEMS */