semxroads-generic.cpp revision 7e33622becf3d7cf9a2401ac0c53d315877f6e34
/* $Id$ */
/** @file
* IPRT Testcase - RTSemXRoads, generic implementation.
*/
/*
* 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 *
*******************************************************************************/
#include <iprt/semaphore.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef struct RTSEMXROADSINTERNAL
{
/** Magic value (RTSEMXROADS_MAGIC). */
/** The state variable.
* All accesses are atomic and it bits are defined like this:
* Bits 0..14 - cNorthSouth.
* Bits 15..30 - cEastWest.
* Bit 30 - fDirection; 0=NS, 1=EW.
* Bit 31 - Unused.
*/
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
#define RTSEMXROADS_CNT_NS_SHIFT 0
#define RTSEMXROADS_CNT_EW_SHIFT 15
#define RTSEMXROADS_DIR_SHIFT 30
{
if (!pThis)
return VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
}
}
return rc;
}
{
/*
* Validate input.
*/
if (pThis == NIL_RTSEMXROADS)
return VINF_SUCCESS;
Assert(!(ASMAtomicReadU32(&pThis->u32State) & (RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK)));
/*
* Invalidate the object and free up the resources.
*/
AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMXROADS_MAGIC_DEAD, RTSEMXROADS_MAGIC), VERR_INVALID_HANDLE);
return VINF_SUCCESS;
}
/**
* Internal worker for RTSemXRoadsNSEnter and RTSemXRoadsEWEnter.
*
* @returns IPRT status code.
* @param pThis The semaphore instace.
* @param hEvtBlock Which semaphore to wait on.
* @param hEvtReset Which semaphore to reset.
* @param uCountShift The shift count for getting the count.
* @param fCountMask The mask for getting the count.
* @param fDirection The direction state value.
*/
{
for (;;)
{
{
/* It's flows in the right direction, try add ourselves to the flow before it changes. */
c++;
u32State &= ~fCountMask;
u32State |= c << uCountShift;
return VINF_SUCCESS;
}
{
/* Wrong direction, but we're alone here and can simply try switch the direction. */
return VERR_SEM_DESTROYED;
return VINF_SUCCESS;
}
else
{
/* Add ourselves to the waiting threads and wait for the direction to change. */
c++;
u32State &= ~fCountMask;
u32State |= c << uCountShift;
{
{
return VERR_SEM_DESTROYED;
if ((ASMAtomicReadU32(&pThis->u32State) & RTSEMXROADS_DIR_MASK) == (fDirection << RTSEMXROADS_DIR_SHIFT))
return VINF_SUCCESS;
}
}
}
ASMNopPause();
return VERR_SEM_DESTROYED;
}
}
/**
* Internal worker for RTSemXRoadsNSLeave and RTSemXRoadsEWLeave.
*
* @returns IPRT status code.
* @param pThis The semaphore instace.
* @param hEvtReset Which semaphore to reset.
* @param hEvtSignal Which semaphore to signal.
* @param uCountShift The shift count for getting the count.
* @param fCountMask The mask for getting the count.
* @param fDirection The direction state value.
*/
{
for (;;)
{
uint32_t c;
/* The direction cannot change until we've left or we'll crash. */
Assert(c > 0);
c--;
if ( c > 0
{
/* We're not the last one across or there aren't any one waiting in the other direction. */
u32State &= ~fCountMask;
u32State |= c << uCountShift;
return VINF_SUCCESS;
}
else
{
/* Reverse the direction. */
return VERR_SEM_DESTROYED;
{
return VINF_SUCCESS;
}
}
ASMNopPause();
return VERR_SEM_DESTROYED;
}
}
{
/*
* Validate input.
*/
if (pThis == NIL_RTSEMXROADS)
return VINF_SUCCESS;
return rtSemXRoadsEnter(pThis, pThis->hEvtNS, pThis->hEvtEW, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK, 0);
}
{
/*
* Validate input.
*/
if (pThis == NIL_RTSEMXROADS)
return VINF_SUCCESS;
return rtSemXRoadsLeave(pThis, pThis->hEvtNS, pThis->hEvtEW, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK, 0);
}
{
/*
* Validate input.
*/
if (pThis == NIL_RTSEMXROADS)
return VINF_SUCCESS;
return rtSemXRoadsEnter(pThis, pThis->hEvtEW, pThis->hEvtNS, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK, 1);
}
{
/*
* Validate input.
*/
if (pThis == NIL_RTSEMXROADS)
return VINF_SUCCESS;
return rtSemXRoadsLeave(pThis, pThis->hEvtEW, pThis->hEvtNS, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK, 1);
}