VirtualBox

Changeset 25549 in vbox for trunk/src/VBox/Runtime/generic


Ignore:
Timestamp:
Dec 21, 2009 5:16:59 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
56225
Message:

semxroads-generic.cpp: bugfix - reset race (of course).

File:
1 edited

Legend:

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

    r25431 r25549  
    3333*   Header Files                                                               *
    3434*******************************************************************************/
     35#define RTASSERT_QUIET
    3536#include <iprt/semaphore.h>
    3637#include "internal/iprt.h"
     
    4445#include "internal/magics.h"
    4546
     47#include <stdio.h>//debug
     48
    4649
    4750/*******************************************************************************
     
    5255    /** Magic value (RTSEMXROADS_MAGIC).  */
    5356    uint32_t volatile   u32Magic;
    54     /** The state variable.
     57    uint32_t            u32Padding; /**< alignment padding.*/
     58    /* The state variable.
    5559     * All accesses are atomic and it bits are defined like this:
    5660     *      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;
     61     *      Bit 15      - Unused.
     62     *      Bits 16..31 - cEastWest.
     63     *      Bit 31      - fDirection; 0=NS, 1=EW.
     64     *      Bits 32..46 - cWaitingNS
     65     *      Bit 47      - Unused.
     66     *      Bits 48..62 - cWaitingEW
     67     *      Bit 63      - Unused.
     68     */
     69    uint64_t volatile   u64State;
     70    /** Per-direction data. */
     71    struct
     72    {
     73        /** What the north/south bound threads are blocking on when waiting for
     74         * east/west traffic to stop. */
     75        RTSEMEVENTMULTI     hEvt;
     76        /** Indicates whether the semaphore needs resetting. */
     77        bool volatile       fNeedReset;
     78    } aDirs[2];
    6879} RTSEMXROADSINTERNAL;
    6980
     
    7283*   Defined Constants And Macros                                               *
    7384*******************************************************************************/
    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)
     85#define RTSEMXROADS_CNT_BITS            15
     86#define RTSEMXROADS_CNT_MASK            UINT64_C(0x00007fff)
     87
     88#define RTSEMXROADS_CNT_NS_SHIFT        0
     89#define RTSEMXROADS_CNT_NS_MASK         (RTSEMXROADS_CNT_MASK << RTSEMXROADS_CNT_NS_SHIFT)
     90#define RTSEMXROADS_CNT_EW_SHIFT        16
     91#define RTSEMXROADS_CNT_EW_MASK         (RTSEMXROADS_CNT_MASK << RTSEMXROADS_CNT_EW_SHIFT)
     92#define RTSEMXROADS_DIR_SHIFT           31
     93#define RTSEMXROADS_DIR_MASK            RT_BIT_64(RTSEMXROADS_DIR_SHIFT)
     94
     95#define RTSEMXROADS_WAIT_CNT_NS_SHIFT   32
     96#define RTSEMXROADS_WAIT_CNT_NS_MASK    (RTSEMXROADS_CNT_MASK << RTSEMXROADS_WAIT_CNT_NS_SHIFT)
     97#define RTSEMXROADS_WAIT_CNT_EW_SHIFT   48
     98#define RTSEMXROADS_WAIT_CNT_EW_MASK    (RTSEMXROADS_CNT_MASK << RTSEMXROADS_WAIT_CNT_EW_SHIFT)
     99
     100
     101#if 0 /* debugging aid */
     102static uint32_t volatile g_iHist = 0;
     103static struct
     104{
     105    void *tsc;
     106    RTTHREAD hThread;
     107    uint32_t line;
     108    bool fDir;
     109    void *u64State;
     110    void *u64OldState;
     111    bool fNeedResetNS;
     112    bool fNeedResetEW;
     113    const char *psz;
     114} g_aHist[256];
     115
     116# define add_hist(ns, os, dir, what)  \
     117    do \
     118    { \
     119        uint32_t i = (ASMAtomicIncU32(&g_iHist) - 1) % RT_ELEMENTS(g_aHist);\
     120        g_aHist[i].line         = __LINE__; \
     121        g_aHist[i].u64OldState  = (void *)(os); \
     122        g_aHist[i].u64State     = (void *)(ns); \
     123        g_aHist[i].fDir         = (dir); \
     124        g_aHist[i].psz          = (what); \
     125        g_aHist[i].fNeedResetNS = pThis->aDirs[0].fNeedReset; \
     126        g_aHist[i].fNeedResetEW = pThis->aDirs[1].fNeedReset; \
     127        g_aHist[i].hThread      = RTThreadSelf(); \
     128        g_aHist[i].tsc          = (void *)ASMReadTSC(); \
     129    } while (0)
     130
     131# undef DECL_FORCE_INLINE
     132# define DECL_FORCE_INLINE(type) static type
     133#else
     134# define add_hist(ns, os, dir, what)  do { } while (0)
     135#endif
    80136
    81137
     
    86142        return VERR_NO_MEMORY;
    87143
    88     int rc = RTSemEventMultiCreate(&pThis->hEvtNS);
     144    int rc = RTSemEventMultiCreate(&pThis->aDirs[0].hEvt);
    89145    if (RT_SUCCESS(rc))
    90146    {
    91         rc = RTSemEventMultiSignal(pThis->hEvtNS);
     147        rc = RTSemEventMultiCreate(&pThis->aDirs[1].hEvt);
    92148        if (RT_SUCCESS(rc))
    93149        {
    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);
     150            pThis->u32Magic            = RTSEMXROADS_MAGIC;
     151            pThis->u32Padding          = 0;
     152            pThis->u64State            = 0;
     153            pThis->aDirs[0].fNeedReset = false;
     154            pThis->aDirs[1].fNeedReset = false;
     155            *phXRoads = pThis;
     156            return VINF_SUCCESS;
     157        }
     158        RTSemEventMultiDestroy(pThis->aDirs[0].hEvt);
    104159    }
    105160    return rc;
     
    117172    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    118173    AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE);
    119     Assert(!(ASMAtomicReadU32(&pThis->u32State) & (RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK)));
     174    Assert(!(ASMAtomicReadU64(&pThis->u64State) & (RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK)));
    120175
    121176    /*
     
    125180
    126181    RTSEMEVENTMULTI hEvt;
    127     ASMAtomicXchgHandle(&pThis->hEvtNS, NIL_RTSEMEVENTMULTI, &hEvt);
     182    ASMAtomicXchgHandle(&pThis->aDirs[0].hEvt, NIL_RTSEMEVENTMULTI, &hEvt);
    128183    int rc = RTSemEventMultiDestroy(hEvt);
    129184    AssertRC(rc);
    130185
    131     ASMAtomicXchgHandle(&pThis->hEvtEW, NIL_RTSEMEVENTMULTI, &hEvt);
     186    ASMAtomicXchgHandle(&pThis->aDirs[1].hEvt, NIL_RTSEMEVENTMULTI, &hEvt);
    132187    rc = RTSemEventMultiDestroy(hEvt);
    133188    AssertRC(rc);
    134189
     190    RTMemFree(pThis);
    135191    return VINF_SUCCESS;
    136192}
     
    142198 * @returns IPRT status code.
    143199 * @param   pThis               The semaphore instace.
    144  * @param   hEvtBlock           Which semaphore to wait on.
    145  * @param   hEvtReset           Which semaphore to reset.
     200 * @param   fDir                The direction.
    146201 * @param   uCountShift         The shift count for getting the count.
    147202 * @param   fCountMask          The mask for getting the count.
    148  * @param   fDirection          The direction state value.
     203 * @param   uWaitCountShift     The shift count for getting the wait count.
     204 * @param   fWaitCountMask      The mask for getting the wait count.
    149205 */
    150 DECL_FORCE_INLINE(int) rtSemXRoadsEnter(RTSEMXROADSINTERNAL *pThis,
    151                                         RTSEMEVENTMULTI hEvtBlock, RTSEMEVENTMULTI hEvtReset,
    152                                         uint32_t uCountShift, uint32_t fCountMask, uint32_t fDirection)
    153 {
     206DECL_FORCE_INLINE(int) rtSemXRoadsEnter(RTSEMXROADSINTERNAL *pThis, uint64_t fDir,
     207                                        uint64_t uCountShift, uint64_t fCountMask,
     208                                        uint64_t uWaitCountShift, uint64_t fWaitCountMask)
     209{
     210    uint64_t    u64OldState;
     211    uint64_t    u64State;
     212
     213    u64State = ASMAtomicReadU64(&pThis->u64State);
     214    u64OldState = u64State;
     215    add_hist(u64State, u64OldState, fDir, "enter");
     216
    154217    for (;;)
    155218    {
    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;
     219        if ((u64State & RTSEMXROADS_DIR_MASK) == (fDir << RTSEMXROADS_DIR_SHIFT))
     220        {
     221            /* It flows in the right direction, try follow it before it changes. */
     222            uint64_t c = (u64State & fCountMask) >> uCountShift;
    166223            c++;
    167224            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)
     225            u64State &= ~fCountMask;
     226            u64State |= c << uCountShift;
     227            if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
     228            {
     229                add_hist(u64State, u64OldState, fDir, "enter-simple");
     230                break;
     231            }
     232        }
     233        else if ((u64State & (RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK)) == 0)
    174234        {
    175235            /* 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;
     236            u64State &= ~(RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK | RTSEMXROADS_DIR_MASK);
     237            u64State |= (UINT64_C(1) << uCountShift) | (fDir << RTSEMXROADS_DIR_SHIFT);
     238            if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
     239            {
     240                Assert(!pThis->aDirs[fDir].fNeedReset);
     241                add_hist(u64State, u64OldState, fDir, "enter-switch");
     242                break;
     243            }
    183244        }
    184245        else
    185246        {
    186             /* Add ourselves to the waiting threads and wait for the direction to change. */
    187             uint32_t c = (u32State & fCountMask) >> uCountShift;
     247            /* Add ourselves to the queue and wait for the direction to change. */
     248            uint64_t c = (u64State & fCountMask) >> uCountShift;
    188249            c++;
    189             Assert(c < 8*_1K);
    190             u32State &= ~fCountMask;
    191             u32State |= c << uCountShift;
    192             if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32OldState))
     250            Assert(c < RTSEMXROADS_CNT_MASK / 2);
     251
     252            uint64_t cWait = (u64State & fWaitCountMask) >> uWaitCountShift;
     253            cWait++;
     254            Assert(cWait <= c);
     255            Assert(cWait < RTSEMXROADS_CNT_MASK / 2);
     256
     257            u64State &= ~(fCountMask | fWaitCountMask);
     258            u64State |= (c << uCountShift) | (cWait << uWaitCountShift);
     259
     260            if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
    193261            {
     262                add_hist(u64State, u64OldState, fDir, "enter-wait");
    194263                for (uint32_t iLoop = 0; ; iLoop++)
    195264                {
    196                     int rc = RTSemEventMultiWait(hEvtBlock, RT_INDEFINITE_WAIT);
     265                    int rc = RTSemEventMultiWait(pThis->aDirs[fDir].hEvt, RT_INDEFINITE_WAIT);
    197266                    AssertRCReturn(rc, rc);
    198267
     
    200269                        return VERR_SEM_DESTROYED;
    201270
    202                     if ((ASMAtomicReadU32(&pThis->u32State) & RTSEMXROADS_DIR_MASK) == (fDirection << RTSEMXROADS_DIR_SHIFT))
    203                         return VINF_SUCCESS;
    204 
    205                     AssertMsgFailed(("%u\n", iLoop));
     271                    Assert(pThis->aDirs[fDir].fNeedReset);
     272                    u64State = ASMAtomicReadU64(&pThis->u64State);
     273                    add_hist(u64State, u64OldState, fDir, "enter-wakeup");
     274                    if ((u64State & RTSEMXROADS_DIR_MASK) == (fDir << RTSEMXROADS_DIR_SHIFT))
     275                        break;
     276                    AssertMsg(iLoop < 1, ("%u\n", iLoop));
    206277                }
     278
     279                /* Decrement the wait count and maybe reset the semaphore (if we're last). */
     280                for (;;)
     281                {
     282                    u64OldState = u64State;
     283
     284                    cWait = (u64State & fWaitCountMask) >> uWaitCountShift;
     285                    Assert(cWait > 0);
     286                    cWait--;
     287                    u64State &= ~fWaitCountMask;
     288                    u64State |= cWait << uWaitCountShift;
     289
     290                    if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
     291                    {
     292                        if (cWait == 0)
     293                        {
     294                            if (ASMAtomicXchgBool(&pThis->aDirs[fDir].fNeedReset, false))
     295                            {
     296                                add_hist(u64State, u64OldState, fDir, fDir ? "enter-reset-EW" : "enter-reset-NS");
     297                                int rc = RTSemEventMultiReset(pThis->aDirs[fDir].hEvt);
     298                                AssertRCReturn(rc, rc);
     299                            }
     300                            else
     301                                add_hist(u64State, u64OldState, fDir, "enter-dec-no-need");
     302                        }
     303                        break;
     304                    }
     305                    u64State = ASMAtomicReadU64(&pThis->u64State);
     306                }
     307                break;
    207308            }
    208         }
    209 
    210         ASMNopPause();
     309
     310            add_hist(u64State, u64OldState, fDir, "enter-wait-failed");
     311        }
     312
    211313        if (pThis->u32Magic != RTSEMXROADS_MAGIC)
    212314            return VERR_SEM_DESTROYED;
     315
     316        ASMNopPause();
     317        u64State = ASMAtomicReadU64(&pThis->u64State);
     318        u64OldState = u64State;
    213319    }
     320
     321    /* got it! */
     322    Assert((ASMAtomicReadU64(&pThis->u64State) & RTSEMXROADS_DIR_MASK) == (fDir << RTSEMXROADS_DIR_SHIFT));
     323    return VINF_SUCCESS;
    214324}
    215325
     
    220330 * @returns IPRT status code.
    221331 * @param   pThis               The semaphore instace.
    222  * @param   hEvtReset           Which semaphore to reset.
    223  * @param   hEvtSignal          Which semaphore to signal.
     332 * @param   fDir                The direction.
    224333 * @param   uCountShift         The shift count for getting the count.
    225334 * @param   fCountMask          The mask for getting the count.
    226  * @param   fDirection          The direction state value.
    227335 */
    228 DECL_FORCE_INLINE(int) rtSemXRoadsLeave(RTSEMXROADSINTERNAL *pThis,
    229                                         RTSEMEVENTMULTI hEvtReset, RTSEMEVENTMULTI hEvtSignal,
    230                                         uint32_t uCountShift, uint32_t fCountMask, uint32_t fDirection)
     336DECL_FORCE_INLINE(int) rtSemXRoadsLeave(RTSEMXROADSINTERNAL *pThis, uint64_t fDir, uint64_t uCountShift, uint64_t fCountMask)
    231337{
    232338    for (;;)
    233339    {
    234         uint32_t u32OldState;
    235         uint32_t u32State;
    236         uint32_t c;
    237 
    238         u32State = ASMAtomicReadU32(&pThis->u32State);
    239         u32OldState = u32State;
     340        uint64_t u64OldState;
     341        uint64_t u64State;
     342        uint64_t c;
     343
     344        u64State = ASMAtomicReadU64(&pThis->u64State);
     345        u64OldState = u64State;
    240346
    241347        /* 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;
     348        Assert((u64State & RTSEMXROADS_DIR_MASK) == (fDir << RTSEMXROADS_DIR_SHIFT));
     349
     350        c = (u64State & fCountMask) >> uCountShift;
    245351        Assert(c > 0);
    246352        c--;
    247353
    248354        if (    c > 0
    249             ||  (u32State & ((RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK) & ~fCountMask)) == 0)
     355            ||  (u64State & ((RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK) & ~fCountMask)) == 0)
    250356        {
    251357            /* 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))
     358            u64State &= ~fCountMask;
     359            u64State |= c << uCountShift;
     360            if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
     361            {
     362                add_hist(u64State, u64OldState, fDir, "leave-simple");
    255363                return VINF_SUCCESS;
     364            }
    256365        }
    257366        else
    258367        {
    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))
     368            /* Reverse the direction and signal the threads in the other direction. */
     369            u64State &= ~(fCountMask | RTSEMXROADS_DIR_MASK);
     370            u64State |= (uint64_t)!fDir << RTSEMXROADS_DIR_SHIFT;
     371            if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState))
    267372            {
    268                 int rc = RTSemEventMultiSignal(hEvtSignal);
     373                add_hist(u64State, u64OldState, fDir, fDir ? "leave-signal-NS" : "leave-signal-EW");
     374                Assert(!pThis->aDirs[!fDir].fNeedReset);
     375                ASMAtomicWriteBool(&pThis->aDirs[!fDir].fNeedReset, true);
     376                int rc = RTSemEventMultiSignal(pThis->aDirs[!fDir].hEvt);
    269377                AssertRC(rc);
    270378                return VINF_SUCCESS;
     
    290398    AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE);
    291399
    292     return rtSemXRoadsEnter(pThis, pThis->hEvtNS, pThis->hEvtEW, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK, 0);
     400    return rtSemXRoadsEnter(pThis, 0, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK, RTSEMXROADS_WAIT_CNT_NS_SHIFT, RTSEMXROADS_WAIT_CNT_NS_MASK);
    293401}
    294402
     
    305413    AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE);
    306414
    307     return rtSemXRoadsLeave(pThis, pThis->hEvtNS, pThis->hEvtEW, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK, 0);
     415    return rtSemXRoadsLeave(pThis, 0, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK);
    308416}
    309417
     
    320428    AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE);
    321429
    322     return rtSemXRoadsEnter(pThis, pThis->hEvtEW, pThis->hEvtNS, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK, 1);
     430    return rtSemXRoadsEnter(pThis, 1, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK, RTSEMXROADS_WAIT_CNT_EW_SHIFT, RTSEMXROADS_WAIT_CNT_EW_MASK);
    323431}
    324432
     
    335443    AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE);
    336444
    337     return rtSemXRoadsLeave(pThis, pThis->hEvtEW, pThis->hEvtNS, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK, 1);
    338 }
    339 
     445    return rtSemXRoadsLeave(pThis, 1, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK);
     446}
     447
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