a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync/* $Id$ */
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync/** @file
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * IPRT - Mutex Semaphores, Ring-0 Driver, Linux.
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync */
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync/*
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2011 Oracle Corporation
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync *
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 *
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 *
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
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync/*******************************************************************************
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync* Header Files *
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync*******************************************************************************/
715e49c31b15c23c17a9ce3be42a75e7c48d4b78vboxsync#define RTSEMMUTEX_WITHOUT_REMAPPING
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync#include "the-linux-kernel.h"
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync#include "internal/iprt.h"
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync#include <iprt/semaphore.h>
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync#include <iprt/assert.h>
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync#include <iprt/asm.h>
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync#include <iprt/mem.h>
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync#include <iprt/err.h>
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync#include <iprt/list.h>
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync#include "internal/magics.h"
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync/*******************************************************************************
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync* Structures and Typedefs *
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync*******************************************************************************/
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsynctypedef struct RTSEMMUTEXLNXWAITER
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync{
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The list entry. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTLISTNODE ListEntry;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The waiting task. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync struct task_struct *pTask;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** Why did we wake up? */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync enum
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync {
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** Wakeup to take the semaphore. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTSEMMUTEXLNXWAITER_WAKEUP,
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** Mutex is being destroyed. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTSEMMUTEXLNXWAITER_DESTROYED,
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** Some other reason. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTSEMMUTEXLNXWAITER_OTHER
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync } volatile enmReason;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync} RTSEMMUTEXLNXWAITER, *PRTSEMMUTEXLNXWAITER;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync/**
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Wrapper for the linux semaphore structure.
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync */
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsynctypedef struct RTSEMMUTEXINTERNAL
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync{
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync /** Magic value (RTSEMMUTEX_MAGIC). */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync uint32_t u32Magic;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The number of recursions. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync uint32_t cRecursions;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The list of waiting threads. */
e961f5bfe1727c6816d3dad3805ebe21b6ba1c64vboxsync RTLISTANCHOR WaiterList;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The current owner, NULL if none. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync struct task_struct *pOwnerTask;
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 uint32_t volatile cRefs;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /** The spinlock protecting the members and falling asleep. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spinlock_t Spinlock;
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync} RTSEMMUTEXINTERNAL, *PRTSEMMUTEXINTERNAL;
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMtx)
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync{
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Allocate.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync */
9df048d43d767b5806f47a07c6914364760ead96vboxsync PRTSEMMUTEXINTERNAL pThis;
9df048d43d767b5806f47a07c6914364760ead96vboxsync pThis = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (!pThis)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return VERR_NO_MEMORY;
9df048d43d767b5806f47a07c6914364760ead96vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Initialize.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync pThis->u32Magic = RTSEMMUTEX_MAGIC;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync pThis->cRecursions = 0;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync pThis->pOwnerTask = NULL;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync pThis->cRefs = 1;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTListInit(&pThis->WaiterList);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_lock_init(&pThis->Spinlock);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync *phMtx = pThis;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return VINF_SUCCESS;
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTSemMutexCreate);
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMtx)
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync{
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync PRTSEMMUTEXINTERNAL pThis = hMtx;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync PRTSEMMUTEXLNXWAITER pCur;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync unsigned long fSavedIrq;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Validate.
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync */
9df048d43d767b5806f47a07c6914364760ead96vboxsync if (pThis == NIL_RTSEMMUTEX)
9df048d43d767b5806f47a07c6914364760ead96vboxsync return VINF_SUCCESS;
9df048d43d767b5806f47a07c6914364760ead96vboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Kill it, kick waiters and release it.
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync */
9df048d43d767b5806f47a07c6914364760ead96vboxsync AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD, RTSEMMUTEX_MAGIC), VERR_INVALID_HANDLE);
9df048d43d767b5806f47a07c6914364760ead96vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTListForEach(&pThis->WaiterList, pCur, RTSEMMUTEXLNXWAITER, ListEntry)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync {
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync pCur->enmReason = RTSEMMUTEXLNXWAITER_DESTROYED;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync wake_up_process(pCur->pTask);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync }
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (ASMAtomicDecU32(&pThis->cRefs) != 0)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync else
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync {
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTMemFree(pThis);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync }
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync return VINF_SUCCESS;
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTSemMutexDestroy);
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync/**
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Worker for rtSemMutexLinuxRequest that handles the case where we go to sleep.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync *
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.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncstatic int rtSemMutexLinuxRequestSleep(PRTSEMMUTEXINTERNAL pThis, RTMSINTERVAL cMillies,
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync bool fInterruptible, unsigned long fSavedIrq)
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync{
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync struct task_struct *pSelf = current;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync int rc = VERR_TIMEOUT;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync long lTimeout = cMillies == RT_INDEFINITE_WAIT ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(cMillies);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTSEMMUTEXLNXWAITER Waiter;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync IPRT_DEBUG_SEMS_STATE(pThis, 'm');
9df048d43d767b5806f47a07c6914364760ead96vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Grab a reference to the mutex and add ourselves to the waiter list.
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync ASMAtomicIncU32(&pThis->cRefs);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync Waiter.pTask = pSelf;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync Waiter.enmReason = RTSEMMUTEXLNXWAITER_OTHER;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTListAppend(&pThis->WaiterList, &Waiter.ListEntry);
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Do the waiting.
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync for (;;)
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync {
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /* Check signal and timeout conditions. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if ( fInterruptible
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync && signal_pending(pSelf))
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync {
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync rc = VERR_INTERRUPTED;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync break;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync }
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (!lTimeout)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync break;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /* Go to sleep. */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync set_task_state(pSelf, fInterruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irq(&pThis->Spinlock);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync lTimeout = schedule_timeout(lTimeout);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_lock_irq(&pThis->Spinlock);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync set_current_state(TASK_RUNNING);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /* Did someone wake us up? */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (Waiter.enmReason == RTSEMMUTEXLNXWAITER_WAKEUP)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync {
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync Assert(pThis->cRecursions == 0);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync pThis->cRecursions = 1;
f25b5aeeb1ce398bad5a8f4e8af0d72d40f24bcavboxsync pThis->pOwnerTask = pSelf;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync rc = VINF_SUCCESS;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync break;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync }
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /* Is the mutex being destroyed? */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (RT_UNLIKELY( Waiter.enmReason == RTSEMMUTEXLNXWAITER_DESTROYED
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync || pThis->u32Magic != RTSEMMUTEX_MAGIC))
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync {
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync rc = VERR_SEM_DESTROYED;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync break;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync }
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync }
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync /*
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.
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTListNodeRemove(&Waiter.ListEntry);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync IPRT_DEBUG_SEMS_STATE_RC(pThis, 'M', rc);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (RT_LIKELY(ASMAtomicDecU32(&pThis->cRefs) != 0))
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync else
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync {
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync Assert(RT_FAILURE_NP(rc));
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync RTMemFree(pThis);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync }
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return rc;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync}
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync/**
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Internal worker.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncDECLINLINE(int) rtSemMutexLinuxRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, bool fInterruptible)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync{
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync PRTSEMMUTEXINTERNAL pThis = hMutexSem;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync struct task_struct *pSelf = current;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync unsigned long fSavedIrq;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync int rc;
30c84c361575629a712f338b514d9db7a8c681f4vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Validate.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync Assert(pThis->cRefs >= 1);
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Lock it and check if it's a recursion.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (pThis->pOwnerTask == pSelf)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync {
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync pThis->cRecursions++;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync Assert(pThis->cRecursions > 1);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync Assert(pThis->cRecursions < 256);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync rc = VINF_SUCCESS;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync }
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Not a recursion, maybe it's not owned by anyone then?
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync */
c7bd911e441d0c986ae0ab41f2b1fb3e81cd6fc4vboxsync else if ( pThis->pOwnerTask == NULL
c7bd911e441d0c986ae0ab41f2b1fb3e81cd6fc4vboxsync && RTListIsEmpty(&pThis->WaiterList))
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync {
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync Assert(pThis->cRecursions == 0);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync pThis->cRecursions = 1;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync pThis->pOwnerTask = pSelf;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync rc = VINF_SUCCESS;
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync }
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Was it a polling call?
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync else if (cMillies == 0)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync rc = VERR_TIMEOUT;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * No, so go to sleep.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync else
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return rtSemMutexLinuxRequestSleep(pThis, cMillies, fInterruptible, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync IPRT_DEBUG_SEMS_STATE_RC(pThis, 'M', rc);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
9df048d43d767b5806f47a07c6914364760ead96vboxsync return rc;
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync}
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync{
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return rtSemMutexLinuxRequest(hMutexSem, cMillies, false /*fInterruptible*/);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync}
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRT_EXPORT_SYMBOL(RTSemMutexRequest);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync{
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return RTSemMutexRequest(hMutexSem, cMillies);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync}
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRT_EXPORT_SYMBOL(RTSemMutexRequestDebug);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync{
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return rtSemMutexLinuxRequest(hMutexSem, cMillies, true /*fInterruptible*/);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync}
01f0d2858d4377ecf19f5aac2531efe99fef9ffcvboxsyncRT_EXPORT_SYMBOL(RTSemMutexRequestNoResume);
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync{
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return RTSemMutexRequestNoResume(hMutexSem, cMillies);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync}
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRT_EXPORT_SYMBOL(RTSemMutexRequestNoResumeDebug);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMtx)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync{
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync PRTSEMMUTEXINTERNAL pThis = hMtx;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync struct task_struct *pSelf = current;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync unsigned long fSavedIrq;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync int rc;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Validate.
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync */
9df048d43d767b5806f47a07c6914364760ead96vboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync Assert(pThis->cRefs >= 1);
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Take the lock and release one recursion.
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (pThis->pOwnerTask == pSelf)
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync {
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync Assert(pThis->cRecursions > 0);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (--pThis->cRecursions == 0)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync {
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync pThis->pOwnerTask = NULL;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /* anyone to wake up? */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync if (!RTListIsEmpty(&pThis->WaiterList))
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync {
c80170800394cbf2746e3136b41886c2d11617aevboxsync PRTSEMMUTEXLNXWAITER pWaiter = RTListGetFirst(&pThis->WaiterList, RTSEMMUTEXLNXWAITER, ListEntry);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync pWaiter->enmReason = RTSEMMUTEXLNXWAITER_WAKEUP;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync wake_up_process(pWaiter->pTask);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync }
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync IPRT_DEBUG_SEMS_STATE(pThis, 'u');
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync }
01f0d2858d4377ecf19f5aac2531efe99fef9ffcvboxsync rc = VINF_SUCCESS;
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync }
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync else
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync rc = VERR_NOT_OWNER;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync AssertRC(rc);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return rc;
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTSemMutexRelease);
a8e0cb7ddfd05bcabf5e18959cf09e723f254663vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync{
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync PRTSEMMUTEXINTERNAL pThis = hMutexSem;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync unsigned long fSavedIrq;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync bool fOwned;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Validate.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync AssertPtrReturn(pThis, false);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), false);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync Assert(pThis->cRefs >= 1);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync /*
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync * Take the lock and release one recursion.
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync */
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync fOwned = pThis->pOwnerTask != NULL;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync return fOwned;
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync}
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsyncRT_EXPORT_SYMBOL(RTSemMutexIsOwned);
8b303c780daa18ac0d712e70b2a2041c3012ae87vboxsync