semspinmutex-r0drv-generic.c revision 30367f31e436dd2a5f7ee6c4a3923ddb576b84c6
/* $Id$ */
/** @file
* IPRT - Spinning Mutex Semaphores, Ring-0 Driver, Generic.
*/
/*
* Copyright (C) 2009 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#ifdef RT_OS_WINDOWS
# include "../nt/the-nt-kernel.h"
#endif
#include <iprt/semaphore.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Saved state information.
*/
typedef struct RTSEMSPINMUTEXSTATE
{
/** Saved flags register. */
/** Preemption state. */
/** Whether to spin or sleep. */
bool fSpin;
/** Whether the flags have been saved. */
bool fValidFlags;
/**
* Spinning mutex semaphore.
*/
typedef struct RTSEMSPINMUTEXINTERNAL
{
/** Magic value (RTSEMSPINMUTEX_MAGIC)
* RTCRITSECT_MAGIC is the value of an initialized & operational section. */
/** Flags. This is a combination of RTSEMSPINMUTEX_FLAGS_XXX and
* RTSEMSPINMUTEX_INT_FLAGS_XXX. */
/** The owner thread.
* This is NIL if the semaphore is not owned by anyone. */
RTNATIVETHREAD volatile hOwner;
/** Number of threads that are fighting for the lock. */
/** The semaphore to block on. */
/** Saved state information of the owner.
* This will be restored by RTSemSpinRelease. */
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
//#define RTSEMSPINMUTEX_INT_FLAGS_MUST
/** Validates the handle, returning if invalid. */
#define RTSEMSPINMUTEX_VALIDATE_RETURN(pThis) \
do \
{ \
if (u32Magic != RTSEMSPINMUTEX_MAGIC) \
{ \
} \
} while (0)
{
int rc;
/*
* Allocate and initialize the structure.
*/
if (!pThis)
return VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
return rc;
}
/**
* Helper for RTSemSpinMutexTryRequest and RTSemSpinMutexRequest.
*
* This will check the current context and see if it's usui
*
* @returns VINF_SUCCESS or VERR_SEM_BAD_CONTEXT.
* @param pState Output structure.
*/
{
int rc = VINF_SUCCESS;
/** @todo Later #1: When entering in interrupt context and we're not able to
* wake up threads from it, we could try switch the lock into pure
* spinlock mode. This would require that there are no other threads
* currently waiting on it and that the RTSEMSPINMUTEX_FLAGS_IRQ_SAFE
* flag is set.
*
* Later #2: Similarly, it is possible to turn on the
* RTSEMSPINMUTEX_FLAGS_IRQ_SAFE at run time if we manage to grab the
* semaphore ownership at interrupt time. We might want to try delay the
* RTSEMSPINMUTEX_FLAGS_IRQ_SAFE even, since we're fine if we get it...
*/
#ifdef RT_OS_WINDOWS
/*
* NT: IRQL <= DISPATCH_LEVEL for waking up threads; IRQL < DISPATCH_LEVEL for sleeping.
*/
return VERR_SEM_BAD_CONTEXT;
else
{
}
/*
* OSes on which RTSemEventSignal can be called from any context.
*/
{
}
#else /* PORTME: Check for context where we cannot wake up threads. */
/*
* Default: ASSUME thread can be woken up from all context except interrupt.
* ASSUME that we can go to sleep if preemption is enabled.
*/
return VERR_SEM_BAD_CONTEXT;
#endif
/*
* Disable interrupts if necessary.
*/
if (pState->fValidFlags)
else
pState->fSavedFlags = 0;
return rc;
}
/**
* Helper for RTSemSpinMutexTryRequest, RTSemSpinMutexRequest and
* RTSemSpinMutexRelease.
*
* @param pState
*/
{
/*
* Restore the interrupt flag.
*/
if (pState->fValidFlags)
#ifdef RT_OS_WINDOWS
/*
* NT: Lower the IRQL if we raised it.
*/
#else
/*
* Default: Restore preemption.
*/
#endif
}
{
bool fRc;
int rc;
/*
* Check context, disable preemption and save flags if necessary.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Try take the ownership.
*/
if (!fRc)
{
/* Busy, too bad. Check for attempts at nested access. */
rc = VERR_SEM_BUSY;
{
AssertMsgFailed(("%p attempt at nested access\n"));
}
return rc;
}
/*
* We're the semaphore owner.
*/
return VINF_SUCCESS;
}
{
bool fRc;
int rc;
/*
* Check context, disable preemption and save flags if necessary.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Try take the ownership.
*/
if (!fRc)
{
/*
* It's busy. Check if it's an attempt at nested access.
*/
{
AssertMsgFailed(("%p attempt at nested access\n"));
return VERR_SEM_NESTED;
}
/*
* Return if we're in interrupt context and the semaphore isn't
* configure to be interrupt safe.
*/
if (rc == VINF_SEM_BAD_CONTEXT)
{
return VERR_SEM_BAD_CONTEXT;
}
/*
* Ok, we have to wait.
*/
{
{
if (fRc)
break;
ASMNopPause();
{
return VERR_SEM_DESTROYED;
}
/*
* may preempting us, and it will certainly stop the hammering
* of hOwner for a little while.
*/
{
}
}
}
else
{
{
if (fRc)
break;
ASMNopPause();
{
return VERR_SEM_DESTROYED;
}
{
if (RT_SUCCESS(rc))
else if (rc == VERR_INTERRUPTED)
else
{
return rc;
}
}
}
}
}
/*
* We're the semaphore owner.
*/
return VINF_SUCCESS;
}
{
bool fRc;
/*
* Get the saved state and try release the semaphore.
*/
if (cLockers > 0)
{
}
return VINF_SUCCESS;
}
{
int rc;
if (hSpinMtx == NIL_RTSEMSPINMUTEX)
return VINF_SUCCESS;
/* No destruction races allowed! */
/*
* Invalidate the structure, free the mutex and free the structure.
*/
return rc;
}