VirtualBox

Changeset 22950 in vbox for trunk/src


Ignore:
Timestamp:
Sep 11, 2009 10:14:54 AM (15 years ago)
Author:
vboxsync
Message:

Runtime/semevent: Fix part I for the Linux-specific RTSemEvent* implementation -- see xtracker 2599

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/linux/semevent-linux.cpp

    r14468 r22950  
    3434/*
    3535 * glibc 2.6 fixed a serious bug in the mutex implementation. We wrote this
    36  * linux specific event semaphores code in order to work around the bug. As it
    37  * turns out, this code seems to have an unresolved issue (#2599), so we'll
    38  * fall back on the pthread based implementation if glibc is known to contain
    39  * the bug fix.
     36 * linux specific event semaphores code in order to work around the bug. We
     37 * will fall back on the pthread-based implementation if glibc is known to
     38 * contain the bug fix.
    4039 *
    4140 * The external refernce to epoll_pwait is a hack which prevents that we link
     
    8281    intptr_t volatile   iMagic;
    8382    /** The futex state variable.
    84      * <0 means signaled.
    85      *  0 means not signaled, no waiters.
    86      * >0 means not signaled, and the value gives the number of waiters.
    87     */
     83     * 0 means not signalled.
     84     * 1 means signalled */
     85    uint32_t volatile   fSignalled;
     86    /** The number of waiting threads */
    8887    int32_t volatile    cWaiters;
    8988};
     
    9392 * Wrapper for the futex syscall.
    9493 */
    95 static long sys_futex(int32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
     94static long sys_futex(uint32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
    9695{
    9796    errno = 0;
     
    117116        pThis->iMagic = RTSEMEVENT_MAGIC;
    118117        pThis->cWaiters = 0;
     118        pThis->fSignalled = 0;
    119119        *pEventSem = pThis;
    120120        return VINF_SUCCESS;
     
    141141    if (ASMAtomicXchgS32(&pThis->cWaiters, INT32_MIN / 2) > 0)
    142142    {
    143         sys_futex(&pThis->cWaiters, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
     143        sys_futex(&pThis->fSignalled, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
    144144        usleep(1000);
    145145    }
     
    161161    AssertReturn(VALID_PTR(pThis) && pThis->iMagic == RTSEMEVENT_MAGIC,
    162162                 VERR_INVALID_HANDLE);
    163     /*
    164      * Try signal it.
    165      */
    166     for (unsigned i = 0;; i++)
    167     {
    168         int32_t iCur;
    169         if (ASMAtomicCmpXchgExS32(&pThis->cWaiters, -1, 0, &iCur))
    170             break; /* nobody is waiting */
    171         else if (iCur < 0)
    172             break; /* already signaled */
    173         else
    174         {
    175             /* somebody is waiting, try wake up one of them. */
    176             long cWoken = sys_futex(&pThis->cWaiters, FUTEX_WAKE, 1, NULL, NULL, 0);
    177             if (RT_LIKELY(cWoken == 1))
    178             {
    179                 ASMAtomicDecS32(&pThis->cWaiters);
    180                 break;
    181             }
    182             AssertMsg(cWoken == 0, ("%ld\n", cWoken));
    183 
    184             /*
    185              * This path is taken in two situations:
    186              *      1) A waiting thread is returning from the sys_futex call with a
    187              *         non-zero return value.
    188              *      2) There are two threads signaling the event at the
    189              *         same time and only one thread waiting.
    190              *
    191              * At this point we know that nobody is activly waiting on the event but
    192              * at the same time, we are racing someone updating the state. The current
    193              * strategy is to spin till the thread racing us is done, this is kind of
    194              * brain dead and need fixing of course.
    195              */
    196             if (RT_UNLIKELY(i > 32))
    197             {
    198                 if ((i % 128) == 127)
    199                     usleep(1000);
    200                 else if (!(i % 4))
    201                     pthread_yield();
    202                 else
    203                     AssertReleaseMsg(i < 4096, ("iCur=%#x pThis=%p\n", iCur, pThis));
    204             }
    205         }
    206 
    207         /* Check the magic to fend off races with RTSemEventDestroy. */
    208         if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENT_MAGIC))
    209             return VERR_SEM_DESTROYED;
    210     }
    211     return VINF_SUCCESS;
     163
     164    ASMAtomicWriteU32(&pThis->fSignalled, 1);
     165    if (ASMAtomicReadS32(&pThis->cWaiters) < 1)
     166        return VINF_SUCCESS;
     167
     168    /* somebody is waiting, try wake up one of them. */
     169    long cWoken = sys_futex(&pThis->fSignalled, FUTEX_WAKE, 1, NULL, NULL, 0);
     170    if (RT_LIKELY(cWoken >= 0))
     171        return VINF_SUCCESS;
     172
     173    if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENT_MAGIC))
     174        return VERR_SEM_DESTROYED;
     175
     176    return VERR_INVALID_PARAMETER;
    212177}
    213178
     
    225190     * Quickly check whether it's signaled.
    226191     */
    227     if (ASMAtomicCmpXchgS32(&pThis->cWaiters, 0, -1))
     192    if (ASMAtomicCmpXchgU32(&pThis->fSignalled, 0, 1))
    228193        return VINF_SUCCESS;
    229194
     
    240205    }
    241206
     207    ASMAtomicIncS32(&pThis->cWaiters);
     208
    242209    /*
    243210     * The wait loop.
    244211     */
    245     for (unsigned i = 0;; i++)
    246     {
    247         /*
    248          * Announce that we're among the waiters.
    249          */
    250         int32_t iNew = ASMAtomicIncS32(&pThis->cWaiters);
    251         if (iNew == 0)
    252             return VINF_SUCCESS;
    253         if (RT_LIKELY(iNew > 0))
    254         {
    255             /*
    256              * Go to sleep.
    257              */
    258             long rc = sys_futex(&pThis->cWaiters, FUTEX_WAIT, iNew, pTimeout, NULL, 0);
    259             if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENT_MAGIC))
    260                 return VERR_SEM_DESTROYED;
    261 
    262             /* Did somebody wake us up from RTSemEventSignal()? */
    263             if (rc == 0)
    264                 return VINF_SUCCESS;
    265 
    266             /* No, then the kernel woke us up or we failed going to sleep. Adjust the accounting. */
    267             iNew = ASMAtomicDecS32(&pThis->cWaiters);
    268             Assert(iNew >= 0);
    269 
    270             /*
    271              * Act on the wakup code.
    272              */
    273             if (rc == -ETIMEDOUT)
     212    int rc = VINF_SUCCESS;
     213    for (;;)
     214    {
     215        long lrc = sys_futex(&pThis->fSignalled, FUTEX_WAIT, 0, pTimeout, NULL, 0);
     216        if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENT_MAGIC))
     217        {
     218            rc = VERR_SEM_DESTROYED;
     219            break;
     220        }
     221
     222        if (RT_LIKELY(lrc == 0 || lrc == -EWOULDBLOCK))
     223        {
     224            /* successful wakeup or fSignalled > 0 in the meantime */
     225            if (ASMAtomicCmpXchgU32(&pThis->fSignalled, 0, 1))
     226                break;
     227        }
     228        else if (lrc == -ETIMEDOUT)
     229        {
     230            rc = VERR_TIMEOUT;
     231            break;
     232        }
     233        else if (lrc == -EINTR)
     234        {
     235            if (!fAutoResume)
    274236            {
    275                 Assert(pTimeout);
    276                 return VERR_TIMEOUT;
     237                rc = VERR_INTERRUPTED;
     238                break;
    277239            }
    278             if (rc == -EWOULDBLOCK)
    279                 /* retry with new value. */;
    280             else if (rc == -EINTR)
    281             {
    282                 if (!fAutoResume)
    283                     return VERR_INTERRUPTED;
    284             }
    285             else
    286             {
    287                 /* this shouldn't happen! */
    288                 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
    289                 return RTErrConvertFromErrno(rc);
    290             }
    291240        }
    292241        else
    293242        {
    294             /* this can't happen. */
    295             if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENT_MAGIC))
    296                 return VERR_SEM_DESTROYED;
    297             AssertReleaseMsgFailed(("iNew=%d\n", iNew));
    298         }
    299     }
     243            /* this shouldn't happen! */
     244            AssertMsgFailed(("rc=%ld errno=%d\n", lrc, errno));
     245            rc = RTErrConvertFromErrno(lrc);
     246            break;
     247        }
     248    }
     249
     250    ASMAtomicDecS32(&pThis->cWaiters);
     251    return rc;
    300252}
    301253
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