VirtualBox

Changeset 92776 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Dec 6, 2021 11:56:21 PM (3 years ago)
Author:
vboxsync
Message:

IPRT/r3/posix: Implemented RTSemEventWaitEx. bugref:10138

Location:
trunk/src/VBox/Runtime/r3/posix
Files:
1 added
2 edited

Legend:

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

    r82968 r92776  
    3737#include <iprt/mem.h>
    3838#include <iprt/lockvalidator.h>
     39#include <iprt/time.h>
    3940
    4041#include "internal/mem.h"
     
    5455# define pthread_yield() sched_yield()
    5556#endif
     57
     58#include "semwait.h"
    5659
    5760
     
    8386    /** The creation flags. */
    8487    uint32_t            fFlags;
     88    /** Set if we're using the monotonic clock. */
     89    bool                fMonotonicClock;
    8590};
    8691
     
    121126         * Create the condition variable.
    122127         */
    123         rc = pthread_cond_init(&pThis->Cond, NULL);
     128        pthread_condattr_t CondAttr;
     129        rc = pthread_condattr_init(&CondAttr);
    124130        if (!rc)
    125131        {
    126             /*
    127              * Create the semaphore.
    128              */
    129             rc = pthread_mutex_init(&pThis->Mutex, NULL);
     132#if defined(CLOCK_MONOTONIC) && defined(IPRT_HAVE_PTHREAD_CONDATTR_SETCLOCK)
     133            /* ASSUMES RTTimeSystemNanoTS() == RTTimeNanoTS() == clock_gettime(CLOCK_MONOTONIC). */
     134            rc = pthread_condattr_setclock(&CondAttr, CLOCK_MONOTONIC);
     135            pThis->fMonotonicClock = rc == 0;
     136#else
     137            pThis->fMonotonicClock = false;
     138#endif
     139            rc = pthread_cond_init(&pThis->Cond, &CondAttr);
    130140            if (!rc)
    131141            {
    132                 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED);
    133                 ASMAtomicWriteU32(&pThis->cWaiters, 0);
    134                 pThis->fFlags = fFlags;
    135 #ifdef RTSEMEVENT_STRICT
    136                 if (!pszNameFmt)
     142                /*
     143                 * Create the semaphore.
     144                 */
     145                rc = pthread_mutex_init(&pThis->Mutex, NULL);
     146                if (!rc)
    137147                {
    138                     static uint32_t volatile s_iSemEventAnon = 0;
    139                     RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
    140                                                  true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL),
    141                                                  "RTSemEvent-%u", ASMAtomicIncU32(&s_iSemEventAnon) - 1);
     148                    pthread_condattr_destroy(&CondAttr);
     149
     150                    ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED);
     151                    ASMAtomicWriteU32(&pThis->cWaiters, 0);
     152                    pThis->fFlags = fFlags;
     153#ifdef RTSEMEVENT_STRICT
     154                    if (!pszNameFmt)
     155                    {
     156                        static uint32_t volatile s_iSemEventAnon = 0;
     157                        RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
     158                                                     true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL),
     159                                                     "RTSemEvent-%u", ASMAtomicIncU32(&s_iSemEventAnon) - 1);
     160                    }
     161                    else
     162                    {
     163                        va_list va;
     164                        va_start(va, pszNameFmt);
     165                        RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
     166                                                      true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL),
     167                                                      pszNameFmt, va);
     168                        va_end(va);
     169                    }
     170                    pThis->fEverHadSignallers = false;
     171#else
     172                    RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt);
     173#endif
     174
     175                    *phEventSem = pThis;
     176                    return VINF_SUCCESS;
    142177                }
    143                 else
    144                 {
    145                     va_list va;
    146                     va_start(va, pszNameFmt);
    147                     RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
    148                                                   true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL),
    149                                                   pszNameFmt, va);
    150                     va_end(va);
    151                 }
    152                 pThis->fEverHadSignallers = false;
    153 #else
    154                 RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt);
    155 #endif
    156 
    157                 *phEventSem = pThis;
    158                 return VINF_SUCCESS;
     178                pthread_cond_destroy(&pThis->Cond);
    159179            }
    160             pthread_cond_destroy(&pThis->Cond);
     180            pthread_condattr_destroy(&CondAttr);
    161181        }
    162182
     
    296316
    297317
    298 DECL_FORCE_INLINE(int) rtSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies, bool fAutoResume)
    299 {
    300 #ifdef RTSEMEVENT_STRICT
    301     PCRTLOCKVALSRCPOS  pSrcPos = NULL;
    302 #endif
    303 
     318/**
     319 * Handle polling (timeout already expired at the time of the call).
     320 *
     321 * @returns VINF_SUCCESS, VERR_TIMEOUT, VERR_SEM_DESTROYED.
     322 * @param   pThis               The semaphore.
     323 */
     324DECLINLINE(int) rtSemEventPosixWaitPoll(struct RTSEMEVENTINTERNAL *pThis)
     325{
     326    int rc = pthread_mutex_lock(&pThis->Mutex);
     327    AssertMsgReturn(!rc, ("Failed to lock event sem %p, rc=%d.\n", pThis, rc), RTErrConvertFromErrno(rc));
     328
     329    uint32_t u32OldState;
     330    bool fSuccess = ASMAtomicCmpXchgExU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED, EVENT_STATE_SIGNALED, &u32OldState);
     331
     332    rc = pthread_mutex_unlock(&pThis->Mutex);
     333    AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", pThis, rc)); NOREF(rc);
     334
     335    return fSuccess
     336         ? VINF_SUCCESS
     337         : u32OldState != EVENT_STATE_UNINITIALIZED
     338         ? VERR_TIMEOUT
     339         : VERR_SEM_DESTROYED;
     340}
     341
     342
     343/**
     344 * Performs an indefinite wait on the event.
     345 */
     346static int rtSemEventPosixWaitIndefinite(struct RTSEMEVENTINTERNAL *pThis, uint32_t fFlags, PCRTLOCKVALSRCPOS pSrcPos)
     347{
     348    RT_NOREF_PV(pSrcPos);
     349
     350    /* for fairness, yield before going to sleep. */
     351    if (    ASMAtomicIncU32(&pThis->cWaiters) > 1
     352        &&  pThis->u32State == EVENT_STATE_SIGNALED)
     353        pthread_yield();
     354
     355     /* take mutex */
     356    int rc = pthread_mutex_lock(&pThis->Mutex);
     357    if (rc)
     358    {
     359        ASMAtomicDecU32(&pThis->cWaiters);
     360        AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", pThis, rc));
     361        return RTErrConvertFromErrno(rc);
     362    }
     363
     364    for (;;)
     365    {
     366        /* check state. */
     367        if (pThis->u32State == EVENT_STATE_SIGNALED)
     368        {
     369            ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED);
     370            ASMAtomicDecU32(&pThis->cWaiters);
     371            rc = pthread_mutex_unlock(&pThis->Mutex);
     372            AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", pThis, rc)); NOREF(rc);
     373            return VINF_SUCCESS;
     374        }
     375        if (pThis->u32State == EVENT_STATE_UNINITIALIZED)
     376        {
     377            rc = pthread_mutex_unlock(&pThis->Mutex);
     378            AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", pThis, rc)); NOREF(rc);
     379            return VERR_SEM_DESTROYED;
     380        }
     381
     382        /* wait */
     383#ifdef RTSEMEVENT_STRICT
     384        RTTHREAD hThreadSelf = !(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)
     385                             ? RTThreadSelfAutoAdopt()
     386                             : RTThreadSelf();
     387        if (pThis->fEverHadSignallers)
     388        {
     389            rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
     390                                                       RT_INDEFINITE_WAIT, RTTHREADSTATE_EVENT, true);
     391            if (RT_FAILURE(rc))
     392            {
     393                ASMAtomicDecU32(&pThis->cWaiters);
     394                pthread_mutex_unlock(&pThis->Mutex);
     395                return rc;
     396            }
     397        }
     398#else
     399        RTTHREAD hThreadSelf = RTThreadSelf();
     400#endif
     401        RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT, true);
     402        RT_NOREF_PV(fFlags); /** @todo interruptible wait is not implementable... */
     403        rc = pthread_cond_wait(&pThis->Cond, &pThis->Mutex);
     404        RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT);
     405        if (rc)
     406        {
     407            AssertMsgFailed(("Failed to wait on event sem %p, rc=%d.\n", pThis, rc));
     408            ASMAtomicDecU32(&pThis->cWaiters);
     409            int rc2 = pthread_mutex_unlock(&pThis->Mutex);
     410            AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", pThis, rc2)); NOREF(rc2);
     411            return RTErrConvertFromErrno(rc);
     412        }
     413    }
     414}
     415
     416
     417/**
     418 * Performs an timed wait on the event.
     419 */
     420static int rtSemEventPosixWaitTimed(struct RTSEMEVENTINTERNAL *pThis, uint32_t fFlags, uint64_t uTimeout,
     421                                    PCRTLOCKVALSRCPOS pSrcPos)
     422{
     423    /*
     424     * Convert the timeout specification to absolute and relative deadlines,
     425     * divierting polling and infinite waits to the appropriate workers.
     426     */
     427    struct timespec AbsDeadline         = { 0, 0 };
     428    uint64_t const  cNsRelativeDeadline = rtSemPosixCalcDeadline(fFlags, uTimeout, pThis->fMonotonicClock, &AbsDeadline);
     429    if (cNsRelativeDeadline == 0)
     430        return rtSemEventPosixWaitPoll(pThis);
     431    if (cNsRelativeDeadline == UINT64_MAX)
     432        return rtSemEventPosixWaitIndefinite(pThis, fFlags, pSrcPos);
     433
     434    /*
     435     * Now to the business of waiting...
     436     */
     437
     438    /* for fairness, yield before going to sleep. */
     439    if (ASMAtomicIncU32(&pThis->cWaiters) > 1)
     440        pthread_yield();
     441
     442    /* take mutex */
     443    int rc = pthread_mutex_lock(&pThis->Mutex);
     444    if (rc)
     445    {
     446        ASMAtomicDecU32(&pThis->cWaiters);
     447        AssertMsg(rc == ETIMEDOUT, ("Failed to lock event sem %p, rc=%d.\n", pThis, rc));
     448        return RTErrConvertFromErrno(rc);
     449    }
     450
     451    for (;;)
     452    {
     453        /* check state. */
     454        uint32_t const u32State = pThis->u32State;
     455        if (u32State != EVENT_STATE_NOT_SIGNALED)
     456        {
     457            if (u32State == EVENT_STATE_SIGNALED)
     458            {
     459                ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED);
     460                ASMAtomicDecU32(&pThis->cWaiters);
     461                rc = VINF_SUCCESS;
     462            }
     463            else
     464            {
     465                Assert(u32State == EVENT_STATE_UNINITIALIZED);
     466                rc = VERR_SEM_DESTROYED;
     467            }
     468            int rc2 = pthread_mutex_unlock(&pThis->Mutex);
     469            AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", pThis, rc2)); RT_NOREF(rc2);
     470            return rc;
     471        }
     472
     473        /* wait */
     474#ifdef RTSEMEVENT_STRICT
     475        RTTHREAD hThreadSelf = !(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)
     476                             ? RTThreadSelfAutoAdopt()
     477                             : RTThreadSelf();
     478        if (pThis->fEverHadSignallers)
     479        {
     480            rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
     481                                                       (cNsRelativeDeadline + RT_NS_1MS - 1) / RT_NS_1MS,
     482                                                       RTTHREADSTATE_EVENT, true);
     483            if (RT_FAILURE(rc))
     484            {
     485                ASMAtomicDecU32(&pThis->cWaiters);
     486                pthread_mutex_unlock(&pThis->Mutex);
     487                return rc;
     488            }
     489        }
     490#else
     491        RTTHREAD hThreadSelf = RTThreadSelf();
     492#endif
     493        RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT, true);
     494        rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &AbsDeadline);
     495        RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT);
     496
     497        /* According to SuS this function shall not return EINTR, but linux man page might have said differently at some point... */
     498        if (   rc != 0
     499            && (   rc != EINTR
     500                || !(fFlags & RTSEMWAIT_FLAGS_NORESUME)))
     501        {
     502            AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event sem %p, rc=%d.\n", pThis, rc));
     503            ASMAtomicDecU32(&pThis->cWaiters);
     504            int rc2 = pthread_mutex_unlock(&pThis->Mutex);
     505            AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", pThis, rc2)); NOREF(rc2);
     506            return RTErrConvertFromErrno(rc);
     507        }
     508    } /* for (;;) */
     509}
     510
     511
     512/**
     513 * Internal wait worker function.
     514 */
     515DECLINLINE(int) rtSemEventPosixWait(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos)
     516{
    304517    /*
    305518     * Validate input.
     
    309522    uint32_t    u32 = pThis->u32State;
    310523    AssertReturn(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED, VERR_INVALID_HANDLE);
     524    AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
    311525
    312526    /*
    313527     * Timed or indefinite wait?
    314528     */
     529    if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
     530        return rtSemEventPosixWaitIndefinite(pThis, fFlags, pSrcPos);
     531    return rtSemEventPosixWaitTimed(hEventSem, fFlags, uTimeout, pSrcPos);
     532}
     533
     534
     535RTDECL(int) RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
     536{
     537    int rc;
     538#ifndef RTSEMEVENT_STRICT
    315539    if (cMillies == RT_INDEFINITE_WAIT)
    316     {
    317         /* for fairness, yield before going to sleep. */
    318         if (    ASMAtomicIncU32(&pThis->cWaiters) > 1
    319             &&  pThis->u32State == EVENT_STATE_SIGNALED)
    320             pthread_yield();
    321 
    322          /* take mutex */
    323         int rc = pthread_mutex_lock(&pThis->Mutex);
    324         if (rc)
    325         {
    326             ASMAtomicDecU32(&pThis->cWaiters);
    327             AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", hEventSem, rc));
    328             return RTErrConvertFromErrno(rc);
    329         }
    330 
    331         for (;;)
    332         {
    333             /* check state. */
    334             if (pThis->u32State == EVENT_STATE_SIGNALED)
    335             {
    336                 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED);
    337                 ASMAtomicDecU32(&pThis->cWaiters);
    338                 rc = pthread_mutex_unlock(&pThis->Mutex);
    339                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc)); NOREF(rc);
    340                 return VINF_SUCCESS;
    341             }
    342             if (pThis->u32State == EVENT_STATE_UNINITIALIZED)
    343             {
    344                 rc = pthread_mutex_unlock(&pThis->Mutex);
    345                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc)); NOREF(rc);
    346                 return VERR_SEM_DESTROYED;
    347             }
    348 
    349             /* wait */
    350 #ifdef RTSEMEVENT_STRICT
    351             RTTHREAD hThreadSelf = !(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)
    352                                  ? RTThreadSelfAutoAdopt()
    353                                  : RTThreadSelf();
    354             if (pThis->fEverHadSignallers)
    355             {
    356                 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
    357                                                            cMillies, RTTHREADSTATE_EVENT, true);
    358                 if (RT_FAILURE(rc))
    359                 {
    360                     ASMAtomicDecU32(&pThis->cWaiters);
    361                     pthread_mutex_unlock(&pThis->Mutex);
    362                     return rc;
    363                 }
    364             }
    365 #else
    366             RTTHREAD hThreadSelf = RTThreadSelf();
    367 #endif
    368             RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT, true);
    369             rc = pthread_cond_wait(&pThis->Cond, &pThis->Mutex);
    370             RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT);
    371             if (rc)
    372             {
    373                 AssertMsgFailed(("Failed to wait on event sem %p, rc=%d.\n", hEventSem, rc));
    374                 ASMAtomicDecU32(&pThis->cWaiters);
    375                 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
    376                 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc2)); NOREF(rc2);
    377                 return RTErrConvertFromErrno(rc);
    378             }
    379         }
    380     }
    381     else
    382     {
    383         /*
    384          * Get current time and calc end of wait time.
    385          */
    386         struct timespec     ts = {0,0};
    387 #if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU)
    388         struct timeval      tv = {0,0};
    389         gettimeofday(&tv, NULL);
    390         ts.tv_sec = tv.tv_sec;
    391         ts.tv_nsec = tv.tv_usec * 1000;
    392 #else
    393         clock_gettime(CLOCK_REALTIME, &ts);
    394 #endif
    395         if (cMillies != 0)
    396         {
    397             ts.tv_nsec += (cMillies % 1000) * 1000000;
    398             ts.tv_sec  += cMillies / 1000;
    399             if (ts.tv_nsec >= 1000000000)
    400             {
    401                 ts.tv_nsec -= 1000000000;
    402                 ts.tv_sec++;
    403             }
    404         }
    405 
    406         /* for fairness, yield before going to sleep. */
    407         if (ASMAtomicIncU32(&pThis->cWaiters) > 1 && cMillies)
    408             pthread_yield();
    409 
    410         /* take mutex */
    411         int rc = pthread_mutex_lock(&pThis->Mutex);
    412         if (rc)
    413         {
    414             ASMAtomicDecU32(&pThis->cWaiters);
    415             AssertMsg(rc == ETIMEDOUT, ("Failed to lock event sem %p, rc=%d.\n", hEventSem, rc));
    416             return RTErrConvertFromErrno(rc);
    417         }
    418 
    419         for (;;)
    420         {
    421             /* check state. */
    422             if (pThis->u32State == EVENT_STATE_SIGNALED)
    423             {
    424                 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED);
    425                 ASMAtomicDecU32(&pThis->cWaiters);
    426                 rc = pthread_mutex_unlock(&pThis->Mutex);
    427                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc)); NOREF(rc);
    428                 return VINF_SUCCESS;
    429             }
    430             if (pThis->u32State == EVENT_STATE_UNINITIALIZED)
    431             {
    432                 rc = pthread_mutex_unlock(&pThis->Mutex);
    433                 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc)); NOREF(rc);
    434                 return VERR_SEM_DESTROYED;
    435             }
    436 
    437             /* we're done if the timeout is 0. */
    438             if (!cMillies)
    439             {
    440                 ASMAtomicDecU32(&pThis->cWaiters);
    441                 rc = pthread_mutex_unlock(&pThis->Mutex);
    442                 return VERR_TIMEOUT;
    443             }
    444 
    445             /* wait */
    446 #ifdef RTSEMEVENT_STRICT
    447             RTTHREAD hThreadSelf = !(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)
    448                                  ? RTThreadSelfAutoAdopt()
    449                                  : RTThreadSelf();
    450             if (pThis->fEverHadSignallers)
    451             {
    452                 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
    453                                                            cMillies, RTTHREADSTATE_EVENT, true);
    454                 if (RT_FAILURE(rc))
    455                 {
    456                     ASMAtomicDecU32(&pThis->cWaiters);
    457                     pthread_mutex_unlock(&pThis->Mutex);
    458                     return rc;
    459                 }
    460             }
    461 #else
    462             RTTHREAD hThreadSelf = RTThreadSelf();
    463 #endif
    464             RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT, true);
    465             rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &ts);
    466             RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT);
    467             if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
    468             {
    469                 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event sem %p, rc=%d.\n", hEventSem, rc));
    470                 ASMAtomicDecU32(&pThis->cWaiters);
    471                 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
    472                 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", hEventSem, rc2)); NOREF(rc2);
    473                 return RTErrConvertFromErrno(rc);
    474             }
    475         } /* for (;;) */
    476     }
    477 }
    478 
    479 
    480 RTDECL(int)  RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
    481 {
    482     int rc = rtSemEventWait(hEventSem, cMillies, true);
     540        rc = rtSemEventPosixWait(hEventSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0, NULL);
     541    else
     542        rc = rtSemEventPosixWait(hEventSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_MILLISECS,
     543                                 cMillies, NULL);
     544#else
     545    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
     546    if (cMillies == RT_INDEFINITE_WAIT)
     547        rc = rtSemEventPosixWait(hEventSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0, &SrcPos);
     548    else
     549        rc = rtSemEventPosixWait(hEventSem, RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_MILLISECS,
     550                                 cMillies, &SrcPos);
     551#endif
    483552    Assert(rc != VERR_INTERRUPTED);
    484553    return rc;
     
    488557RTDECL(int)  RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
    489558{
    490     return rtSemEventWait(hEventSem, cMillies, false);
     559    int rc;
     560#ifndef RTSEMEVENT_STRICT
     561    if (cMillies == RT_INDEFINITE_WAIT)
     562        rc = rtSemEventPosixWait(hEventSem, RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0, NULL);
     563    else
     564        rc = rtSemEventPosixWait(hEventSem, RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_MILLISECS,
     565                                 cMillies, NULL);
     566#else
     567    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
     568    if (cMillies == RT_INDEFINITE_WAIT)
     569        rc = rtSemEventPosixWait(hEventSem, RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0, &SrcPos);
     570    else
     571        rc = rtSemEventPosixWait(hEventSem, RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_MILLISECS,
     572                                 cMillies, &SrcPos);
     573#endif
     574    Assert(rc != VERR_INTERRUPTED);
     575    return rc;
     576}
     577
     578
     579RTDECL(int)  RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout)
     580{
     581#ifndef RTSEMEVENT_STRICT
     582    return rtSemEventPosixWait(hEventSem, fFlags, uTimeout, NULL);
     583#else
     584    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
     585    return rtSemEventPosixWait(hEventSem, fFlags, uTimeout, &SrcPos);
     586#endif
     587}
     588
     589
     590RTDECL(int)  RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout,
     591                                   RTHCUINTPTR uId, RT_SRC_POS_DECL)
     592{
     593    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
     594    return rtSemEventPosixWait(hEventSem, fFlags, uTimeout, &SrcPos);
     595}
     596
     597
     598RTDECL(uint32_t) RTSemEventGetResolution(void)
     599{
     600    /** @todo we have 1ns parameter resolution, but we need to check each host
     601     *        what the actual resolution might be once the parameter makes it to the
     602     *        kernel and is processed there. */
     603    return 1;
    491604}
    492605
  • trunk/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp

    r88294 r92776  
    4646#include <sys/time.h>
    4747
    48 
    49 /*********************************************************************************************************************************
    50 *   Defined Constants And Macros                                                                                                 *
    51 *********************************************************************************************************************************/
    52 /** @def IPRT_HAVE_PTHREAD_CONDATTR_SETCLOCK
    53  * Set if the platform implements pthread_condattr_setclock().
    54  * Enables the use of the monotonic clock for waiting on condition variables. */
    55 #ifndef IPRT_HAVE_PTHREAD_CONDATTR_SETCLOCK
    56 /* Linux detection */
    57 # if defined(RT_OS_LINUX) && defined(__USE_XOPEN2K)
    58 #  include <features.h>
    59 #  if __GLIBC_PREREQ(2,6) /** @todo figure the exact version where this was added */
    60 #   define IPRT_HAVE_PTHREAD_CONDATTR_SETCLOCK
    61 #  endif
    62 # endif
    63 /** @todo check other platforms */
    64 #endif
     48#include "semwait.h"
    6549
    6650
     
    147131                    pthread_condattr_destroy(&CondAttr);
    148132
    149                     ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED);
    150                     ASMAtomicXchgU32(&pThis->cWaiters, 0);
     133                    ASMAtomicWriteU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED);
     134                    ASMAtomicWriteU32(&pThis->cWaiters, 0);
    151135#ifdef RTSEMEVENTMULTI_STRICT
    152136                    if (!pszNameFmt)
     
    179163            pthread_condattr_destroy(&CondAttr);
    180164        }
    181 
    182165        rc = RTErrConvertFromErrno(rc);
    183166        RTMemFree(pThis);
     
    454437{
    455438    /*
    456      * Convert uTimeout to a relative value in nano seconds.
    457      */
    458     if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
    459         uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000)
    460                  ? uTimeout * UINT32_C(1000000)
    461                  : UINT64_MAX;
    462     if (uTimeout == UINT64_MAX) /* unofficial way of indicating an indefinite wait */
     439     * Convert the timeout specification to absolute and relative deadlines,
     440     * divierting polling and infinite waits to the appropriate workers.
     441     */
     442    struct timespec AbsDeadline         = { 0, 0 };
     443    uint64_t const  cNsRelativeDeadline = rtSemPosixCalcDeadline(fFlags, uTimeout, pThis->fMonotonicClock, &AbsDeadline);
     444    if (cNsRelativeDeadline == 0)
     445        return rtSemEventMultiPosixWaitPoll(pThis);
     446    if (cNsRelativeDeadline == UINT64_MAX)
    463447        return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos);
    464 
    465     uint64_t uAbsTimeout = uTimeout;
    466     if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)
    467     {
    468         uint64_t u64Now = RTTimeSystemNanoTS();
    469         uTimeout = uTimeout > u64Now ? uTimeout - u64Now : 0;
    470     }
    471 
    472     if (uTimeout == 0)
    473         return rtSemEventMultiPosixWaitPoll(pThis);
    474 
    475     /*
    476      * Get current time and calc end of deadline relative to real time.
    477      */
    478     struct timespec     ts = {0,0};
    479     if (!pThis->fMonotonicClock)
    480     {
    481 #if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU)
    482         struct timeval  tv = {0,0};
    483         gettimeofday(&tv, NULL);
    484         ts.tv_sec = tv.tv_sec;
    485         ts.tv_nsec = tv.tv_usec * 1000;
    486 #else
    487         clock_gettime(CLOCK_REALTIME, &ts);
    488 #endif
    489         struct timespec tsAdd;
    490         tsAdd.tv_nsec = uTimeout % UINT32_C(1000000000);
    491         tsAdd.tv_sec  = uTimeout / UINT32_C(1000000000);
    492         if (   sizeof(ts.tv_sec) < sizeof(uint64_t)
    493             && (   uTimeout > UINT64_C(1000000000) * UINT32_MAX
    494                 || (uint64_t)ts.tv_sec + tsAdd.tv_sec >= UINT32_MAX) )
    495             return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos);
    496 
    497         ts.tv_sec  += tsAdd.tv_sec;
    498         ts.tv_nsec += tsAdd.tv_nsec;
    499         if (ts.tv_nsec >= 1000000000)
    500         {
    501             ts.tv_nsec -= 1000000000;
    502             ts.tv_sec++;
    503         }
    504         /* Note! No need to complete uAbsTimeout for RTSEMWAIT_FLAGS_RELATIVE in this path. */
    505     }
    506     else
    507     {
    508         /* ASSUMES RTTimeSystemNanoTS() == RTTimeNanoTS() == clock_gettime(CLOCK_MONOTONIC). */
    509         if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
    510             uAbsTimeout += RTTimeSystemNanoTS();
    511         if (   sizeof(ts.tv_sec) < sizeof(uint64_t)
    512             && uAbsTimeout > UINT64_C(1000000000) * UINT32_MAX)
    513             return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos);
    514         ts.tv_nsec = uAbsTimeout % UINT32_C(1000000000);
    515         ts.tv_sec  = uAbsTimeout / UINT32_C(1000000000);
    516     }
    517448
    518449    /*
     
    544475        {
    545476            rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
    546                                                        uTimeout / UINT32_C(1000000), RTTHREADSTATE_EVENT_MULTI, true);
     477                                                       (uTimeout + RT_NS_1MS - 1)/ RT_NS_1MS, RTTHREADSTATE_EVENT_MULTI, true);
    547478            if (RT_FAILURE(rc))
    548479            {
     
    556487#endif
    557488        RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
    558         rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &ts);
     489        rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &AbsDeadline);
    559490        RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
    560         if (    rc
    561             && (   rc != EINTR  /* according to SuS this function shall not return EINTR, but linux man page says differently. */
     491
     492        /* According to SuS this function shall not return EINTR, but linux man page might have said differently at some point... */
     493        if (    rc != 0
     494            && (   rc != EINTR
    562495                || (fFlags & RTSEMWAIT_FLAGS_NORESUME)) )
    563496        {
     
    568501            return RTErrConvertFromErrno(rc);
    569502        }
    570 
    571         /* check the absolute deadline. */
    572503    }
    573504}
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