VirtualBox

Changeset 92782 in vbox for trunk/src/VBox/Runtime/r3/linux


Ignore:
Timestamp:
Dec 7, 2021 10:58:17 AM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
148700
Message:

IPRT/semevent*-linux: Share more code between the single-release and multiple-release linux event sempahore code. bugref:10138

Location:
trunk/src/VBox/Runtime/r3/linux
Files:
3 edited

Legend:

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

    r92779 r92782  
    134134    if (pThis)
    135135    {
    136         pThis->iMagic = RTSEMEVENT_MAGIC;
    137         pThis->cWaiters = 0;
     136        pThis->iMagic     = RTSEMEVENT_MAGIC;
     137        pThis->cWaiters   = 0;
    138138        pThis->fSignalled = 0;
    139         pThis->fFlags = fFlags;
     139        pThis->fFlags     = fFlags;
    140140#ifdef RTSEMEVENT_STRICT
    141141        if (!pszNameFmt)
     
    318318
    319319
     320/**
     321 * Handle polling (timeout already expired at the time of the call).
     322 *
     323 * @returns VINF_SUCCESS, VERR_TIMEOUT, VERR_SEM_DESTROYED.
     324 * @param   pThis               The semaphore.
     325 */
    320326static int rtSemEventLinuxWaitPoll(struct RTSEMEVENTINTERNAL *pThis)
    321327{
     
    332338
    333339
     340/**
     341 * Performs an timed wait on the event.
     342 */
    334343static int rtSemEventLinuxWaitTimed(struct RTSEMEVENTINTERNAL *pThis, uint32_t fFlags,
    335344                                    uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos)
     
    340349     * Convert the timeout value.
    341350     */
    342     int       iWaitOp;
    343     uint32_t  uWaitVal3;
    344     timespec  TsTimeout;
    345     uint64_t  uAbsTimeout = uTimeout;  /* Note! only relevant for relative waits (FUTEX_WAIT). */
    346     if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
    347     {
    348         if (!uTimeout)
    349             return rtSemEventLinuxWaitPoll(pThis);
    350 
    351         if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
    352         {
    353             if (   sizeof(TsTimeout.tv_sec) >= sizeof(uint64_t)
    354                 || uTimeout < (uint64_t)UINT32_MAX * RT_MS_1SEC)
    355             {
    356                 TsTimeout.tv_sec  = uTimeout / RT_MS_1SEC;
    357                 TsTimeout.tv_nsec = (uTimeout % RT_MS_1SEC) & RT_NS_1MS;
    358                 uAbsTimeout      *= RT_NS_1MS;
    359             }
    360             else
    361                 return rtSemEventLinuxWaitIndefinite(pThis, fFlags, pSrcPos);
    362         }
    363         else
    364         {
    365             Assert(fFlags & RTSEMWAIT_FLAGS_NANOSECS);
    366             if (   sizeof(TsTimeout.tv_sec) >= sizeof(uint64_t)
    367                 || uTimeout < (uint64_t)UINT32_MAX * RT_NS_1SEC)
    368             {
    369                 TsTimeout.tv_sec  = uTimeout / RT_NS_1SEC;
    370                 TsTimeout.tv_nsec = uTimeout % RT_NS_1SEC;
    371             }
    372             else
    373                 return rtSemEventLinuxWaitIndefinite(pThis, fFlags, pSrcPos);
    374         }
    375 
    376         if (fFlags & RTSEMWAIT_FLAGS_RESUME)
    377             uAbsTimeout += RTTimeNanoTS();
    378 
    379         iWaitOp   = FUTEX_WAIT;
    380         uWaitVal3 = 0;
    381     }
    382     else
    383     {
    384         /* Absolute deadline: */
    385         Assert(fFlags & RTSEMWAIT_FLAGS_ABSOLUTE);
    386         if (g_fCanUseWaitBitSet == true)
    387         {
    388             if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
    389             {
    390                 if (   sizeof(TsTimeout.tv_sec) >= sizeof(uint64_t)
    391                     || uTimeout < (uint64_t)UINT32_MAX * RT_MS_1SEC)
    392                 {
    393                     TsTimeout.tv_sec  = uTimeout / RT_MS_1SEC;
    394                     TsTimeout.tv_nsec = (uTimeout % RT_MS_1SEC) & RT_NS_1MS;
    395                 }
    396                 else
    397                     return rtSemEventLinuxWaitIndefinite(pThis, fFlags, pSrcPos);
    398             }
    399             else
    400             {
    401                 Assert(fFlags & RTSEMWAIT_FLAGS_NANOSECS);
    402                 if (   sizeof(TsTimeout.tv_sec) >= sizeof(uint64_t)
    403                     || uTimeout < (uint64_t)UINT32_MAX * RT_NS_1SEC)
    404                 {
    405                     TsTimeout.tv_sec  = uTimeout / RT_NS_1SEC;
    406                     TsTimeout.tv_nsec = uTimeout % RT_NS_1SEC;
    407                 }
    408                 else
    409                     return rtSemEventLinuxWaitIndefinite(pThis, fFlags, pSrcPos);
    410             }
    411             iWaitOp   = FUTEX_WAIT_BITSET;
    412             uWaitVal3 = UINT32_MAX;
    413         }
    414         else
    415         {
    416             /* Recalculate it as an relative timeout: */
    417             if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
    418             {
    419                 if (uTimeout < UINT64_MAX / RT_NS_1MS)
    420                     uAbsTimeout = uTimeout *= RT_NS_1MS;
    421                 else
    422                     return rtSemEventLinuxWaitIndefinite(pThis, fFlags, pSrcPos);
    423             }
    424 
    425             uint64_t const u64Now = RTTimeNanoTS();
    426             if (u64Now < uTimeout)
    427                 uTimeout -= u64Now;
    428             else
    429                 return rtSemEventLinuxWaitPoll(pThis);
    430 
    431             if (   sizeof(TsTimeout.tv_sec) >= sizeof(uint64_t)
    432                 || uTimeout < (uint64_t)UINT32_MAX * RT_NS_1SEC)
    433             {
    434                 TsTimeout.tv_sec  = uTimeout / RT_NS_1SEC;
    435                 TsTimeout.tv_nsec = uTimeout % RT_NS_1SEC;
    436             }
    437             else
    438                 return rtSemEventLinuxWaitIndefinite(pThis, fFlags, pSrcPos);
    439 
    440             iWaitOp   = FUTEX_WAIT;
    441             uWaitVal3 = 0;
    442         }
    443     }
     351    struct timespec TsTimeout;
     352    int             iWaitOp;
     353    uint32_t        uWaitVal3;
     354    uint64_t        nsAbsTimeout;
     355    uTimeout = rtSemLinuxCalcDeadline(fFlags, uTimeout, g_fCanUseWaitBitSet, &TsTimeout, &iWaitOp, &uWaitVal3, &nsAbsTimeout);
     356    if (uTimeout == 0)
     357        return rtSemEventLinuxWaitPoll(pThis);
     358    if (uTimeout == UINT64_MAX)
     359        return rtSemEventLinuxWaitIndefinite(pThis, fFlags, pSrcPos);
    444360
    445361    /*
     
    494410        else if (lrc == -ETIMEDOUT)
    495411        {
     412#ifdef RT_STRICT
     413            uint64_t const uNow = RTTimeNanoTS();
     414            AssertMsg(uNow >= nsAbsTimeout || nsAbsTimeout - uNow < RT_NS_1MS,
     415                      ("%#RX64 - %#RX64 => %#RX64 (%RI64)\n", nsAbsTimeout, uNow, nsAbsTimeout - uNow, nsAbsTimeout - uNow));
     416#endif
    496417            rc = VERR_TIMEOUT;
    497418            break;
     
    516437        if (iWaitOp == FUTEX_WAIT)
    517438        {
    518             int64_t i64Diff = uAbsTimeout - RTTimeSystemNanoTS();
     439            int64_t i64Diff = nsAbsTimeout - RTTimeSystemNanoTS();
    519440            if (i64Diff < 1000)
    520441            {
     
    542463    struct RTSEMEVENTINTERNAL *pThis = hEventSem;
    543464    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    544     uint32_t    fSignalled = pThis->fSignalled;
    545     AssertReturn(fSignalled == false || fSignalled == true, VERR_INVALID_HANDLE);
     465    AssertReturn(pThis->iMagic == RTSEMEVENT_MAGIC, VERR_INVALID_HANDLE);
    546466    AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
     467#ifdef RT_STRICT
     468    uint32_t const fSignalled = pThis->fSignalled;
     469    Assert(fSignalled == false || fSignalled == true);
     470#endif
    547471
    548472    /*
  • trunk/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp

    r92779 r92782  
    268268
    269269
    270 
    271 DECLINLINE(int) rtSemEventLnxMultiWait(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, uint64_t uTimeout,
    272                                        PCRTLOCKVALSRCPOS pSrcPos)
     270/**
     271 * Performs an indefinite wait on the event.
     272 */
     273static int rtSemEventMultiLinuxWaitIndefinite(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, PCRTLOCKVALSRCPOS pSrcPos)
    273274{
    274275    RT_NOREF(pSrcPos);
    275 
    276     /*
    277      * Validate input.
    278      */
    279     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    280     AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
    281     AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
    282276
    283277    /*
     
    288282        return VINF_SUCCESS;
    289283    ASSERT_VALID_STATE(uState);
    290 
    291     /*
    292      * Check and convert the timeout value.
    293      */
    294     struct timespec ts;
    295     struct timespec *pTimeout = NULL;
    296     uint64_t u64Deadline = 0; /* shut up gcc */
    297     if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
    298     {
    299         /* If the timeout is zero, then we're done. */
    300         if (!uTimeout)
    301             return VERR_TIMEOUT;
    302 
    303         /* Convert it to a deadline + interval timespec. */
    304         if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
    305             uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
    306                      ? uTimeout * UINT32_C(1000000)
    307                      : UINT64_MAX;
    308         if (uTimeout != UINT64_MAX) /* unofficial way of indicating an indefinite wait */
    309         {
    310             if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
    311                 u64Deadline = RTTimeSystemNanoTS() + uTimeout;
    312             else
    313             {
    314                 uint64_t u64Now = RTTimeSystemNanoTS();
    315                 if (uTimeout <= u64Now)
    316                     return VERR_TIMEOUT;
    317                 u64Deadline = uTimeout;
    318                 uTimeout   -= u64Now;
    319             }
    320             if (   sizeof(ts.tv_sec) >= sizeof(uint64_t)
    321                 || uTimeout <= UINT64_C(1000000000) * UINT32_MAX)
    322             {
    323                 ts.tv_nsec = uTimeout % UINT32_C(1000000000);
    324                 ts.tv_sec  = uTimeout / UINT32_C(1000000000);
    325                 pTimeout = &ts;
    326             }
    327         }
    328     }
    329284
    330285    /*
     
    348303                                       RTSEMEVENTMULTI_LNX_NOT_SIGNALED)))
    349304        {
    350             /* adjust the relative timeout */
    351             if (pTimeout)
    352             {
    353                 int64_t i64Diff = u64Deadline - RTTimeSystemNanoTS();
    354                 if (i64Diff < 1000)
    355                     return VERR_TIMEOUT;
    356                 ts.tv_sec  = (uint64_t)i64Diff / UINT32_C(1000000000);
    357                 ts.tv_nsec = (uint64_t)i64Diff % UINT32_C(1000000000);
    358             }
    359305#ifdef RTSEMEVENTMULTI_STRICT
    360306            if (pThis->fEverHadSignallers)
    361307            {
    362308                int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
    363                                                                 uTimeout / UINT32_C(1000000), RTTHREADSTATE_EVENT_MULTI, true);
     309                                                                RT_INDEFINITE_WAIT, RTTHREADSTATE_EVENT_MULTI, true);
    364310                if (RT_FAILURE(rc9))
    365311                    return rc9;
     
    370316#endif
    371317            RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
    372             long rc = sys_futex(&pThis->uState, FUTEX_WAIT, 1, pTimeout, NULL, 0);
     318            long rc = sys_futex(&pThis->uState, FUTEX_WAIT, 1, NULL /*pTimeout*/, NULL, 0);
    373319            RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
    374             if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
     320
     321            /* Check that the structure is still alive before continuing. */
     322            if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC))
     323            { /*likely*/ }
     324            else
    375325                return VERR_SEM_DESTROYED;
     326
     327            /*
     328             * Return if success.
     329             */
    376330            if (rc == 0)
    377331            {
     
    383337             * Act on the wakup code.
    384338             */
    385             if (rc == -ETIMEDOUT)
    386             {
    387 /** @todo something is broken here. shows up every now and again in the ata
    388  *        code. Should try to run the timeout against RTTimeMilliTS to
    389  *        check that it's doing the right thing... */
    390                 Assert(pTimeout);
    391                 return VERR_TIMEOUT;
    392             }
    393339            if (rc == -EWOULDBLOCK)
    394340                /* retry, the value changed. */;
     
    413359
    414360
     361/**
     362 * Handle polling (timeout already expired at the time of the call).
     363 *
     364 * @returns VINF_SUCCESS, VERR_TIMEOUT, VERR_SEM_DESTROYED.
     365 * @param   pThis               The semaphore.
     366 */
     367static int rtSemEventMultiLinuxWaitPoll(struct RTSEMEVENTMULTIINTERNAL *pThis)
     368{
     369    uint32_t uState = ASMAtomicUoReadU32(&pThis->uState);
     370    if (uState == RTSEMEVENTMULTI_LNX_SIGNALED)
     371        return VINF_SUCCESS;
     372    return VERR_TIMEOUT;
     373}
     374
     375
     376/**
     377 * Performs an indefinite wait on the event.
     378 */
     379static int rtSemEventMultiLinuxWaitTimed(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, uint64_t uTimeout,
     380                                         PCRTLOCKVALSRCPOS pSrcPos)
     381{
     382    RT_NOREF(pSrcPos);
     383
     384    /*
     385     * Quickly check whether it's signaled.
     386     */
     387    uint32_t uState = ASMAtomicUoReadU32(&pThis->uState);
     388    if (uState == RTSEMEVENTMULTI_LNX_SIGNALED)
     389        return VINF_SUCCESS;
     390    ASSERT_VALID_STATE(uState);
     391
     392    /*
     393     * Convert the timeout value.
     394     */
     395    struct timespec TsTimeout;
     396    int             iWaitOp;
     397    uint32_t        uWaitVal3;
     398    uint64_t        nsAbsTimeout;
     399    uTimeout = rtSemLinuxCalcDeadline(fFlags, uTimeout, g_fCanUseWaitBitSet, &TsTimeout, &iWaitOp, &uWaitVal3, &nsAbsTimeout);
     400    if (uTimeout == 0)
     401        return rtSemEventMultiLinuxWaitPoll(pThis);
     402    if (uTimeout == UINT64_MAX)
     403        return rtSemEventMultiLinuxWaitIndefinite(pThis, fFlags, pSrcPos);
     404
     405    /*
     406     * The wait loop.
     407     */
     408#ifdef RTSEMEVENTMULTI_STRICT
     409    RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
     410#else
     411    RTTHREAD hThreadSelf = RTThreadSelf();
     412#endif
     413    for (unsigned i = 0;; i++)
     414    {
     415        /*
     416         * Start waiting. We only account for there being or having been
     417         * threads waiting on the semaphore to keep things simple.
     418         */
     419        uState = ASMAtomicUoReadU32(&pThis->uState);
     420        if (   uState == RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS
     421            || (   uState == RTSEMEVENTMULTI_LNX_NOT_SIGNALED
     422                && ASMAtomicCmpXchgU32(&pThis->uState, RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS,
     423                                       RTSEMEVENTMULTI_LNX_NOT_SIGNALED)))
     424        {
     425#ifdef RTSEMEVENTMULTI_STRICT
     426            if (pThis->fEverHadSignallers)
     427            {
     428                int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
     429                                                                uTimeout / UINT32_C(1000000), RTTHREADSTATE_EVENT_MULTI, true);
     430                if (RT_FAILURE(rc9))
     431                    return rc9;
     432            }
     433#endif
     434#ifdef RT_STRICT
     435            uint32_t const uPrevSignalSerialNo = ASMAtomicReadU32(&pThis->uSignalSerialNo);
     436#endif
     437            RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
     438            long rc = sys_futex(&pThis->uState, iWaitOp, 1, &TsTimeout, NULL, uWaitVal3);
     439            RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
     440
     441            /* Check that the structure is still alive before continuing. */
     442            if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC))
     443            { /*likely*/ }
     444            else
     445                return VERR_SEM_DESTROYED;
     446
     447            /*
     448             * Return if success.
     449             */
     450            if (rc == 0)
     451            {
     452                Assert(uPrevSignalSerialNo != ASMAtomicReadU32(&pThis->uSignalSerialNo));
     453                return VINF_SUCCESS;
     454            }
     455
     456            /*
     457             * Act on the wakup code.
     458             */
     459            if (rc == -ETIMEDOUT)
     460            {
     461                /** @todo something is broken here. shows up every now and again in the ata
     462                 *        code. Should try to run the timeout against RTTimeMilliTS to
     463                 *        check that it's doing the right thing... */
     464#ifdef RT_STRICT
     465                uint64_t const uNow = RTTimeNanoTS();
     466                AssertMsg(uNow >= nsAbsTimeout || nsAbsTimeout - uNow < RT_NS_1MS,
     467                          ("%#RX64 - %#RX64 => %#RX64 (%RI64)\n", nsAbsTimeout, uNow, nsAbsTimeout - uNow, nsAbsTimeout - uNow));
     468#endif
     469                return VERR_TIMEOUT;
     470            }
     471            if (rc == -EWOULDBLOCK)
     472            {
     473                /* retry, the value changed. */;
     474            }
     475            else if (rc == -EINTR)
     476            {
     477                if (fFlags & RTSEMWAIT_FLAGS_NORESUME)
     478                    return VERR_INTERRUPTED;
     479            }
     480            else
     481            {
     482                /* this shouldn't happen! */
     483                AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
     484                return RTErrConvertFromErrno(rc);
     485            }
     486        }
     487        else if (uState == RTSEMEVENTMULTI_LNX_SIGNALED)
     488            return VINF_SUCCESS;
     489        else
     490            ASSERT_VALID_STATE(uState);
     491
     492        /* adjust the relative timeout if relative */
     493        if (iWaitOp == FUTEX_WAIT)
     494        {
     495            int64_t i64Diff = nsAbsTimeout - RTTimeSystemNanoTS();
     496            if (i64Diff < 1000)
     497                return VERR_TIMEOUT;
     498            TsTimeout.tv_sec  = (uint64_t)i64Diff / RT_NS_1SEC;
     499            TsTimeout.tv_nsec = (uint64_t)i64Diff % RT_NS_1SEC;
     500        }
     501    }
     502}
     503
     504/**
     505 * Internal wait worker function.
     506 */
     507DECLINLINE(int) rtSemEventLnxMultiWait(RTSEMEVENTMULTI hEventSem, uint32_t fFlags, uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos)
     508{
     509    /*
     510     * Validate input.
     511     */
     512    struct RTSEMEVENTMULTIINTERNAL *pThis = hEventSem;
     513    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     514    AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
     515    AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
     516
     517    /*
     518     * Timed or indefinite wait?
     519     */
     520    if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
     521        return rtSemEventMultiLinuxWaitIndefinite(pThis, fFlags, pSrcPos);
     522    return rtSemEventMultiLinuxWaitTimed(hEventSem, fFlags, uTimeout, pSrcPos);
     523}
     524
     525
    415526#undef RTSemEventMultiWaitEx
    416527RTDECL(int)  RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
  • trunk/src/VBox/Runtime/r3/linux/semwait-linux.h

    r92779 r92782  
    7171}
    7272
     73
     74/**
     75 * Converts a extended wait timeout specification to an timespec and
     76 * corresponding futex operation, as well as an approximate relative nanosecond
     77 * interval.
     78 *
     79 * @note    This does not check for RTSEMWAIT_FLAGS_INDEFINITE, caller should've
     80 *          done that already.
     81 *
     82 * @returns The relative wait in nanoseconds.  0 for a poll call, UINT64_MAX for
     83 *          an effectively indefinite wait.
     84 * @param   fFlags              RTSEMWAIT_FLAGS_XXX.
     85 * @param   fCanUseWaitBitSet   Whether we can use FUTEX_WAIT_BITMSET or not.
     86 * @param   uTimeout            The timeout.
     87 * @param   pDeadline           Where to return the deadline.
     88 * @param   piWaitOp            Where to return the FUTEX wait operation number.
     89 * @param   puWaitVal3          Where to return the FUTEX wait value 3.
     90 * @param   pnsAbsTimeout       Where to return the absolute timeout in case of
     91 *                              a resuming relative call (i.e. FUTEX_WAIT).
     92 */
     93DECL_FORCE_INLINE(uint64_t)
     94rtSemLinuxCalcDeadline(uint32_t fFlags, uint64_t uTimeout, int fCanUseWaitBitSet,
     95                       struct timespec *pDeadline, int *piWaitOp, uint32_t *puWaitVal3, uint64_t *pnsAbsTimeout)
     96{
     97    Assert(!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE));
     98
     99    if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
     100    {
     101        Assert(!(fFlags & RTSEMWAIT_FLAGS_ABSOLUTE));
     102
     103        /*
     104         * Polling call?
     105         */
     106        if (uTimeout == 0)
     107            return 0;
     108
     109        /*
     110         * We use FUTEX_WAIT here as it takes a relative timespec.
     111         *
     112         * Note! For non-resuming waits, we can skip calculating the absolute
     113         *       time ASSUMING it is only needed for timeout adjustments
     114         *       after an -EINTR return.
     115         */
     116        if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
     117        {
     118            if (   sizeof(pDeadline->tv_sec) >= sizeof(uint64_t)
     119                || uTimeout < (uint64_t)UINT32_MAX * RT_MS_1SEC)
     120            {
     121                pDeadline->tv_sec  = uTimeout / RT_MS_1SEC;
     122                pDeadline->tv_nsec = (uTimeout % RT_MS_1SEC) & RT_NS_1MS;
     123                uTimeout *= RT_NS_1MS;
     124            }
     125            else
     126                return UINT64_MAX;
     127        }
     128        else
     129        {
     130            Assert(fFlags & RTSEMWAIT_FLAGS_NANOSECS);
     131            if (   sizeof(pDeadline->tv_sec) >= sizeof(uint64_t)
     132                || uTimeout < (uint64_t)UINT32_MAX * RT_NS_1SEC)
     133            {
     134                pDeadline->tv_sec  = uTimeout / RT_NS_1SEC;
     135                pDeadline->tv_nsec = uTimeout % RT_NS_1SEC;
     136            }
     137            else
     138                return UINT64_MAX;
     139        }
     140
     141#ifdef RT_STRICT
     142        if (!(fFlags & RTSEMWAIT_FLAGS_RESUME))
     143            *pnsAbsTimeout = uTimeout;
     144        else
     145#endif
     146            *pnsAbsTimeout = RTTimeNanoTS() + uTimeout; /* Note! only relevant for relative waits (FUTEX_WAIT). */
     147    }
     148    else
     149    {
     150        /* Absolute deadline: */
     151        Assert(fFlags & RTSEMWAIT_FLAGS_ABSOLUTE);
     152        if (fCanUseWaitBitSet == true)
     153        {
     154            /*
     155             * Use FUTEX_WAIT_BITSET as it takes an absolute deadline.
     156             */
     157            if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
     158            {
     159                if (   sizeof(pDeadline->tv_sec) >= sizeof(uint64_t)
     160                    || uTimeout < (uint64_t)UINT32_MAX * RT_MS_1SEC)
     161                {
     162                    pDeadline->tv_sec  = uTimeout / RT_MS_1SEC;
     163                    pDeadline->tv_nsec = (uTimeout % RT_MS_1SEC) & RT_NS_1MS;
     164                }
     165                else
     166                    return UINT64_MAX;
     167            }
     168            else
     169            {
     170                Assert(fFlags & RTSEMWAIT_FLAGS_NANOSECS);
     171                if (   sizeof(pDeadline->tv_sec) >= sizeof(uint64_t)
     172                    || uTimeout < (uint64_t)UINT32_MAX * RT_NS_1SEC)
     173                {
     174                    pDeadline->tv_sec  = uTimeout / RT_NS_1SEC;
     175                    pDeadline->tv_nsec = uTimeout % RT_NS_1SEC;
     176                }
     177                else
     178                    return UINT64_MAX;
     179            }
     180            *pnsAbsTimeout = uTimeout;
     181            *piWaitOp      = FUTEX_WAIT_BITSET;
     182            *puWaitVal3    = UINT32_MAX;
     183            return RT_MS_1SEC; /* Whatever non-zero; Whole point is not calling RTTimeNanoTS() in this path. */
     184        }
     185
     186        /*
     187         * FUTEX_WAIT_BITSET is not available, so use FUTEX_WAIT with a
     188         * relative timeout.
     189         */
     190        if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
     191        {
     192            if (uTimeout < UINT64_MAX / RT_NS_1MS)
     193                uTimeout *= RT_NS_1MS;
     194            else
     195                return UINT64_MAX;
     196        }
     197
     198        uint64_t const u64Now = RTTimeNanoTS();
     199        if (u64Now < uTimeout)
     200        {
     201            *pnsAbsTimeout = uTimeout;
     202            uTimeout      -= u64Now;
     203        }
     204        else
     205            return 0;
     206
     207        if (   sizeof(pDeadline->tv_sec) >= sizeof(uint64_t)
     208            || uTimeout < (uint64_t)UINT32_MAX * RT_NS_1SEC)
     209        {
     210            pDeadline->tv_sec  = uTimeout / RT_NS_1SEC;
     211            pDeadline->tv_nsec = uTimeout % RT_NS_1SEC;
     212        }
     213        else
     214            return UINT64_MAX;
     215    }
     216
     217    *piWaitOp   = FUTEX_WAIT;
     218    *puWaitVal3 = 0;
     219    return uTimeout;
     220}
     221
    73222#endif /* !IPRT_INCLUDED_SRC_r3_linux_semwait_linux_h */
    74223
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