5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * IPRT - Mutex Semaphores, Ring-0 Driver, Linux.
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2011 Oracle Corporation
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync * available from http://www.virtualbox.org. This file is free software;
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * The contents of this file may alternatively be used under the terms
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * of the Common Development and Distribution License Version 1.0
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution, in which case the provisions of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * CDDL are applicable instead of those of the GPL.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * You may elect to license modified versions of this file under the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * terms and conditions of either the GPL or the CDDL or both.
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync/*******************************************************************************
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync* Header Files *
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync*******************************************************************************/
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync/*******************************************************************************
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync* Structures and Typedefs *
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync*******************************************************************************/
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The list entry. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The waiting task. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** Why did we wake up? */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** Wakeup to take the semaphore. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** Mutex is being destroyed. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** Some other reason. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Wrapper for the linux semaphore structure.
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync /** Magic value (RTSEMMUTEX_MAGIC). */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The number of recursions. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The list of waiting threads. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The current owner, NULL if none. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The number of references to this piece of memory. This is used to
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * prevent it from being kicked from underneath us while waiting. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The spinlock protecting the members and falling asleep. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Allocate.
9df048d43d767b5806f47a07c6914364760ead96vboxsync pThis = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Initialize.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Validate.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Kill it, kick waiters and release it.
9df048d43d767b5806f47a07c6914364760ead96vboxsync AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD, RTSEMMUTEX_MAGIC), VERR_INVALID_HANDLE);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTListForEach(&pThis->WaiterList, pCur, RTSEMMUTEXLNXWAITER, ListEntry)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Worker for rtSemMutexLinuxRequest that handles the case where we go to sleep.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * @returns VINF_SUCCESS, VERR_INTERRUPTED, VERR_TIMEOUT or VERR_SEM_DESTROYED.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Returns without owning the spinlock.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * @param pThis The mutex instance.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * @param cMillies The timeout.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * @param fInterruptible The wait type.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * @param fSavedIrq The saved IRQ flags.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncstatic int rtSemMutexLinuxRequestSleep(PRTSEMMUTEXINTERNAL pThis, RTMSINTERVAL cMillies,
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync long lTimeout = cMillies == RT_INDEFINITE_WAIT ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(cMillies);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Grab a reference to the mutex and add ourselves to the waiter list.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTListAppend(&pThis->WaiterList, &Waiter.ListEntry);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Do the waiting.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /* Check signal and timeout conditions. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /* Go to sleep. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync set_task_state(pSelf, fInterruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /* Did someone wake us up? */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (Waiter.enmReason == RTSEMMUTEXLNXWAITER_WAKEUP)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /* Is the mutex being destroyed? */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (RT_UNLIKELY( Waiter.enmReason == RTSEMMUTEXLNXWAITER_DESTROYED
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Unlink ourself from the waiter list, dereference the mutex and exit the
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * lock. We might have to free the mutex if it was the destroyed.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (RT_LIKELY(ASMAtomicDecU32(&pThis->cRefs) != 0))
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Internal worker.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncDECLINLINE(int) rtSemMutexLinuxRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, bool fInterruptible)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Validate.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Lock it and check if it's a recursion.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Not a recursion, maybe it's not owned by anyone then?
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Was it a polling call?
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync else if (cMillies == 0)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * No, so go to sleep.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return rtSemMutexLinuxRequestSleep(pThis, cMillies, fInterruptible, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return rtSemMutexLinuxRequest(hMutexSem, cMillies, false /*fInterruptible*/);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return rtSemMutexLinuxRequest(hMutexSem, cMillies, true /*fInterruptible*/);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return RTSemMutexRequestNoResume(hMutexSem, cMillies);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Validate.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Take the lock and release one recursion.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /* anyone to wake up? */
c80170800394cbf2746e3136b41886c2d11617aevboxsync PRTSEMMUTEXLNXWAITER pWaiter = RTListGetFirst(&pThis->WaiterList, RTSEMMUTEXLNXWAITER, ListEntry);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Validate.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), false);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Take the lock and release one recursion.