VirtualBox

Changeset 7920 in vbox


Ignore:
Timestamp:
Apr 11, 2008 2:40:22 PM (17 years ago)
Author:
vboxsync
Message:

Adjusted the RTSemRW interface to do recursion. Updated the posix implementation to reflect this.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/semaphore.h

    r5999 r7920  
    267267 * Request read access to a read/write semaphore, resume on interruption
    268268 *
    269  * Read requests cannot be nested. A deadlock error will be returned
    270  * on such attempts.
    271  *
    272  * @returns iprt status code.
    273  *          Will not return VERR_INTERRUPTED.
     269 * @returns iprt status code.
     270 * @retval  VINF_SUCCESS on success.
     271 * @retval  VERR_INTERRUPT if the wait was interrupted.
     272 * @retval  VERR_INVALID_HANDLE if RWSem is invalid.
     273 *
    274274 * @param   RWSem       The Read/Write semaphore to request read access to.
    275275 * @param   cMillies    The number of milliseconds to wait.
     
    280280 * Request read access to a read/write semaphore, return on interruption
    281281 *
    282  * Read requests cannot be nested. A deadlock error will be returned
    283  * on such attempts.
    284  *
    285  * @returns iprt status code.
     282 * @returns iprt status code.
     283 * @retval  VINF_SUCCESS on success.
     284 * @retval  VERR_INTERRUPT if the wait was interrupted.
     285 * @retval  VERR_INVALID_HANDLE if RWSem is invalid.
     286 *
    286287 * @param   RWSem       The Read/Write semaphore to request read access to.
    287288 * @param   cMillies    The number of milliseconds to wait.
     
    301302 * Request write access to a read/write semaphore, resume on interruption.
    302303 *
    303  * Write requests cannot be nested. If called by the thread currently owning
    304  * the write lock the function returns an error code indicating deadlock.
    305  *
    306  * @returns iprt status code.
    307  *          Will not return VERR_INTERRUPTED.
     304 * @returns iprt status code.
     305 * @retval  VINF_SUCCESS on success.
     306 * @retval  VERR_DEADLOCK if the caller owned the read lock.
     307 * @retval  VERR_INVALID_HANDLE if RWSem is invalid.
     308 *
    308309 * @param   RWSem       The Read/Write semaphore to request write access to.
    309310 * @param   cMillies    The number of milliseconds to wait.
     
    314315 * Request write access to a read/write semaphore, return on interruption.
    315316 *
    316  * Write requests cannot be nested. If called by the thread currently owning
    317  * the write lock the function returns an error code indicating deadlock.
    318  *
    319  * @returns iprt status code.
     317 * @returns iprt status code.
     318 * @retval  VINF_SUCCESS on success.
     319 * @retval  VERR_INTERRUPT if the wait was interrupted.
     320 * @retval  VERR_DEADLOCK if the caller owned the read lock.
     321 * @retval  VERR_INVALID_HANDLE if RWSem is invalid.
     322 *
    320323 * @param   RWSem       The Read/Write semaphore to request write access to.
    321324 * @param   cMillies    The number of milliseconds to wait.
  • trunk/src/VBox/Runtime/r3/posix/semrw-posix.cpp

    r6738 r7920  
    3939#include <sys/time.h>
    4040
     41#include "internal/magics.h"
     42
    4143
    4244/*******************************************************************************
     
    4648struct RTSEMRWINTERNAL
    4749{
     50    /** The usual magic. (RTSEMRW_MAGIC) */
     51    uint32_t            u32Magic;
     52    /* Alignment padding. */
     53    uint32_t            u32Padding;
     54    /** Number of write recursions. */
     55    uint32_t            cWrites;
     56    /** Number of read recursions by the writer. */
     57    uint32_t            cWriterReads;
     58    /** The write owner of the lock. */
     59    volatile pthread_t  Writer;
    4860    /** pthread rwlock. */
    4961    pthread_rwlock_t    RWLock;
    50     /** Variable to check if initialized.
    51      * 0 is uninitialized, ~0 is inititialized. */
    52     volatile unsigned   uCheck;
    53     /** The write owner of the lock. */
    54     volatile pthread_t  WROwner;
    5562};
    5663
    5764
    58 
    59 /**
    60  * Validate a read-write semaphore handle passed to one of the interface.
    61  *
    62  * @returns true if valid.
    63  * @returns false if invalid.
    64  * @param   pIntRWSem   Pointer to the read-write semaphore to validate.
    65  */
    66 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
    67 {
    68     if ((uintptr_t)pIntRWSem < 0x10000)
    69         return false;
    70 
    71     if (pIntRWSem->uCheck != (unsigned)~0)
    72         return false;
    73 
    74     return true;
    75 }
    76 
    77 
    78 RTDECL(int)   RTSemRWCreate(PRTSEMRW pRWSem)
     65RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)
    7966{
    8067    int rc;
     
    8370     * Allocate handle.
    8471     */
    85     struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
    86     if (pIntRWSem)
     72    struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
     73    if (pThis)
    8774    {
    8875        /*
    8976         * Create the rwlock.
    9077         */
    91         pthread_rwlockattr_t    Attr;
     78        pthread_rwlockattr_t Attr;
    9279        rc = pthread_rwlockattr_init(&Attr);
    9380        if (!rc)
    9481        {
    95             rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);
     82            rc = pthread_rwlock_init(&pThis->RWLock, &Attr);
    9683            if (!rc)
    9784            {
    98                 pIntRWSem->uCheck = ~0;
    99                 pIntRWSem->WROwner = (pthread_t)-1;
    100                 *pRWSem = pIntRWSem;
     85                pThis->u32Magic = RTSEMRW_MAGIC;
     86                pThis->u32Padding = 0;
     87                pThis->cWrites = 0;
     88                pThis->cWriterReads = 0;
     89                pThis->Writer = (pthread_t)-1;
     90                *pRWSem = pThis;
    10191                return VINF_SUCCESS;
    10292            }
     
    10494
    10595        rc = RTErrConvertFromErrno(rc);
    106         RTMemFree(pIntRWSem);
     96        RTMemFree(pThis);
    10797    }
    10898    else
     
    113103
    114104
    115 RTDECL(int)   RTSemRWDestroy(RTSEMRW RWSem)
    116 {
    117     /*
    118      * Validate input.
    119      */
    120     if (!rtsemRWValid(RWSem))
    121     {
    122         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    123         return VERR_INVALID_HANDLE;
    124     }
     105RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)
     106{
     107    /*
     108     * Validate input, nil handle is fine.
     109     */
     110    if (RWSem == NIL_RTSEMRW)
     111        return VINF_SUCCESS;
     112    struct RTSEMRWINTERNAL *pThis = RWSem;
     113    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     114    AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
     115                    ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
     116                    VERR_INVALID_HANDLE);
     117    Assert(pThis->Writer == (pthread_t)-1);
     118    Assert(!pThis->cWrites);
     119    Assert(!pThis->cWriterReads);
    125120
    126121    /*
    127122     * Try destroy it.
    128123     */
    129     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    130     int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);
     124    int rc = pthread_rwlock_destroy(&pThis->RWLock);
    131125    if (!rc)
    132126    {
    133         pIntRWSem->uCheck = 0;
    134         RTMemFree(pIntRWSem);
     127        pThis->u32Magic++;
     128        RTMemFree(pThis);
    135129        rc = VINF_SUCCESS;
    136130    }
     
    145139
    146140
    147 RTDECL(int)   RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
     141RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
    148142{
    149143    /*
    150144     * Validate input.
    151145     */
    152     if (!rtsemRWValid(RWSem))
    153     {
    154         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    155         return VERR_INVALID_HANDLE;
     146    struct RTSEMRWINTERNAL *pThis = RWSem;
     147    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     148    AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
     149                    ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
     150                    VERR_INVALID_HANDLE);
     151
     152    /*
     153     * Check if it's the writer (implement write+read recursion).
     154     */
     155    pthread_t Self = pthread_self();
     156    pthread_t Writer;
     157    ASMAtomicReadSize(&pThis->Writer, &Writer);
     158    if (Writer == Self)
     159    {
     160        Assert(pThis->cWriterReads < INT32_MAX);
     161        pThis->cWriterReads++;
     162        return VINF_SUCCESS;
    156163    }
    157164
     
    159166     * Try lock it.
    160167     */
    161     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    162168    if (cMillies == RT_INDEFINITE_WAIT)
    163169    {
    164170        /* take rwlock */
    165         int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);
     171        int rc = pthread_rwlock_rdlock(&pThis->RWLock);
    166172        if (rc)
    167173        {
    168174            AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
     175            return RTErrConvertFromErrno(rc);
     176        }
     177    }
     178    else
     179    {
     180#ifdef RT_OS_DARWIN
     181        AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
     182        return VERR_NOT_IMPLEMENTED;
     183
     184#else /* !RT_OS_DARWIN */
     185        /*
     186         * Get current time and calc end of wait time.
     187         */
     188        struct timespec     ts = {0,0};
     189        clock_gettime(CLOCK_REALTIME, &ts);
     190        if (cMillies != 0)
     191        {
     192            ts.tv_nsec += (cMillies % 1000) * 1000000;
     193            ts.tv_sec  += cMillies / 1000;
     194            if (ts.tv_nsec >= 1000000000)
     195            {
     196                ts.tv_nsec -= 1000000000;
     197                ts.tv_sec++;
     198            }
     199        }
     200
     201        /* take rwlock */
     202        int rc = pthread_rwlock_timedrdlock(&pThis->RWLock, &ts);
     203        if (rc)
     204        {
     205            AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
     206            return RTErrConvertFromErrno(rc);
     207        }
     208#endif /* !RT_OS_DARWIN */
     209    }
     210
     211    return VINF_SUCCESS;
     212}
     213
     214
     215RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
     216{
     217    /* EINTR isn't returned by the wait functions we're using. */
     218    return RTSemRWRequestRead(RWSem, cMillies);
     219}
     220
     221
     222RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
     223{
     224    /*
     225     * Validate input.
     226     */
     227    struct RTSEMRWINTERNAL *pThis = RWSem;
     228    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     229    AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
     230                    ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
     231                    VERR_INVALID_HANDLE);
     232
     233    /*
     234     * Check if it's the writer.
     235     */
     236    pthread_t Self = pthread_self();
     237    pthread_t Writer;
     238    ASMAtomicReadSize(&pThis->Writer, &Writer);
     239    if (Writer == Self)
     240    {
     241        AssertMsgReturn(pThis->cWriterReads > 0,
     242                        ("pThis=%p\n", pThis), VERR_NOT_OWNER);
     243        pThis->cWriterReads--;
     244        return VINF_SUCCESS;
     245    }
     246
     247    /*
     248     * Try unlock it.
     249     */
     250    int rc = pthread_rwlock_unlock(&pThis->RWLock);
     251    if (rc)
     252    {
     253        AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
     254        return RTErrConvertFromErrno(rc);
     255    }
     256
     257    return VINF_SUCCESS;
     258}
     259
     260
     261RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
     262{
     263    /*
     264     * Validate input.
     265     */
     266    struct RTSEMRWINTERNAL *pThis = RWSem;
     267    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     268    AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
     269                    ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
     270                    VERR_INVALID_HANDLE);
     271
     272    /*
     273     * Recursion?
     274     */
     275    pthread_t Self = pthread_self();
     276    pthread_t Writer;
     277    ASMAtomicReadSize(&pThis->Writer, &Writer);
     278    if (Writer == Self)
     279    {
     280        Assert(pThis->cWrites < INT32_MAX);
     281        pThis->cWrites++;
     282        return VINF_SUCCESS;
     283    }
     284
     285    /*
     286     * Try lock it.
     287     */
     288    if (cMillies == RT_INDEFINITE_WAIT)
     289    {
     290        /* take rwlock */
     291        int rc = pthread_rwlock_wrlock(&pThis->RWLock);
     292        if (rc)
     293        {
     294            AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
    169295            return RTErrConvertFromErrno(rc);
    170296        }
     
    193319
    194320        /* take rwlock */
    195         int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);
     321        int rc = pthread_rwlock_timedwrlock(&pThis->RWLock, &ts);
    196322        if (rc)
    197323        {
     
    202328    }
    203329
     330    ASMAtomicWriteSize(&pThis->Writer, Self);
     331    pThis->cWrites = 1;
    204332    return VINF_SUCCESS;
    205333}
    206334
    207335
    208 RTDECL(int)   RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
    209 {
    210     /* EINTR isn't returned by the wait functions we're using. */
    211     return RTSemRWRequestRead(RWSem, cMillies);
    212 }
    213 
    214 
    215 RTDECL(int)   RTSemRWReleaseRead(RTSEMRW RWSem)
    216 {
    217     /*
    218      * Validate input.
    219      */
    220     if (!rtsemRWValid(RWSem))
    221     {
    222         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    223         return VERR_INVALID_HANDLE;
    224     }
    225 
    226     /*
    227      * Try unlock it.
    228      */
    229     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    230     if (pIntRWSem->WROwner == pthread_self())
    231     {
    232         AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));
    233         return VERR_NOT_OWNER;
    234     }
    235     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
    236     if (rc)
    237     {
    238         AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
    239         return RTErrConvertFromErrno(rc);
    240     }
    241 
    242     return VINF_SUCCESS;
    243 }
    244 
    245 
    246 RTDECL(int)   RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
    247 {
    248     /*
    249      * Validate input.
    250      */
    251     if (!rtsemRWValid(RWSem))
    252     {
    253         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    254         return VERR_INVALID_HANDLE;
    255     }
    256 
    257     /*
    258      * Try lock it.
    259      */
    260     struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
    261     if (cMillies == RT_INDEFINITE_WAIT)
    262     {
    263         /* take rwlock */
    264         int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);
    265         if (rc)
    266         {
    267             AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
    268             return RTErrConvertFromErrno(rc);
    269         }
    270     }
    271     else
    272     {
    273 #ifdef RT_OS_DARWIN
    274         AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
    275         return VERR_NOT_IMPLEMENTED;
    276 #else /* !RT_OS_DARWIN */
    277         /*
    278          * Get current time and calc end of wait time.
    279          */
    280         struct timespec     ts = {0,0};
    281         clock_gettime(CLOCK_REALTIME, &ts);
    282         if (cMillies != 0)
    283         {
    284             ts.tv_nsec += (cMillies % 1000) * 1000000;
    285             ts.tv_sec  += cMillies / 1000;
    286             if (ts.tv_nsec >= 1000000000)
    287             {
    288                 ts.tv_nsec -= 1000000000;
    289                 ts.tv_sec++;
    290             }
    291         }
    292 
    293         /* take rwlock */
    294         int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);
    295         if (rc)
    296         {
    297             AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
    298             return RTErrConvertFromErrno(rc);
    299         }
    300 #endif /* !RT_OS_DARWIN */
    301     }
    302 
    303 #ifdef RT_OS_SOLARIS
    304     ASMAtomicXchgSize(&pIntRWSem->WROwner, pthread_self());
    305 #else
    306     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());
    307 #endif
    308 
    309     return VINF_SUCCESS;
    310 }
    311 
    312 
    313 RTDECL(int)   RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
     336RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
    314337{
    315338    /* EINTR isn't returned by the wait functions we're using. */
     
    318341
    319342
    320 RTDECL(int)   RTSemRWReleaseWrite(RTSEMRW RWSem)
     343RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
    321344{
    322345    /*
    323346     * Validate input.
    324347     */
    325     if (!rtsemRWValid(RWSem))
    326     {
    327         AssertMsgFailed(("Invalid handle %p!\n", RWSem));
    328         return VERR_INVALID_HANDLE;
    329     }
     348    struct RTSEMRWINTERNAL *pThis = RWSem;
     349    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     350    AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
     351                    ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
     352                    VERR_INVALID_HANDLE);
     353
     354    /*
     355     * Verify ownership and implement recursion.
     356     */
     357    pthread_t Self = pthread_self();
     358    pthread_t Writer;
     359    ASMAtomicReadSize(&pThis->Writer, &Writer);
     360    AssertMsgReturn(Writer == Self, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
     361    pThis->cWrites--;
     362    if (pThis->cWrites)
     363        return VINF_SUCCESS;
     364    AssertReturn(!pThis->cWriterReads, VERR_WRONG_ORDER);
    330365
    331366    /*
    332367     * Try unlock it.
    333368     */
    334     pthread_t                 Self = pthread_self();
    335     struct RTSEMRWINTERNAL   *pIntRWSem = RWSem;
    336     if (pIntRWSem->WROwner != Self)
    337     {
    338         AssertMsgFailed(("Not Write owner!\n"));
    339         return VERR_NOT_OWNER;
    340     }
    341 
    342     /*
    343      * Try unlock it.
    344      */
    345 #ifdef RT_OS_SOLARIS
    346     ASMAtomicXchgSize(&pIntRWSem->WROwner, (pthread_t)-1);
    347 #else
    348     AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));
    349     ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(pthread_t)-1);
    350 #endif
    351     int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
     369    ASMAtomicWriteSize(&pThis->Writer, (pthread_t)-1);
     370    int rc = pthread_rwlock_unlock(&pThis->RWLock);
    352371    if (rc)
    353372    {
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