VirtualBox

Ignore:
Timestamp:
Dec 16, 2009 2:15:11 PM (15 years ago)
Author:
vboxsync
Message:

RTSemXRoads: initial implementation.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/generic/semxroads-generic.cpp

    r25426 r25431  
    3939#include <iprt/assert.h>
    4040#include <iprt/err.h>
     41#include <iprt/mem.h>
    4142#include <iprt/thread.h>
    4243
     
    4748*   Structures and Typedefs                                                    *
    4849*******************************************************************************/
     50typedef struct RTSEMXROADSINTERNAL
     51{
     52    /** Magic value (RTSEMXROADS_MAGIC).  */
     53    uint32_t volatile   u32Magic;
     54    /** The state variable.
     55     * All accesses are atomic and it bits are defined like this:
     56     *      Bits 0..14  - cNorthSouth.
     57     *      Bits 15..30 - cEastWest.
     58     *      Bit 30      - fDirection; 0=NS, 1=EW.
     59     *      Bit 31      - Unused.
     60     */
     61    uint32_t volatile   u32State;
     62    /** What the north/south bound threads are blocking on when waiting for
     63     * east/west traffic to stop. */
     64    RTSEMEVENTMULTI     hEvtNS;
     65    /** What the east/west bound threads are blocking on when waiting for
     66     * north/south traffic to stop. */
     67    RTSEMEVENTMULTI     hEvtEW;
     68} RTSEMXROADSINTERNAL;
     69
     70
     71/*******************************************************************************
     72*   Defined Constants And Macros                                               *
     73*******************************************************************************/
     74#define RTSEMXROADS_CNT_NS_SHIFT    0
     75#define RTSEMXROADS_CNT_NS_MASK     UINT32_C(0x00007fff)
     76#define RTSEMXROADS_CNT_EW_SHIFT    15
     77#define RTSEMXROADS_CNT_EW_MASK     UINT32_C(0x3fff8000)
     78#define RTSEMXROADS_DIR_SHIFT       30
     79#define RTSEMXROADS_DIR_MASK        UINT32_C(0x40000000)
    4980
    5081
    5182RTDECL(int) RTSemXRoadsCreate(PRTSEMXROADS phXRoads)
    5283{
    53     return VERR_NOT_IMPLEMENTED;
     84    RTSEMXROADSINTERNAL *pThis = (RTSEMXROADSINTERNAL *)RTMemAlloc(sizeof(*pThis));
     85    if (!pThis)
     86        return VERR_NO_MEMORY;
     87
     88    int rc = RTSemEventMultiCreate(&pThis->hEvtNS);
     89    if (RT_SUCCESS(rc))
     90    {
     91        rc = RTSemEventMultiSignal(pThis->hEvtNS);
     92        if (RT_SUCCESS(rc))
     93        {
     94            rc = RTSemEventMultiCreate(&pThis->hEvtEW);
     95            if (RT_SUCCESS(rc))
     96            {
     97                pThis->u32Magic = RTSEMXROADS_MAGIC;
     98                pThis->u32State = 0;
     99                *phXRoads = pThis;
     100                return VINF_SUCCESS;
     101            }
     102        }
     103        RTSemEventMultiDestroy(pThis->hEvtNS);
     104    }
     105    return rc;
    54106}
    55107
     
    57109RTDECL(int) RTSemXRoadsDestroy(RTSEMXROADS hXRoads)
    58110{
    59     return VERR_NOT_IMPLEMENTED;
     111    /*
     112     * Validate input.
     113     */
     114    RTSEMXROADSINTERNAL *pThis = hXRoads;
     115    if (pThis == NIL_RTSEMXROADS)
     116        return VINF_SUCCESS;
     117    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     118    AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE);
     119    Assert(!(ASMAtomicReadU32(&pThis->u32State) & (RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK)));
     120
     121    /*
     122     * Invalidate the object and free up the resources.
     123     */
     124    AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMXROADS_MAGIC_DEAD, RTSEMXROADS_MAGIC), VERR_INVALID_HANDLE);
     125
     126    RTSEMEVENTMULTI hEvt;
     127    ASMAtomicXchgHandle(&pThis->hEvtNS, NIL_RTSEMEVENTMULTI, &hEvt);
     128    int rc = RTSemEventMultiDestroy(hEvt);
     129    AssertRC(rc);
     130
     131    ASMAtomicXchgHandle(&pThis->hEvtEW, NIL_RTSEMEVENTMULTI, &hEvt);
     132    rc = RTSemEventMultiDestroy(hEvt);
     133    AssertRC(rc);
     134
     135    return VINF_SUCCESS;
     136}
     137
     138
     139/**
     140 * Internal worker for RTSemXRoadsNSEnter and RTSemXRoadsEWEnter.
     141 *
     142 * @returns IPRT status code.
     143 * @param   pThis               The semaphore instace.
     144 * @param   hEvtBlock           Which semaphore to wait on.
     145 * @param   hEvtReset           Which semaphore to reset.
     146 * @param   uCountShift         The shift count for getting the count.
     147 * @param   fCountMask          The mask for getting the count.
     148 * @param   fDirection          The direction state value.
     149 */
     150DECL_FORCE_INLINE(int) rtSemXRoadsEnter(RTSEMXROADSINTERNAL *pThis,
     151                                        RTSEMEVENTMULTI hEvtBlock, RTSEMEVENTMULTI hEvtReset,
     152                                        uint32_t uCountShift, uint32_t fCountMask, uint32_t fDirection)
     153{
     154    for (;;)
     155    {
     156        uint32_t u32OldState;
     157        uint32_t u32State;
     158
     159        u32State = ASMAtomicReadU32(&pThis->u32State);
     160        u32OldState = u32State;
     161
     162        if ((u32State & RTSEMXROADS_DIR_MASK) == (fDirection << RTSEMXROADS_DIR_SHIFT))
     163        {
     164            /* It's flows in the right direction, try add ourselves to the flow before it changes. */
     165            uint32_t c = (u32State & fCountMask) >> uCountShift;
     166            c++;
     167            Assert(c < 8*_1K);
     168            u32State &= ~fCountMask;
     169            u32State |= c << uCountShift;
     170            if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32OldState))
     171                return VINF_SUCCESS;
     172        }
     173        else if ((u32State & (RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK)) == 0)
     174        {
     175            /* Wrong direction, but we're alone here and can simply try switch the direction. */
     176            RTSemEventMultiReset(hEvtReset);
     177            if (pThis->u32Magic != RTSEMXROADS_MAGIC)
     178                return VERR_SEM_DESTROYED;
     179
     180            u32State = (UINT32_C(1) << uCountShift) | (fDirection << RTSEMXROADS_DIR_SHIFT);
     181            if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32OldState))
     182                return VINF_SUCCESS;
     183        }
     184        else
     185        {
     186            /* Add ourselves to the waiting threads and wait for the direction to change. */
     187            uint32_t c = (u32State & fCountMask) >> uCountShift;
     188            c++;
     189            Assert(c < 8*_1K);
     190            u32State &= ~fCountMask;
     191            u32State |= c << uCountShift;
     192            if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32OldState))
     193            {
     194                for (uint32_t iLoop = 0; ; iLoop++)
     195                {
     196                    int rc = RTSemEventMultiWait(hEvtBlock, RT_INDEFINITE_WAIT);
     197                    AssertRCReturn(rc, rc);
     198
     199                    if (pThis->u32Magic != RTSEMXROADS_MAGIC)
     200                        return VERR_SEM_DESTROYED;
     201
     202                    if ((ASMAtomicReadU32(&pThis->u32State) & RTSEMXROADS_DIR_MASK) == (fDirection << RTSEMXROADS_DIR_SHIFT))
     203                        return VINF_SUCCESS;
     204
     205                    AssertMsgFailed(("%u\n", iLoop));
     206                }
     207            }
     208        }
     209
     210        ASMNopPause();
     211        if (pThis->u32Magic != RTSEMXROADS_MAGIC)
     212            return VERR_SEM_DESTROYED;
     213    }
     214}
     215
     216
     217/**
     218 * Internal worker for RTSemXRoadsNSLeave and RTSemXRoadsEWLeave.
     219 *
     220 * @returns IPRT status code.
     221 * @param   pThis               The semaphore instace.
     222 * @param   hEvtReset           Which semaphore to reset.
     223 * @param   hEvtSignal          Which semaphore to signal.
     224 * @param   uCountShift         The shift count for getting the count.
     225 * @param   fCountMask          The mask for getting the count.
     226 * @param   fDirection          The direction state value.
     227 */
     228DECL_FORCE_INLINE(int) rtSemXRoadsLeave(RTSEMXROADSINTERNAL *pThis,
     229                                        RTSEMEVENTMULTI hEvtReset, RTSEMEVENTMULTI hEvtSignal,
     230                                        uint32_t uCountShift, uint32_t fCountMask, uint32_t fDirection)
     231{
     232    for (;;)
     233    {
     234        uint32_t u32OldState;
     235        uint32_t u32State;
     236        uint32_t c;
     237
     238        u32State = ASMAtomicReadU32(&pThis->u32State);
     239        u32OldState = u32State;
     240
     241        /* The direction cannot change until we've left or we'll crash. */
     242        Assert((u32State & RTSEMXROADS_DIR_MASK) == (fDirection << RTSEMXROADS_DIR_SHIFT));
     243
     244        c = (u32State & fCountMask) >> uCountShift;
     245        Assert(c > 0);
     246        c--;
     247
     248        if (    c > 0
     249            ||  (u32State & ((RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK) & ~fCountMask)) == 0)
     250        {
     251            /* We're not the last one across or there aren't any one waiting in the other direction.  */
     252            u32State &= ~fCountMask;
     253            u32State |= c << uCountShift;
     254            if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32OldState))
     255                return VINF_SUCCESS;
     256        }
     257        else
     258        {
     259            /* Reverse the direction. */
     260            RTSemEventMultiReset(hEvtReset);
     261            if (pThis->u32Magic != RTSEMXROADS_MAGIC)
     262                return VERR_SEM_DESTROYED;
     263
     264            u32State &= ~(fCountMask | RTSEMXROADS_DIR_MASK);
     265            u32State |= !fDirection << RTSEMXROADS_DIR_SHIFT;
     266            if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32OldState))
     267            {
     268                int rc = RTSemEventMultiSignal(hEvtSignal);
     269                AssertRC(rc);
     270                return VINF_SUCCESS;
     271            }
     272        }
     273
     274        ASMNopPause();
     275        if (pThis->u32Magic != RTSEMXROADS_MAGIC)
     276            return VERR_SEM_DESTROYED;
     277    }
    60278}
    61279
     
    63281RTDECL(int) RTSemXRoadsNSEnter(RTSEMXROADS hXRoads)
    64282{
    65     return VERR_NOT_IMPLEMENTED;
     283    /*
     284     * Validate input.
     285     */
     286    RTSEMXROADSINTERNAL *pThis = hXRoads;
     287    if (pThis == NIL_RTSEMXROADS)
     288        return VINF_SUCCESS;
     289    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     290    AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE);
     291
     292    return rtSemXRoadsEnter(pThis, pThis->hEvtNS, pThis->hEvtEW, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK, 0);
    66293}
    67294
     
    69296RTDECL(int) RTSemXRoadsNSLeave(RTSEMXROADS hXRoads)
    70297{
    71     return VERR_NOT_IMPLEMENTED;
     298    /*
     299     * Validate input.
     300     */
     301    RTSEMXROADSINTERNAL *pThis = hXRoads;
     302    if (pThis == NIL_RTSEMXROADS)
     303        return VINF_SUCCESS;
     304    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     305    AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE);
     306
     307    return rtSemXRoadsLeave(pThis, pThis->hEvtNS, pThis->hEvtEW, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK, 0);
    72308}
    73309
     
    75311RTDECL(int) RTSemXRoadsEWEnter(RTSEMXROADS hXRoads)
    76312{
    77     return VERR_NOT_IMPLEMENTED;
     313    /*
     314     * Validate input.
     315     */
     316    RTSEMXROADSINTERNAL *pThis = hXRoads;
     317    if (pThis == NIL_RTSEMXROADS)
     318        return VINF_SUCCESS;
     319    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     320    AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE);
     321
     322    return rtSemXRoadsEnter(pThis, pThis->hEvtEW, pThis->hEvtNS, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK, 1);
    78323}
    79324
     
    81326RTDECL(int) RTSemXRoadsEWLeave(RTSEMXROADS hXRoads)
    82327{
    83     return VERR_NOT_IMPLEMENTED;
    84 }
    85 
     328    /*
     329     * Validate input.
     330     */
     331    RTSEMXROADSINTERNAL *pThis = hXRoads;
     332    if (pThis == NIL_RTSEMXROADS)
     333        return VINF_SUCCESS;
     334    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     335    AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE);
     336
     337    return rtSemXRoadsLeave(pThis, pThis->hEvtEW, pThis->hEvtNS, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK, 1);
     338}
     339
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette