VirtualBox

Changeset 20601 in vbox for trunk/src


Ignore:
Timestamp:
Jun 15, 2009 7:08:29 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
48648
Message:

Runtime: generic SemRW code, removed old implementation

File:
1 edited

Legend:

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

    r13836 r20601  
    88
    99/*
    10  * Copyright (C) 2006-2007 Sun Microsystems, Inc.
     10 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
    1111 *
    1212 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3232 */
    3333
    34 /** @todo fix generic RW sems. (reimplement) */
    35 #define USE_CRIT_SECT
    3634
    3735
     
    4038*******************************************************************************/
    4139#include <iprt/semaphore.h>
     40#include <iprt/critsect.h>
    4241#include <iprt/alloc.h>
    4342#include <iprt/time.h>
     
    4645#include <iprt/thread.h>
    4746#include <iprt/err.h>
    48 #ifdef USE_CRIT_SECT
    49 #include <iprt/critsect.h>
    50 #endif
    51 
     47#include <iprt/stream.h>
     48
     49#include "internal/magics.h"
    5250
    5351
     
    5553*   Structures and Typedefs                                                    *
    5654*******************************************************************************/
     55
    5756/** Internal representation of a Read-Write semaphore for the
    5857 * Generic implementation. */
    5958struct RTSEMRWINTERNAL
    6059{
    61 #ifdef USE_CRIT_SECT
    62     /** Critical section. */
    63     RTCRITSECT  CritSect;
    64 #else
    65     /** Magic (RTSEMRW_MAGIC). */
    66     uint32_t                u32Magic;
     60    /** The usual magic. (RTSEMRW_MAGIC) */
     61    uint32_t            u32Magic;
     62    /* Alignment padding. */
     63    uint32_t            u32Padding;
    6764    /** This critical section serializes the access to and updating of the structure members. */
    68     RTCRITSECT              CritSect;
    69     /** The current number of readers. */
    70     uint32_t                cReaders;
    71     /** The number of readers waiting. */
    72     uint32_t                cReadersWaiting;
    73     /** The current number of waiting writers. */
    74     uint32_t                cWritersWaiting;
     65    RTCRITSECT          CritSect;
     66    /** The current number of reads. (pure read recursion counts too) */
     67    uint32_t            cReads;
     68    /** The current number of writes. (recursion counts too) */
     69    uint32_t            cWrites;
     70    /** Number of read recursions by the writer. */
     71    uint32_t            cWriterReads;
     72    /** Number of writers waiting. */
     73    uint32_t            cWritesWaiting;
     74    /** The write owner of the lock. */
     75    RTTHREAD            Writer;
    7576    /** The handle of the event object on which the waiting readers block. (manual reset). */
    76     RTSEMEVENTMULTI         EventReaders;
    77     /** The handle of the event object on which the waiting writers block. (manual reset). */
    78     RTSEMEVENTMULTI         EventWriters;
    79     /** The current state of the read-write lock. */
    80     KPRF_TYPE(,RWLOCKSTATE) enmState;
    81 
    82 #endif
     77    RTSEMEVENTMULTI     ReadEvent;
     78    /** The handle of the event object on which the waiting writers block. (automatic reset). */
     79    RTSEMEVENT          WriteEvent;
    8380};
    8481
     
    8986 * @returns true if valid.
    9087 * @returns false if invalid.
    91  * @param   pIntRWSem   Pointer to the read-write semaphore to validate.
     88 * @param   pThis   Pointer to the read-write semaphore to validate.
    9289 */
    93 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
    94 {
    95     if (!VALID_PTR(pIntRWSem))
     90inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pThis)
     91{
     92    if (!VALID_PTR(pThis))
    9693        return false;
    9794
    98 #ifdef USE_CRIT_SECT
    99     if (pIntRWSem->CritSect.u32Magic != RTCRITSECT_MAGIC)
     95    if (pThis->u32Magic != RTSEMRW_MAGIC)
    10096        return false;
    101 #else
    102     if (pIntRWSem->u32Check != (uint32_t)~0)
    103         return false;
    104 #endif
    10597    return true;
    10698}
    10799
    108100
    109 RTDECL(int)   RTSemRWCreate(PRTSEMRW pRWSem)
     101RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)
    110102{
    111103    int rc;
     
    114106     * Allocate memory.
    115107     */
    116     struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
    117     if (pIntRWSem)
    118     {
    119 #ifdef USE_CRIT_SECT
    120         rc = RTCritSectInit(&pIntRWSem->CritSect);
     108    struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
     109    if (pThis)
     110    {
     111        /*
     112         * Create the semaphores.
     113         */
     114        rc = RTSemEventCreate(&pThis->WriteEvent);
    121115        if (RT_SUCCESS(rc))
    122116        {
    123             *pRWSem = pIntRWSem;
    124             return VINF_SUCCESS;
    125         }
    126 #else
    127         /*
    128          * Create the semaphores.
    129          */
    130         rc = RTSemEventCreate(&pIntRWSem->WriteEvent);
    131         if (RT_SUCCESS(rc))
    132         {
    133             rc = RTSemEventMultiCreate(&pIntRWSem->ReadEvent);
     117            rc = RTSemEventMultiCreate(&pThis->ReadEvent);
    134118            if (RT_SUCCESS(rc))
    135119            {
    136                 rc = RTSemMutexCreate(&pIntRWSem->Mutex);
     120                rc = RTCritSectInit(&pThis->CritSect);
    137121                if (RT_SUCCESS(rc))
    138122                {
     
    140124                     * Signal the read semaphore and initialize other variables.
    141125                     */
    142                     rc = RTSemEventMultiSignal(pIntRWSem->ReadEvent);
     126                    rc = RTSemEventMultiSignal(pThis->ReadEvent);
    143127                    if (RT_SUCCESS(rc))
    144128                    {
    145                         pIntRWSem->cReaders = 0;
    146                         pIntRWSem->cWriters = 0;
    147                         pIntRWSem->WROwner  = NIL_RTTHREAD;
    148                         pIntRWSem->u32Check = ~0;
    149                         *pRWSem = pIntRWSem;
     129                        pThis->u32Padding       = 0xa5a55a5a;
     130                        pThis->cReads           = 0;
     131                        pThis->cWrites          = 0;
     132                        pThis->cWriterReads     = 0;
     133                        pThis->cWritesWaiting   = 0;
     134                        pThis->Writer           = NIL_RTTHREAD;
     135                        pThis->u32Magic         = RTSEMRW_MAGIC;
     136                        *pRWSem = pThis;
    150137                        return VINF_SUCCESS;
    151138                    }
    152                     RTSemMutexDestroy(pIntRWSem->Mutex);
     139                    RTCritSectDelete(&pThis->CritSect);
    153140                }
    154                 RTSemEventMultiDestroy(pIntRWSem->ReadEvent);
     141                RTSemEventMultiDestroy(pThis->ReadEvent);
    155142            }
    156             RTSemEventDestroy(pIntRWSem->WriteEvent);
    157         }
    158 #endif
    159         RTMemFree(pIntRWSem);
     143            RTSemEventDestroy(pThis->WriteEvent);
     144        }
     145        RTMemFree(pThis);
    160146    }
    161147    else
     
    166152
    167153
    168 RTDECL(int)   RTSemRWDestroy(RTSEMRW RWSem)
    169 {
    170     /*
    171      * Validate handle.
    172      */
    173     if (!rtsemRWValid(RWSem))
    174     {
    175         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    176         return VERR_INVALID_HANDLE;
    177     }
    178 
    179 #ifdef USE_CRIT_SECT
    180     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    181     int rc = RTCritSectDelete(&pIntRWSem->CritSect);
     154RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)
     155{
     156    struct RTSEMRWINTERNAL *pThis = RWSem;
     157    /*
     158     * Validate handle.
     159     */
     160    if (!rtsemRWValid(pThis))
     161    {
     162        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
     163        return VERR_INVALID_HANDLE;
     164    }
     165
     166    /*
     167     * Check if busy.
     168     */
     169    int rc = RTCritSectTryEnter(&pThis->CritSect);
    182170    if (RT_SUCCESS(rc))
    183         RTMemFree(pIntRWSem);
    184     return rc;
    185 #else
    186 
    187     /*
    188      * Check if busy.
    189      */
    190     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    191     int rc = RTSemMutexRequest(pIntRWSem->Mutex, 32);
    192     if (RT_SUCCESS(rc))
    193     {
    194         if (!pIntRWSem->cReaders && !pIntRWSem->cWriters)
     171    {
     172        if (!pThis->cReads && !pThis->cWrites)
    195173        {
    196174            /*
    197175             * Make it invalid and unusable.
    198176             */
    199             ASMAtomicXchgU32(&pIntRWSem->u32Check, 0);
    200             ASMAtomicXchgU32(&pIntRWSem->cReaders, ~0);
     177            pThis->u32Magic = ~RTSEMRW_MAGIC;
     178            pThis->cReads = ~0;
    201179
    202180            /*
    203              * Do actual cleanup.
    204              * None of these can now fail excep for the mutex which
    205              * can be a little bit busy.
     181             * Do actual cleanup. None of these can now fail.
    206182             */
    207             rc = RTSemEventMultiDestroy(pIntRWSem->ReadEvent);
     183            rc = RTSemEventMultiDestroy(pThis->ReadEvent);
    208184            AssertMsgRC(rc, ("RTSemEventMultiDestroy failed! rc=%d\n", rc));
    209             pIntRWSem->ReadEvent = NIL_RTSEMEVENTMULTI;
    210 
    211             rc = RTSemEventDestroy(pIntRWSem->WriteEvent);
     185            pThis->ReadEvent = NIL_RTSEMEVENTMULTI;
     186
     187            rc = RTSemEventDestroy(pThis->WriteEvent);
    212188            AssertMsgRC(rc, ("RTSemEventDestroy failed! rc=%d\n", rc));
    213             pIntRWSem->WriteEvent = NIL_RTSEMEVENT;
    214 
    215             RTSemMutexRelease(pIntRWSem->Mutex);
    216             for (unsigned i = 32; i > 0; i--)
    217             {
    218                 rc = RTSemMutexDestroy(pIntRWSem->Mutex);
    219                 if (RT_SUCCESS(rc))
    220                     break;
    221                 RTThreadSleep(1);
    222             }
    223             AssertMsgRC(rc, ("RTSemMutexDestroy failed! rc=%d\n", rc));
    224             pIntRWSem->Mutex = (RTSEMMUTEX)0;
    225 
    226             RTMemFree(pIntRWSem);
     189            pThis->WriteEvent = NIL_RTSEMEVENT;
     190
     191            RTCritSectLeave(&pThis->CritSect);
     192            rc = RTCritSectDelete(&pThis->CritSect);
     193            AssertMsgRC(rc, ("RTCritSectDelete failed! rc=%d\n", rc));
     194
     195            RTMemFree(pThis);
    227196            rc = VINF_SUCCESS;
    228197        }
     
    230199        {
    231200            rc = VERR_SEM_BUSY;
    232             RTSemMutexRelease(pIntRWSem->Mutex);
     201            RTCritSectLeave(&pThis->CritSect);
    233202        }
    234203    }
    235204    else
    236         rc = rc == VERR_TIMEOUT ? VERR_SEM_BUSY : rc;
    237 
    238     return VINF_SUCCESS;
    239 #endif
    240 }
    241 
    242 
    243 RTDECL(int)   RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
    244 {
    245     /*
    246      * Validate handle.
    247      */
    248     if (!rtsemRWValid(RWSem))
    249     {
    250         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    251         return VERR_INVALID_HANDLE;
    252     }
    253 
    254 #ifdef USE_CRIT_SECT
    255     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    256     return RTCritSectEnter(&pIntRWSem->CritSect);
    257 #else
    258 
    259     /*
    260      * Take mutex and check if already reader.
    261      */
    262     //RTTHREAD    Self = RTThreadSelf();
     205    {
     206        AssertMsgRC(rc, ("RTCritSectTryEnter failed! rc=%d\n", rc));
     207        rc = VERR_SEM_BUSY;
     208    }
     209
     210    return rc;
     211}
     212
     213
     214RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
     215{
     216    struct RTSEMRWINTERNAL *pThis = RWSem;
     217    /*
     218     * Validate handle.
     219     */
     220    if (!rtsemRWValid(pThis))
     221    {
     222        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
     223        return VERR_INVALID_HANDLE;
     224    }
     225
    263226    RTTHREAD    Self = (RTTHREAD)RTThreadNativeSelf();
    264227    unsigned    cMilliesInitial = cMillies;
    265228    uint64_t    tsStart = 0;
    266     if (cMillies != RTSEM_INDEFINITE_WAIT)
     229    if (cMillies != RT_INDEFINITE_WAIT)
    267230        tsStart = RTTimeNanoTS();
    268231
    269     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    270     int rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);
     232    /*
     233     * Take critsect.
     234     */
     235    int rc = RTCritSectEnter(&pThis->CritSect);
    271236    if (RT_FAILURE(rc))
    272237    {
    273         AssertMsgFailed(("RTSemMutexRequest failed on rwsem %p, rc=%d\n", RWSem, rc));
     238        AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%d\n", RWSem, rc));
    274239        return rc;
    275240    }
    276241
    277     unsigned i = pIntRWSem->cReaders;
    278     while (i-- > 0)
    279     {
    280         if (pIntRWSem->aReaders[i].Thread == Self)
    281         {
    282             if (pIntRWSem->aReaders[i].cNesting + 1 < (unsigned)~0)
    283                 pIntRWSem->aReaders[i].cNesting++;
    284             else
    285             {
    286                 AssertMsgFailed(("Too many requests for one thread!\n"));
    287                 rc = RTSemMutexRelease(pIntRWSem->Mutex);
    288                 AssertMsgRC(rc, ("RTSemMutexRelease failed rc=%d\n", rc));
    289                 return VERR_TOO_MANY_SEM_REQUESTS;
    290             }
    291         }
    292     }
    293 
    294 
    295242    for (;;)
    296243    {
    297244        /*
    298          * Check if the stat of the affairs allow read access.
    299          */
    300         if (pIntRWSem->u32Check == (uint32_t)~0)
    301         {
    302             if (pIntRWSem->cWriters == 0)
    303             {
    304                 if (pIntRWSem->cReaders < RT_ELEMENTS(pIntRWSem->aReaders))
    305                 {
    306                     /*
    307                      * Add ourselves to the list of readers and return.
    308                      */
    309                     i = pIntRWSem->cReaders;
    310                     pIntRWSem->aReaders[i].Thread   = Self;
    311                     pIntRWSem->aReaders[i].cNesting = 1;
    312                     ASMAtomicXchgU32(&pIntRWSem->cReaders, i + 1);
    313 
    314                     RTSemMutexRelease(pIntRWSem->Mutex);
    315                     return VINF_SUCCESS;
    316                 }
    317                 else
    318                 {
    319                     AssertMsgFailed(("Too many readers! How come we have so many threads!?!\n"));
    320                     rc = VERR_TOO_MANY_SEM_REQUESTS;
    321                 }
    322             }
    323             #if 0 /* any action here shouldn't be necessary */
    324             else
    325             {
    326                 rc = RTSemEventMultiReset(pIntRWSem->ReadEvent);
    327                 AssertMsgRC(rc, ("RTSemEventMultiReset failed on RWSem %p, rc=%d\n", RWSem, rc));
    328             }
    329             #endif
    330         }
    331         else
    332             rc = VERR_SEM_DESTROYED;
    333         RTSemMutexRelease(pIntRWSem->Mutex);
    334         if (RT_FAILURE(rc))
    335             break;
    336 
     245         * Check if the state of affairs allows read access.
     246         * Do not block further readers if there is a writer waiting, as
     247         * that will break/deadlock reader recursion.
     248         */
     249        if (!pThis->cWrites)
     250        {
     251            pThis->cReads++;
     252
     253            RTCritSectLeave(&pThis->CritSect);
     254            return VINF_SUCCESS;
     255        }
     256        else if (pThis->Writer == Self)
     257        {
     258            pThis->cWriterReads++;
     259
     260            RTCritSectLeave(&pThis->CritSect);
     261            return VINF_SUCCESS;
     262        }
     263
     264        RTCritSectLeave(&pThis->CritSect);
    337265
    338266        /*
    339267         * Wait till it's ready for reading.
    340268         */
    341         if (cMillies != RTSEM_INDEFINITE_WAIT)
    342         {
    343             int64_t     tsDelta = RTTimeNanoTS() - tsStart;
     269        if (cMillies != RT_INDEFINITE_WAIT)
     270        {
     271            int64_t tsDelta = RTTimeNanoTS() - tsStart;
    344272            if (tsDelta >= 1000000)
    345273            {
     
    349277            }
    350278        }
    351         rc = RTSemEventMultiWait(pIntRWSem->ReadEvent, cMillies);
     279        rc = RTSemEventMultiWait(pThis->ReadEvent, cMillies);
     280        if (RT_FAILURE(rc) && rc != VERR_TIMEOUT)
     281        {
     282            AssertMsgRC(rc, ("RTSemEventMultiWait failed on rwsem %p, rc=%d\n", RWSem, rc));
     283            break;
     284        }
     285
     286        if (pThis->u32Magic != RTSEMRW_MAGIC)
     287        {
     288            rc = VERR_SEM_DESTROYED;
     289            break;
     290        }
     291
     292        /*
     293         * Re-take critsect.
     294         */
     295        rc = RTCritSectEnter(&pThis->CritSect);
    352296        if (RT_FAILURE(rc))
    353297        {
    354             AssertMsg(rc == VERR_TIMEOUT, ("RTSemEventMultiWait failed on rwsem %p, rc=%d\n", RWSem, rc));
     298            AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%d\n", RWSem, rc));
    355299            break;
    356300        }
    357 
    358         /*
    359          * Get Mutex.
    360          */
    361         rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);
    362         if (RT_FAILURE(rc))
    363         {
    364             AssertMsgFailed(("RTSemMutexRequest failed on rwsem %p, rc=%d\n", RWSem, rc));
    365             break;
    366         }
    367301    }
    368302
    369303    return rc;
    370 #endif
    371 }
    372 
    373 
    374 RTDECL(int)   RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
     304}
     305
     306
     307RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
    375308{
    376309    return RTSemRWRequestRead(RWSem, cMillies);
     
    378311
    379312
    380 RTDECL(int)   RTSemRWReleaseRead(RTSEMRW RWSem)
    381 {
    382     /*
    383      * Validate handle.
    384      */
    385     if (!rtsemRWValid(RWSem))
    386     {
    387         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    388         return VERR_INVALID_HANDLE;
    389     }
    390 
    391 #ifdef USE_CRIT_SECT
    392     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    393     return RTCritSectLeave(&pIntRWSem->CritSect);
    394 #else
    395 
    396     /*
    397      * Take Mutex.
    398      */
    399     //RTTHREAD Self = RTThreadSelf();
     313RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
     314{
     315    struct RTSEMRWINTERNAL *pThis = RWSem;
     316    /*
     317     * Validate handle.
     318     */
     319    if (!rtsemRWValid(pThis))
     320    {
     321        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
     322        return VERR_INVALID_HANDLE;
     323    }
     324
    400325    RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf();
    401     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    402     int rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);
     326
     327    /*
     328     * Take critsect.
     329     */
     330    int rc = RTCritSectEnter(&pThis->CritSect);
    403331    if (RT_SUCCESS(rc))
    404332    {
    405         unsigned i = pIntRWSem->cReaders;
    406         while (i-- > 0)
    407         {
    408             if (pIntRWSem->aReaders[i].Thread == Self)
     333        if (pThis->Writer == Self)
     334        {
     335            pThis->cWriterReads--;
     336        }
     337        else
     338        {
     339            AssertMsg(pThis->Writer == NIL_RTTHREAD, ("Impossible! Writers and Readers are exclusive!\n"));
     340            pThis->cReads--;
     341
     342            /* Kick off a writer if appropriate. */
     343            if (    pThis->cWritesWaiting > 0
     344                &&  !pThis->cReads)
    409345            {
    410                 AssertMsg(pIntRWSem->WROwner == NIL_RTTHREAD, ("Impossible! Writers and Readers are exclusive!\n"));
    411 
    412                 if (pIntRWSem->aReaders[i].cNesting <= 1)
    413                 {
    414                     pIntRWSem->aReaders[i] = pIntRWSem->aReaders[pIntRWSem->cReaders - 1];
    415                     ASMAtomicXchgU32(&pIntRWSem->cReaders, pIntRWSem->cReaders - 1);
    416 
    417                     /* Kick off writers? */
    418                     if (    pIntRWSem->cWriters > 0
    419                         &&  pIntRWSem->cReaders == 0)
    420                     {
    421                         rc = RTSemEventSignal(pIntRWSem->WriteEvent);
    422                         AssertMsgRC(rc, ("Failed to signal writers on rwsem %p, rc=%d\n", RWSem, rc));
    423                     }
    424                 }
    425                 else
    426                     pIntRWSem->aReaders[i].cNesting--;
    427 
    428                 RTSemMutexRelease(pIntRWSem->Mutex);
    429                 return VINF_SUCCESS;
     346                rc = RTSemEventSignal(pThis->WriteEvent);
     347                AssertMsgRC(rc, ("Failed to signal writers on rwsem %p, rc=%d\n", RWSem, rc));
    430348            }
    431349        }
    432350
    433         RTSemMutexRelease(pIntRWSem->Mutex);
    434         rc = VERR_NOT_OWNER;
    435         AssertMsgFailed(("Not reader of rwsem %p\n", RWSem));
     351        RTCritSectLeave(&pThis->CritSect);
     352        return VINF_SUCCESS;
    436353    }
    437354    else
    438         AssertMsgFailed(("RTSemMutexRequest failed on rwsem %p, rc=%d\n", RWSem, rc));
     355        AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%d\n", RWSem, rc));
    439356
    440357    return rc;
    441 #endif
    442 }
    443 
     358}
    444359
    445360
    446361RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
    447362{
    448     /*
    449      * Validate handle.
    450      */
    451     if (!rtsemRWValid(RWSem))
    452     {
    453         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    454         return VERR_INVALID_HANDLE;
    455     }
    456 
    457 #ifdef USE_CRIT_SECT
    458     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    459     return RTCritSectEnter(&pIntRWSem->CritSect);
    460 #else
    461 
    462     /*
    463      * Get Mutex.
    464      */
    465     //RTTHREAD    Self = RTThreadSelf();
     363    struct RTSEMRWINTERNAL *pThis = RWSem;
     364    /*
     365     * Validate handle.
     366     */
     367    if (!rtsemRWValid(pThis))
     368    {
     369        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
     370        return VERR_INVALID_HANDLE;
     371    }
     372
    466373    RTTHREAD    Self = (RTTHREAD)RTThreadNativeSelf();
    467374    unsigned    cMilliesInitial = cMillies;
    468375    uint64_t    tsStart = 0;
    469     if (cMillies != RTSEM_INDEFINITE_WAIT)
     376    if (cMillies != RT_INDEFINITE_WAIT)
    470377        tsStart = RTTimeNanoTS();
    471378
    472     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    473     int rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);
     379    /*
     380     * Take critsect.
     381     */
     382    int rc = RTCritSectEnter(&pThis->CritSect);
    474383    if (RT_FAILURE(rc))
    475384    {
    476         AssertMsgFailed(("RTSemMutexWait failed on rwsem %p, rc=%d\n", RWSem, rc));
     385        AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%d\n", RWSem, rc));
    477386        return rc;
    478387    }
    479388
    480389    /*
    481      * Check that we're not a reader.
    482      */
    483     unsigned i = pIntRWSem->cReaders;
    484     while (i-- > 0)
    485     {
    486         if (pIntRWSem->aReaders[i].Thread == Self)
    487         {
    488             AssertMsgFailed(("Deadlock - requested write access while being a reader! rwsem %p.\n", RWSem));
    489             RTSemMutexRelease(pIntRWSem->Mutex);
    490             return VERR_DEADLOCK;
    491         }
    492     }
    493 
    494 
    495     /*
    496      * Reset the reader event semaphore and increment number of readers.
    497      */
    498     rc = RTSemEventMultiReset(pIntRWSem->ReadEvent);
    499     if (RT_FAILURE(rc))
    500     {
    501         AssertMsgFailed(("Failed to reset readers, rwsem %p, rc=%d.\n", RWSem, rc));
    502         RTSemMutexRelease(pIntRWSem->Mutex);
    503         return rc;
    504     }
    505     ASMAtomicXchgU32(&pIntRWSem->cWriters, pIntRWSem->cWriters + 1);
    506 
    507     /*
    508      * Wait while there are other threads owning this sem.
    509      */
    510     while (     pIntRWSem->WROwner != NIL_RTTHREAD
    511            ||   pIntRWSem->cReaders > 0)
    512     {
    513         AssertMsg(pIntRWSem->WROwner == NIL_RTTHREAD || pIntRWSem->cWriters > 1,
    514                   ("The lock is write owned by there is only one waiter...\n"));
    515 
    516         /*
    517          * Release the mutex and wait on the writer semaphore.
    518          */
    519         rc = RTSemMutexRelease(pIntRWSem->Mutex);
    520         if (RT_FAILURE(rc))
    521         {
    522             AssertMsgFailed(("RTSemMutexRelease failed on rwsem %p, rc=%d\n", RWSem, rc));
    523             return VERR_SEM_DESTROYED;
    524         }
    525 
    526         /*
    527          * Wait.
    528          */
    529         if (cMillies != RTSEM_INDEFINITE_WAIT)
    530         {
    531             int64_t     tsDelta = RTTimeNanoTS() - tsStart;
     390     * Signal writer presence.
     391     */
     392    pThis->cWritesWaiting++;
     393
     394    for (;;)
     395    {
     396        /*
     397         * Check if the state of affairs allows write access.
     398         */
     399        if (!pThis->cReads && (!pThis->cWrites || pThis->Writer == Self))
     400        {
     401            /*
     402             * Reset the reader event semaphore. For write recursion this
     403             * is redundant, but does not hurt.
     404             */
     405            rc = RTSemEventMultiReset(pThis->ReadEvent);
     406            AssertMsgRC(rc, ("Failed to reset readers, rwsem %p, rc=%d.\n", RWSem, rc));
     407
     408            pThis->cWrites++;
     409            pThis->Writer = Self;
     410            /* We're not waiting, so decrease counter. */
     411            pThis->cWritesWaiting--;
     412            RTCritSectLeave(&pThis->CritSect);
     413            return VINF_SUCCESS;
     414        }
     415
     416        RTCritSectLeave(&pThis->CritSect);
     417
     418        /*
     419         * Wait till it's ready for writing.
     420         */
     421        if (cMillies != RT_INDEFINITE_WAIT)
     422        {
     423            int64_t tsDelta = RTTimeNanoTS() - tsStart;
    532424            if (tsDelta >= 1000000)
    533425            {
     
    537429            }
    538430        }
    539         rc = RTSemEventWait(pIntRWSem->WriteEvent, cMillies);
    540 
    541         /*
    542          * Check that the semaphore wasn't destroyed while we waited.
    543          */
    544         if (    rc == VERR_SEM_DESTROYED
    545             ||  pIntRWSem->u32Check != (uint32_t)~0)
    546             return VERR_SEM_DESTROYED;
    547 
    548         /*
    549          * Attempt take the mutex.
    550          */
    551         int rc2 = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);
    552         if (RT_FAILURE(rc) || RT_FAILURE(rc2))
    553         {
    554             AssertMsgRC(rc2, ("RTSemMutexRequest failed on rwsem %p, rc=%d\n", RWSem, rc2));
    555             if (RT_SUCCESS(rc))
    556                 rc = rc2;
    557             else
    558                 AssertMsg(rc == VERR_TIMEOUT, ("RTSemEventWait failed on rwsem %p, rc=%d\n", RWSem, rc));
    559 
    560             /*
    561              * Remove our selves from the writers queue.
    562              */
    563             /** @todo write an atomic dec function! (it's too late for that kind of stuff tonight) */
    564             if (pIntRWSem->cWriters > 0)
    565                 ASMAtomicXchgU32(&pIntRWSem->cWriters, pIntRWSem->cWriters - 1);
    566             if (!pIntRWSem->cWriters)
    567                 RTSemEventMultiSignal(pIntRWSem->ReadEvent);
    568             if (RT_SUCCESS(rc2))
    569                 RTSemMutexRelease(pIntRWSem->Mutex);
    570             return rc;
    571         }
    572 
    573         AssertMsg(pIntRWSem->WROwner == NIL_RTTHREAD, ("We woke up an there is owner! %#x\n", pIntRWSem->WROwner));
    574         AssertMsg(!pIntRWSem->cReaders, ("We woke up an there are readers around!\n"));
    575     }
    576 
    577     /*
    578      * If we get here we own the mutex and we are ready to take
    579      * the read-write ownership.
    580      */
    581     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)Self);
    582     rc = RTSemMutexRelease(pIntRWSem->Mutex);
    583     AssertMsgRC(rc, ("RTSemMutexRelease failed. rc=%d\n", rc));
    584 
    585     return VINF_SUCCESS;
    586 #endif
     431        rc = RTSemEventWait(pThis->WriteEvent, cMillies);
     432        if (RT_FAILURE(rc) && rc != VERR_TIMEOUT)
     433        {
     434            AssertMsgRC(rc, ("RTSemEventWait failed on rwsem %p, rc=%d\n", RWSem, rc));
     435            break;
     436        }
     437
     438        if (pThis->u32Magic != RTSEMRW_MAGIC)
     439        {
     440            rc = VERR_SEM_DESTROYED;
     441            break;
     442        }
     443
     444        /*
     445         * Re-take critsect.
     446         */
     447        rc = RTCritSectEnter(&pThis->CritSect);
     448        if (RT_FAILURE(rc))
     449        {
     450            AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%d\n", RWSem, rc));
     451            break;
     452        }
     453//        AssertMsg(!pThis->cReads, ("We woke up and there are readers around!\n"));
     454    }
     455
     456    /*
     457     * Timeout/error case, clean up.
     458     */
     459    if (pThis->u32Magic == RTSEMRW_MAGIC)
     460    {
     461        RTCritSectEnter(&pThis->CritSect);
     462        /* Adjust this counter, whether we got the critsect or not. */
     463        pThis->cWritesWaiting--;
     464        RTCritSectLeave(&pThis->CritSect);
     465    }
     466    return rc;
    587467}
    588468
     
    594474
    595475
    596 
    597 RTDECL(int)   RTSemRWReleaseWrite(RTSEMRW RWSem)
    598 {
    599     /*
    600      * Validate handle.
    601      */
    602     if (!rtsemRWValid(RWSem))
    603     {
    604         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    605         return VERR_INVALID_HANDLE;
    606     }
    607 
    608 #ifdef USE_CRIT_SECT
    609     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    610     return RTCritSectLeave(&pIntRWSem->CritSect);
    611 #else
     476RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
     477{
     478    struct RTSEMRWINTERNAL *pThis = RWSem;
     479    /*
     480     * Validate handle.
     481     */
     482    if (!rtsemRWValid(pThis))
     483    {
     484        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
     485        return VERR_INVALID_HANDLE;
     486    }
     487
     488    RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf();
     489
     490    /*
     491     * Take critsect.
     492     */
     493    int rc = RTCritSectEnter(&pThis->CritSect);
     494    if (RT_FAILURE(rc))
     495    {
     496        AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%d\n", RWSem, rc));
     497        return rc;
     498    }
    612499
    613500    /*
    614501     * Check if owner.
    615502     */
    616     //RTTHREAD  Self = RTThreadSelf();
    617     RTTHREAD  Self = (RTTHREAD)RTThreadNativeSelf();
    618     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    619     if (pIntRWSem->WROwner != Self)
    620     {
     503    if (pThis->Writer != Self)
     504    {
     505        RTCritSectLeave(&pThis->CritSect);
    621506        AssertMsgFailed(("Not read-write owner of rwsem %p.\n", RWSem));
    622507        return VERR_NOT_OWNER;
    623508    }
    624509
    625     /*
    626      * Request the mutex.
    627      */
    628     int rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);
    629     if (RT_FAILURE(rc))
    630     {
    631         AssertMsgFailed(("RTSemMutexWait failed on rwsem %p, rc=%d\n", RWSem, rc));
    632         return rc;
    633     }
    634 
     510    Assert(pThis->cWrites > 0);
    635511    /*
    636512     * Release ownership and remove ourselves from the writers count.
    637513     */
    638     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)NIL_RTTHREAD);
    639     Assert(pIntRWSem->cWriters > 0);
    640     ASMAtomicXchgU32(&pIntRWSem->cWriters, pIntRWSem->cWriters - 1);
    641 
    642     /*
    643      * Release the readers if no more writers.
    644      */
    645     if (!pIntRWSem->cWriters)
    646     {
    647         rc = RTSemEventMultiSignal(pIntRWSem->ReadEvent);
     514    pThis->cWrites--;
     515    if (!pThis->cWrites)
     516        pThis->Writer = NIL_RTTHREAD;
     517
     518    /*
     519     * Release the readers if no more writers waiting, otherwise the writers.
     520     */
     521    if (!pThis->cWritesWaiting)
     522    {
     523        rc = RTSemEventMultiSignal(pThis->ReadEvent);
    648524        AssertMsgRC(rc, ("RTSemEventMultiSignal failed for rwsem %p, rc=%d.\n", RWSem, rc));
    649525    }
    650     rc = RTSemMutexRelease(pIntRWSem->Mutex);
    651     AssertMsgRC(rc, ("RTSemEventMultiSignal failed for rwsem %p, rc=%d.\n", RWSem, rc));
    652 
    653     return VINF_SUCCESS;
    654 #endif
    655 }
    656 
     526    else
     527    {
     528        rc = RTSemEventSignal(pThis->WriteEvent);
     529        AssertMsgRC(rc, ("Failed to signal writers on rwsem %p, rc=%d\n", RWSem, rc));
     530    }
     531    RTCritSectLeave(&pThis->CritSect);
     532
     533    return rc;
     534}
     535
     536
     537RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW RWSem)
     538{
     539    struct RTSEMRWINTERNAL *pThis = RWSem;
     540    /*
     541     * Validate handle.
     542     */
     543    if (!rtsemRWValid(pThis))
     544    {
     545        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
     546        return VERR_INVALID_HANDLE;
     547    }
     548
     549    /*
     550     * Check ownership.
     551     */
     552    RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf();
     553    RTTHREAD Writer;
     554    ASMAtomicUoReadSize(&pThis->Writer, &Writer);
     555    return Writer == Self;
     556}
     557
     558
     559RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW RWSem)
     560{
     561    struct RTSEMRWINTERNAL *pThis = RWSem;
     562    /*
     563     * Validate handle.
     564     */
     565    if (!rtsemRWValid(pThis))
     566    {
     567        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
     568        return VERR_INVALID_HANDLE;
     569    }
     570
     571    /*
     572     * Return the requested data.
     573     */
     574    return pThis->cWrites;
     575}
     576
     577
     578RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW RWSem)
     579{
     580    struct RTSEMRWINTERNAL *pThis = RWSem;
     581    /*
     582     * Validate handle.
     583     */
     584    if (!rtsemRWValid(pThis))
     585    {
     586        AssertMsgFailed(("Invalid handle %p!\n", RWSem));
     587        return VERR_INVALID_HANDLE;
     588    }
     589
     590    /*
     591     * Return the requested data.
     592     */
     593    return pThis->cWriterReads;
     594}
Note: See TracChangeset for help on using the changeset viewer.

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