/* $Id$ */
/** @file
*/
/*
* Copyright (C) 2009-2013 Oracle Corporation
*
* 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.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define RTCRITSECTRW_WITHOUT_REMAPPING
#define RTASSERT_QUIET
#include <iprt/critsect.h>
#include <iprt/lockvalidator.h>
#include <iprt/semaphore.h>
{
}
{
int rc;
AssertReturn(!(fFlags & ~( RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_BOOTSTRAP_HACK
| RTCRITSECT_FLAGS_NOP )),
/*
* Initialize the structure, allocate the lock validator stuff and sems.
*/
pThis->fNeedReset = false;
pThis->cWriterReads = 0;
pThis->cWriteRecursions = 0;
#if HC_ARCH_BITS == 32
#endif
#ifdef RTCRITSECTRW_STRICT
if (!pszNameFmt)
{
fLVEnabled, "RTCritSectRw-%u", i);
if (RT_SUCCESS(rc))
}
else
{
if (RT_SUCCESS(rc))
{
}
}
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
#endif
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
}
}
#ifdef RTCRITSECTRW_STRICT
#endif
return rc;
}
{
#ifdef RTCRITSECTRW_STRICT
#else
return RTLOCKVAL_SUB_CLASS_INVALID;
#endif
}
{
/*
* Validate input.
*/
#ifdef RTCRITSECTRW_STRICT
if (!fTryOnly)
{
int rc9;
rc9 = RTLockValidatorRecExclCheckOrder(pThis->pValidatorWrite, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
else
rc9 = RTLockValidatorRecSharedCheckOrder(pThis->pValidatorRead, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
if (RT_FAILURE(rc9))
return rc9;
}
#endif
/*
* Get cracking...
*/
for (;;)
{
{
/* It flows in the right direction, try follow it before it changes. */
c++;
u64State |= c << RTCSRW_CNT_RD_SHIFT;
{
#ifdef RTCRITSECTRW_STRICT
#endif
break;
}
}
{
/* Wrong direction, but we're alone here and can simply try switch the direction. */
{
#ifdef RTCRITSECTRW_STRICT
#endif
break;
}
}
else
{
/* Is the writer perhaps doing a read recursion? */
if (hNativeSelf == hNativeWriter)
{
#ifdef RTCRITSECTRW_STRICT
int rc9 = RTLockValidatorRecExclRecursionMixed(pThis->pValidatorWrite, &pThis->pValidatorRead->Core, pSrcPos);
if (RT_FAILURE(rc9))
return rc9;
#endif
return VINF_SUCCESS; /* don't break! */
}
/* If we're only trying, return already. */
if (fTryOnly)
return VERR_SEM_BUSY;
/* Add ourselves to the queue and wait for the direction to change. */
c++;
cWait++;
{
{
int rc;
#ifdef RTCRITSECTRW_STRICT
RT_INDEFINITE_WAIT, RTTHREADSTATE_RW_READ, false);
if (RT_SUCCESS(rc))
#else
#endif
{
return VERR_SEM_DESTROYED;
}
if (RT_FAILURE(rc))
{
/* Decrement the counts and return the error. */
for (;;)
{
c--;
cWait--;
break;
}
return rc;
}
break;
}
/* Decrement the wait count and maybe reset the semaphore (if we're last). */
for (;;)
{
cWait--;
{
if (cWait == 0)
{
{
}
}
break;
}
}
#ifdef RTCRITSECTRW_STRICT
#endif
break;
}
}
return VERR_SEM_DESTROYED;
ASMNopPause();
}
/* got it! */
Assert((ASMAtomicReadU64(&pThis->u64State) & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT));
return VINF_SUCCESS;
}
{
#ifndef RTCRITSECTRW_STRICT
#else
#endif
}
{
}
{
#ifndef RTCRITSECTRW_STRICT
#else
#endif
}
{
}
{
/*
* Validate handle.
*/
/*
* Check the direction and take action accordingly.
*/
{
#ifdef RTCRITSECTRW_STRICT
if (RT_FAILURE(rc9))
return rc9;
#endif
for (;;)
{
AssertReturn(c > 0, VERR_NOT_OWNER);
c--;
if ( c > 0
|| (u64State & RTCSRW_CNT_WR_MASK) == 0)
{
/* Don't change the direction. */
u64State |= c << RTCSRW_CNT_RD_SHIFT;
break;
}
else
{
/* Reverse the direction and signal the reader threads. */
{
break;
}
}
ASMNopPause();
}
}
else
{
#ifdef RTCRITSECTRW_STRICT
if (RT_FAILURE(rc))
return rc;
#endif
}
return VINF_SUCCESS;
}
{
/*
* Validate input.
*/
#ifdef RTCRITSECTRW_STRICT
if (!fTryOnly)
{
int rc9 = RTLockValidatorRecExclCheckOrder(pThis->pValidatorWrite, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
if (RT_FAILURE(rc9))
return rc9;
}
#endif
/*
* Check if we're already the owner and just recursing.
*/
if (hNativeSelf == hNativeWriter)
{
Assert((ASMAtomicReadU64(&pThis->u64State) & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT));
#ifdef RTCRITSECTRW_STRICT
if (RT_FAILURE(rc9))
return rc9;
#endif
return VINF_SUCCESS;
}
/*
* Get cracking.
*/
for (;;)
{
{
/* It flows in the right direction, try follow it before it changes. */
c++;
u64State |= c << RTCSRW_CNT_WR_SHIFT;
break;
}
{
/* Wrong direction, but we're alone here and can simply try switch the direction. */
break;
}
else if (fTryOnly)
/* Wrong direction and we're not supposed to wait, just return. */
return VERR_SEM_BUSY;
else
{
/* Add ourselves to the write count and break out to do the wait. */
c++;
u64State |= c << RTCSRW_CNT_WR_SHIFT;
break;
}
return VERR_SEM_DESTROYED;
ASMNopPause();
}
/*
* If we're in write mode now try grab the ownership. Play fair if there
* are threads already waiting.
*/
|| fTryOnly);
if (fDone)
if (!fDone)
{
/*
* If only trying, undo the above writer incrementation and return.
*/
if (fTryOnly)
{
for (;;)
{
c--;
u64State |= c << RTCSRW_CNT_WR_SHIFT;
break;
}
return VERR_SEM_BUSY;
}
/*
* Wait for our turn.
*/
{
int rc;
#ifdef RTCRITSECTRW_STRICT
if (hThreadSelf == NIL_RTTHREAD)
RT_INDEFINITE_WAIT, RTTHREADSTATE_RW_WRITE, false);
if (RT_SUCCESS(rc))
#else
#endif
{
return VERR_SEM_DESTROYED;
}
if (RT_FAILURE(rc))
{
/* Decrement the counts and return the error. */
for (;;)
{
c--;
u64State |= c << RTCSRW_CNT_WR_SHIFT;
break;
}
return rc;
}
{
if (fDone)
break;
}
}
}
/*
* Got it!
*/
Assert((ASMAtomicReadU64(&pThis->u64State) & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT));
#ifdef RTCRITSECTRW_STRICT
#endif
return VINF_SUCCESS;
}
{
#ifndef RTCRITSECTRW_STRICT
#else
#endif
}
{
}
{
#ifndef RTCRITSECTRW_STRICT
#else
#endif
}
{
}
{
/*
* Validate handle.
*/
/*
* Unwind a recursion.
*/
{
AssertReturn(pThis->cWriterReads == 0, VERR_WRONG_ORDER); /* (must release all read recursions before the final write.) */
#ifdef RTCRITSECTRW_STRICT
if (RT_FAILURE(rc9))
return rc9;
#endif
/*
* Update the state.
*/
for (;;)
{
Assert(c > 0);
c--;
if ( c > 0
|| (u64State & RTCSRW_CNT_RD_MASK) == 0)
{
/* Don't change the direction, wait up the next writer if any. */
u64State |= c << RTCSRW_CNT_WR_SHIFT;
{
if (c > 0)
{
}
break;
}
}
else
{
/* Reverse the direction and signal the reader threads. */
{
break;
}
}
ASMNopPause();
return VERR_SEM_DESTROYED;
}
}
else
{
#ifdef RTCRITSECTRW_STRICT
if (RT_FAILURE(rc9))
return rc9;
#endif
}
return VINF_SUCCESS;
}
{
/*
* Validate handle.
*/
/*
* Check ownership.
*/
return hNativeWriter == hNativeSelf;
}
{
/*
* Validate handle.
*/
/*
* Inspect the state.
*/
{
/*
* It's in write mode, so we can only be a reader if we're also the
* current writer.
*/
return hWriter == hNativeSelf;
}
/*
* Read mode. If there are no current readers, then we cannot be a reader.
*/
if (!(u64State & RTCSRW_CNT_RD_MASK))
return false;
#ifdef RTCRITSECTRW_STRICT
/*
* Ask the lock validator.
*/
#else
/*
* Ok, we don't know, just tell the caller what he want to hear.
*/
return fWannaHear;
#endif
}
{
/*
* Validate handle.
*/
/*
* Return the requested data.
*/
return pThis->cWriteRecursions;
}
{
/*
* Validate handle.
*/
/*
* Return the requested data.
*/
return pThis->cWriterReads;
}
{
/*
* Validate input.
*/
/*
* Return the requested data.
*/
return 0;
}
{
/*
* Assert free waiters and so on.
*/
//Assert(pThis->cNestings == 0);
//Assert(pThis->cLockers == -1);
/*
* Invalidate the structure and free the semaphores.
*/
return VERR_INVALID_PARAMETER;
}