semmutex-linux.cpp revision 89dfdbb56cf9dddad3c7685b41bda1e4e4c1d6f9
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * innotek Portable Runtime - Mutex Semaphore, Linux (2.6.x+).
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * Copyright (C) 2006-2007 innotek GmbH
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * available from http://www.virtualbox.org. This file is free software;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * you can redistribute it and/or modify it under the terms of the GNU
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * General Public License (GPL) as published by the Free Software
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * The contents of this file may alternatively be used under the terms
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * of the Common Development and Distribution License Version 1.0
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * VirtualBox OSE distribution, in which case the provisions of the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * CDDL are applicable instead of those of the GPL.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * You may elect to license modified versions of this file under the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * terms and conditions of either the GPL or the CDDL or both.
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync/*******************************************************************************
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync* Header Files *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync*******************************************************************************/
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#if 0 /* With 2.6.17 futex.h has become C++ unfriendly. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/*******************************************************************************
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync* Structures and Typedefs *
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync*******************************************************************************/
d68336e34409fd767807d5ef641a305de4d9ee59vboxsync * Linux internal representation of a Mutex semaphore.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The futex state variable.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * 0 means unlocked.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * 1 means locked, no waiters.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * 2 means locked, one or more waiters.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Nesting count. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The owner of the mutex. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Magic value. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Wrapper for the futex syscall.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic long sys_futex(int32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync long rc = syscall(__NR_futex, uaddr, op, val, utime, uaddr2, val3);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Allocate semaphore handle.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync struct RTSEMMUTEXINTERNAL *pThis = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * Validate input.
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync ("MutexSem=%p iMagic=%#x\n", pThis, pThis->iMagic),
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * Invalidate the semaphore and wake up anyone waiting on it.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync ASMAtomicXchgSize(&pThis->iMagic, RTSEMMUTEX_MAGIC + 1);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Free the semaphore memory and be gone.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic int rtsemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies, bool fAutoResume)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Validate input.
b3109af8dcc2a3da7f424aa05a4e84a64bf1c43fvboxsync ("MutexSem=%p iMagic=%#x\n", pThis, pThis->iMagic),
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Check if nested request.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Convert timeout value.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Lock the mutex.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (RT_UNLIKELY(!ASMAtomicCmpXchgS32(&pThis->iState, 1, 0)))
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync int32_t iOld = ASMAtomicXchgS32(&pThis->iState, 2);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Was the lock released in the meantime? This is unlikely (but possible)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Go to sleep.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync long rc = sys_futex(&pThis->iState, FUTEX_WAIT, 2, pTimeout, NULL, 0);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (RT_UNLIKELY(pThis->iMagic != RTSEMMUTEX_MAGIC))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Act on the wakup code.
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync /* we'll leave the loop now unless another thread is faster */;
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync /* retry with new value. */;
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync /* this shouldn't happen! */
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync * When leaving this loop, iState is set to 2. This means that we gained the
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync * Lock and there are _possibly_ some waiters. We don't know exactly as another
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync * thread might entered this loop at nearly the same time. Therefore we will
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync * call futex_wakeup once too often (if _no_ other thread entered this loop).
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * The key problem is the simple futex_wait test for x != y (iState != 2) in
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * our case).
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync * Set the owner and nesting.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncRTDECL(int) RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
0780b79e94db3b60fb4a3057df7c64ba8b1cb75dvboxsync int rc = rtsemMutexRequest(MutexSem, cMillies, true);
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsyncRTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync return rtsemMutexRequest(MutexSem, cMillies, false);
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync * Validate input.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync ("MutexSem=%p iMagic=%#x\n", pThis, pThis->iMagic),
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Check if nested.
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync * If nested we'll just pop a nesting.
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync * Clear the state. (cNesting == 1)
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync * Release the mutex.
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /* somebody is waiting, try wake up one of them. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync (void)sys_futex(&pThis->iState, FUTEX_WAKE, 1, NULL, NULL, 0);