spinlock-generic.cpp revision c97989161fbe75bc14cea477a5443bbf474dd3ad
a4544a5a0e622ef69e38641f87ab1b5685e05911Phill Cunnington/* $Id$ */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/** @file
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * innotek Portable Runtime - Spinlock, generic implementation.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/*
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Copyright (C) 2006-2007 innotek GmbH
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * This file is part of VirtualBox Open Source Edition (OSE), as
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * available from http://www.virtualbox.org. This file is free software;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * you can redistribute it and/or modify it under the terms of the GNU
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * General Public License as published by the Free Software Foundation,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * distribution. VirtualBox OSE is distributed in the hope that it will
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * be useful, but WITHOUT ANY WARRANTY of any kind.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * If you received this file as part of a commercial VirtualBox
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * distribution, then only the terms of your commercial VirtualBox
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * license agreement apply instead of the previous paragraph.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/*******************************************************************************
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster* Defined Constants And Macros *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster*******************************************************************************/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/** @def RT_CFG_SPINLOCK_GENERIC_DO_SLEEP
a4544a5a0e622ef69e38641f87ab1b5685e05911Phill Cunnington * Force cpu yields after spinning the number of times indicated by the define.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * If 0 we will spin forever. */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#define RT_CFG_SPINLOCK_GENERIC_DO_SLEEP 100000
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/*******************************************************************************
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster* Header Files *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster*******************************************************************************/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <iprt/spinlock.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <iprt/alloc.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <iprt/asm.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <iprt/err.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <iprt/assert.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#if RT_CFG_SPINLOCK_GENERIC_DO_SLEEP
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster# include <iprt/thread.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#endif
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "internal/magics.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/*******************************************************************************
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster* Structures and Typedefs *
80ca0b9f5ad61b2335af25d4dcf25a04ebfcbc91Peter Major*******************************************************************************/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Generic spinlock structure.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fostertypedef struct RTSPINLOCKINTERNAL
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** Spinlock magic value (RTSPINLOCK_MAGIC). */
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott uint32_t u32Magic;
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott /** The spinlock. */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster uint32_t volatile fLocked;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster} RTSPINLOCKINTERNAL, *PRTSPINLOCKINTERNAL;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan FosterRTDECL(int) RTSpinlockCreate(PRTSPINLOCK pSpinlock)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /*
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Allocate.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster PRTSPINLOCKINTERNAL pSpinlockInt;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster pSpinlockInt = (PRTSPINLOCKINTERNAL)RTMemAlloc(sizeof(*pSpinlockInt));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (!pSpinlockInt)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return VERR_NO_MEMORY;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /*
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Initialize and return.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster pSpinlockInt->u32Magic = RTSPINLOCK_MAGIC;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ASMAtomicXchgU32(&pSpinlockInt->fLocked, 0);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *pSpinlock = pSpinlockInt;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return VINF_SUCCESS;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan FosterRTDECL(int) RTSpinlockDestroy(RTSPINLOCK Spinlock)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /*
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Validate input.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster PRTSPINLOCKINTERNAL pSpinlockInt = (PRTSPINLOCKINTERNAL)Spinlock;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (!pSpinlockInt)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return VERR_INVALID_PARAMETER;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (pSpinlockInt->u32Magic != RTSPINLOCK_MAGIC)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster AssertMsgFailed(("Invalid spinlock %p magic=%#x\n", pSpinlockInt, pSpinlockInt->u32Magic));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return VERR_INVALID_PARAMETER;
8d3140b524c0e28c0a49dc7c7d481123ef3cfe11Chris Lee }
8d3140b524c0e28c0a49dc7c7d481123ef3cfe11Chris Lee
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ASMAtomicIncU32(&pSpinlockInt->u32Magic);
8d3140b524c0e28c0a49dc7c7d481123ef3cfe11Chris Lee RTMemFree(pSpinlockInt);
8d3140b524c0e28c0a49dc7c7d481123ef3cfe11Chris Lee return VINF_SUCCESS;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8d3140b524c0e28c0a49dc7c7d481123ef3cfe11Chris Lee
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan FosterRTDECL(void) RTSpinlockAcquireNoInts(RTSPINLOCK Spinlock, PRTSPINLOCKTMP pTmp)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster PRTSPINLOCKINTERNAL pSpinlockInt = (PRTSPINLOCKINTERNAL)Spinlock;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster AssertMsg(pSpinlockInt && pSpinlockInt->u32Magic == RTSPINLOCK_MAGIC,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ("pSpinlockInt=%p u32Magic=%08x\n", pSpinlockInt, pSpinlockInt ? (int)pSpinlockInt->u32Magic : 0));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster pTmp->uFlags = ASMGetFlags();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#if RT_CFG_SPINLOCK_GENERIC_DO_SLEEP
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster for (;;)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ASMIntDisable();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster for (int c = RT_CFG_SPINLOCK_GENERIC_DO_SLEEP; c > 0; c--)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (ASMAtomicCmpXchgU32(&pSpinlockInt->fLocked, 1, 0))
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster RTThreadYield();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#else
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott ASMIntDisable();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster while (!ASMAtomicCmpXchgU32(&pSpinlockInt->fLocked, 1, 0))
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /*nothing */;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#endif
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan FosterRTDECL(void) RTSpinlockReleaseNoInts(RTSPINLOCK Spinlock, PRTSPINLOCKTMP pTmp)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster PRTSPINLOCKINTERNAL pSpinlockInt = (PRTSPINLOCKINTERNAL)Spinlock;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster AssertMsg(pSpinlockInt && pSpinlockInt->u32Magic == RTSPINLOCK_MAGIC,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ("pSpinlockInt=%p u32Magic=%08x\n", pSpinlockInt, pSpinlockInt ? (int)pSpinlockInt->u32Magic : 0));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster NOREF(pSpinlockInt);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (!ASMAtomicCmpXchgU32(&pSpinlockInt->fLocked, 0, 1))
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster AssertMsgFailed(("Spinlock %p was not locked!\n", pSpinlockInt));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ASMSetFlags(pTmp->uFlags);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan FosterRTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock, PRTSPINLOCKTMP pTmp)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster PRTSPINLOCKINTERNAL pSpinlockInt = (PRTSPINLOCKINTERNAL)Spinlock;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster AssertMsg(pSpinlockInt && pSpinlockInt->u32Magic == RTSPINLOCK_MAGIC,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ("pSpinlockInt=%p u32Magic=%08x\n", pSpinlockInt, pSpinlockInt ? (int)pSpinlockInt->u32Magic : 0));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster NOREF(pTmp);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#if RT_CFG_SPINLOCK_GENERIC_DO_SLEEP
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster for (;;)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster for (int c = RT_CFG_SPINLOCK_GENERIC_DO_SLEEP; c > 0; c--)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (ASMAtomicCmpXchgU32(&pSpinlockInt->fLocked, 1, 0))
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster RTThreadYield();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#else
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster while (!ASMAtomicCmpXchgU32(&pSpinlockInt->fLocked, 1, 0))
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /*nothing */;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#endif
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan FosterRTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock, PRTSPINLOCKTMP pTmp)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster PRTSPINLOCKINTERNAL pSpinlockInt = (PRTSPINLOCKINTERNAL)Spinlock;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster AssertMsg(pSpinlockInt && pSpinlockInt->u32Magic == RTSPINLOCK_MAGIC,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ("pSpinlockInt=%p u32Magic=%08x\n", pSpinlockInt, pSpinlockInt ? (int)pSpinlockInt->u32Magic : 0));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster NOREF(pTmp);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (!ASMAtomicCmpXchgU32(&pSpinlockInt->fLocked, 0, 1))
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster AssertMsgFailed(("Spinlock %p was not locked!\n", pSpinlockInt));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster