semevent-linux.cpp revision 660fd430a3a8cfa16505d04c7c577acf89d45a40
e6d40133bc9f858308654afb1262b8b483ec5922Till Mossakowski * IPRT - Event Semaphore, Linux (2.6.x+).
b4fbc96e05117839ca409f5f20f97b3ac872d1edTill Mossakowski * Copyright (C) 2006-2007 Sun Microsystems, Inc.
aefb25a4f42b9078ea2b04fe2b599da4ca20cd34Christian Maeder * This file is part of VirtualBox Open Source Edition (OSE), as
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder * available from http://www.virtualbox.org. This file is free software;
add1aac0ed564b88495edb5491efd8c511607ea9Christian Maeder * you can redistribute it and/or modify it under the terms of the GNU
aefb25a4f42b9078ea2b04fe2b599da4ca20cd34Christian Maeder * General Public License (GPL) as published by the Free Software
aefb25a4f42b9078ea2b04fe2b599da4ca20cd34Christian Maeder * Foundation, in version 2 as it comes in the "COPYING" file of the
aefb25a4f42b9078ea2b04fe2b599da4ca20cd34Christian Maeder * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
aefb25a4f42b9078ea2b04fe2b599da4ca20cd34Christian Maeder * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
add1aac0ed564b88495edb5491efd8c511607ea9Christian Maeder * The contents of this file may alternatively be used under the terms
5a635ded758223aace5fd93489167f03cc336502Christian Maeder * of the Common Development and Distribution License Version 1.0
5a635ded758223aace5fd93489167f03cc336502Christian Maeder * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder * VirtualBox OSE distribution, in which case the provisions of the
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder * CDDL are applicable instead of those of the GPL.
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder * You may elect to license modified versions of this file under the
6ab1767d594a99e063bb698c123823411c05700eChristian Maeder * terms and conditions of either the GPL or the CDDL or both.
add1aac0ed564b88495edb5491efd8c511607ea9Christian Maeder * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0cb5f9c8582ad87ceef1c16b5d92347ae0878019Christian Maeder * Clara, CA 95054 USA or visit http://www.sun.com if you need
add1aac0ed564b88495edb5491efd8c511607ea9Christian Maeder * additional information or have any questions.
0cb5f9c8582ad87ceef1c16b5d92347ae0878019Christian Maeder/*******************************************************************************
0cb5f9c8582ad87ceef1c16b5d92347ae0878019Christian Maeder* Header Files *
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder*******************************************************************************/
efcb75d747dcdecc53bc5a584b6b4d98d1ae2755Christian Maeder#if 0 /* With 2.6.17 futex.h has become C++ unfriendly. */
42c01284bba8d7c8d995c8dfb96ace57d28ed1bcTill Mossakowski/*******************************************************************************
42c01284bba8d7c8d995c8dfb96ace57d28ed1bcTill Mossakowski* Structures and Typedefs *
42c01284bba8d7c8d995c8dfb96ace57d28ed1bcTill Mossakowski*******************************************************************************/
42c01284bba8d7c8d995c8dfb96ace57d28ed1bcTill Mossakowski * Linux (single wakup) event semaphore.
42c01284bba8d7c8d995c8dfb96ace57d28ed1bcTill Mossakowski /** Magic value. */
42c01284bba8d7c8d995c8dfb96ace57d28ed1bcTill Mossakowski /** The futex state variable.
42c01284bba8d7c8d995c8dfb96ace57d28ed1bcTill Mossakowski * <0 means signaled.
b645cf3dc1e449038ed291bbd11fcc6e02b2fc7fChristian Maeder * 0 means not signaled, no waiters.
efcb75d747dcdecc53bc5a584b6b4d98d1ae2755Christian Maeder * >0 means not signaled, and the value gives the number of waiters.
0cb5f9c8582ad87ceef1c16b5d92347ae0878019Christian Maeder * Wrapper for the futex syscall.
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maederstatic long sys_futex(int32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
5516c28f6575b3550029d1d82c6a14f8402ac3a2Christian Maeder long rc = syscall(__NR_futex, uaddr, op, val, utime, uaddr2, val3);
42c01284bba8d7c8d995c8dfb96ace57d28ed1bcTill MossakowskiRTDECL(int) RTSemEventCreate(PRTSEMEVENT pEventSem)
781d04c5e02635caed8b98f0adcf559f9426a39cTill Mossakowski * Allocate semaphore handle.
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder struct RTSEMEVENTINTERNAL *pThis = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTINTERNAL));
6ab1767d594a99e063bb698c123823411c05700eChristian MaederRTDECL(int) RTSemEventDestroy(RTSEMEVENT EventSem)
6ab1767d594a99e063bb698c123823411c05700eChristian Maeder * Validate input.
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder if (EventSem == NIL_RTSEMEVENT) /* don't bitch */
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder struct RTSEMEVENTINTERNAL *pThis = EventSem;
b645cf3dc1e449038ed291bbd11fcc6e02b2fc7fChristian Maeder AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
42c01284bba8d7c8d995c8dfb96ace57d28ed1bcTill Mossakowski AssertReturn(pThis->iMagic == RTSEMEVENT_MAGIC, VERR_INVALID_HANDLE);
42c01284bba8d7c8d995c8dfb96ace57d28ed1bcTill Mossakowski * Invalidate the semaphore and wake up anyone waiting on it.
b645cf3dc1e449038ed291bbd11fcc6e02b2fc7fChristian Maeder ASMAtomicXchgSize(&pThis->iMagic, RTSEMEVENT_MAGIC + 1);
aefb25a4f42b9078ea2b04fe2b599da4ca20cd34Christian Maeder if (ASMAtomicXchgS32(&pThis->cWaiters, INT32_MIN / 2) > 0)
b645cf3dc1e449038ed291bbd11fcc6e02b2fc7fChristian Maeder sys_futex(&pThis->cWaiters, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
5a635ded758223aace5fd93489167f03cc336502Christian Maeder * Free the semaphore memory and be gone.
1df7e6a9e5273f3eeb770d9f2fbbee40fb1ba51dChristian MaederRTDECL(int) RTSemEventSignal(RTSEMEVENT EventSem)
4561227a776bdf0ab679b19fb92f1eaaed8786f7Christian Maeder * Validate input.
4561227a776bdf0ab679b19fb92f1eaaed8786f7Christian Maeder struct RTSEMEVENTINTERNAL *pThis = EventSem;
277f12a72ee6876b9c48f01ef34d7cde65a423c8Christian Maeder AssertReturn(VALID_PTR(pThis) && pThis->iMagic == RTSEMEVENT_MAGIC,
4561227a776bdf0ab679b19fb92f1eaaed8786f7Christian Maeder * Try signal it.
4561227a776bdf0ab679b19fb92f1eaaed8786f7Christian Maeder for (unsigned i = 0;; i++)
4561227a776bdf0ab679b19fb92f1eaaed8786f7Christian Maeder if (ASMAtomicCmpXchgS32(&pThis->cWaiters, -1, 0))
4561227a776bdf0ab679b19fb92f1eaaed8786f7Christian Maeder break; /* nobody is waiting */
4561227a776bdf0ab679b19fb92f1eaaed8786f7Christian Maeder else if (iCur < 0)
add1aac0ed564b88495edb5491efd8c511607ea9Christian Maeder break; /* already signaled */
add1aac0ed564b88495edb5491efd8c511607ea9Christian Maeder /* somebody is waiting, try wake up one of them. */
aefb25a4f42b9078ea2b04fe2b599da4ca20cd34Christian Maeder long cWoken = sys_futex(&pThis->cWaiters, FUTEX_WAKE, 1, NULL, NULL, 0);
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder * This path is taken in two situations:
4561227a776bdf0ab679b19fb92f1eaaed8786f7Christian Maeder * 1) A waiting thread is returning from the sys_futex call with a
4561227a776bdf0ab679b19fb92f1eaaed8786f7Christian Maeder * non-zero return value.
4561227a776bdf0ab679b19fb92f1eaaed8786f7Christian Maeder * 2) There are two threads signaling the event at the
5a635ded758223aace5fd93489167f03cc336502Christian Maeder * same time and only one thread waiting.
eca18e4fda019d7e57e1fe1cc16ed21592c9e11bChristian Maeder * At this point we know that nobody is activly waiting on the event but
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder * at the same time, we are racing someone updating the state. The current
5a635ded758223aace5fd93489167f03cc336502Christian Maeder * strategy is to spin till the thread racing us is done, this is kind of
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder * brain dead and need fixing of course.
4561227a776bdf0ab679b19fb92f1eaaed8786f7Christian Maeder else if (!(i % 4))
4561227a776bdf0ab679b19fb92f1eaaed8786f7Christian Maeder AssertReleaseMsg(i < 4096, ("iCur=%#x pThis=%p\n", iCur, pThis));
277f12a72ee6876b9c48f01ef34d7cde65a423c8Christian Maederstatic int rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fAutoResume)
aefb25a4f42b9078ea2b04fe2b599da4ca20cd34Christian Maeder * Validate input.
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder struct RTSEMEVENTINTERNAL *pThis = EventSem;
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder AssertReturn(VALID_PTR(pThis) && pThis->iMagic == RTSEMEVENT_MAGIC,
5a635ded758223aace5fd93489167f03cc336502Christian Maeder * Quickly check whether it's signaled.
5a635ded758223aace5fd93489167f03cc336502Christian Maeder if (ASMAtomicCmpXchgS32(&pThis->cWaiters, 0, -1))
0cb5f9c8582ad87ceef1c16b5d92347ae0878019Christian Maeder * Convert timeout value.
add1aac0ed564b88495edb5491efd8c511607ea9Christian Maeder * The wait loop.
dd776ca56af505d39e16e9eecf69948beddfb279Christian Maeder for (unsigned i = 0;; i++)
add1aac0ed564b88495edb5491efd8c511607ea9Christian Maeder * Announce that we're among the waiters.
0cb5f9c8582ad87ceef1c16b5d92347ae0878019Christian Maeder int32_t iNew = ASMAtomicIncS32(&pThis->cWaiters);
27273a2967ca2f12b5e6ff0ec5e3f66e2ea8fcb2Christian Maeder * Go to sleep.
0cb5f9c8582ad87ceef1c16b5d92347ae0878019Christian Maeder long rc = sys_futex(&pThis->cWaiters, FUTEX_WAIT, iNew, pTimeout, NULL, 0);
27273a2967ca2f12b5e6ff0ec5e3f66e2ea8fcb2Christian Maeder if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENT_MAGIC))
5a635ded758223aace5fd93489167f03cc336502Christian Maeder /* Did somebody wake us up from RTSemEventSignal()? */
42c01284bba8d7c8d995c8dfb96ace57d28ed1bcTill Mossakowski /* No, then the kernel woke us up or we failed going to sleep. Adjust the accounting. */
42c01284bba8d7c8d995c8dfb96ace57d28ed1bcTill Mossakowski * Act on the wakup code.
0cb5f9c8582ad87ceef1c16b5d92347ae0878019Christian Maeder /* retry with new value. */;
0cb5f9c8582ad87ceef1c16b5d92347ae0878019Christian Maeder /* this shouldn't happen! */
25d484b7e8a319494046201857a80ed4dd2cea86Christian Maeder AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
25d484b7e8a319494046201857a80ed4dd2cea86Christian Maeder /* this can't happen. */
add1aac0ed564b88495edb5491efd8c511607ea9Christian Maeder if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENT_MAGIC))
add1aac0ed564b88495edb5491efd8c511607ea9Christian Maeder AssertReleaseMsgFailed(("iNew=%d\n", iNew));
9929f81562adecc8aafaefb14a0159afcf4a3351Christian MaederRTDECL(int) RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies)
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder int rc = rtSemEventWait(EventSem, cMillies, true);
9929f81562adecc8aafaefb14a0159afcf4a3351Christian Maeder Assert(rc != VERR_TIMEOUT || cMillies != RT_INDEFINITE_WAIT);
1f726c6d4aea88acb19f73a1471257dbde301156Till MossakowskiRTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies)