VirtualBox

Ignore:
Timestamp:
Sep 9, 2019 10:43:23 AM (5 years ago)
Author:
vboxsync
Message:

IPRT: Redid RTTimerLRChangeInterval. Converted RTTimerLR testcase to RTTest style.

File:
1 edited

Legend:

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

    r76553 r80665  
    4747
    4848/*********************************************************************************************************************************
     49*   Defined Constants And Macros                                                                                                 *
     50*********************************************************************************************************************************/
     51/** The smallest interval for low resolution timers. */
     52#define RTTIMERLR_MIN_INTERVAL  RT_NS_100MS
     53
     54
     55/*********************************************************************************************************************************
    4956*   Structures and Typedefs                                                                                                      *
    5057*********************************************************************************************************************************/
     
    6269    /** Flag indicating that the timer has been destroyed. */
    6370    bool volatile           fDestroyed;
     71    /** Set when the thread is blocked. */
     72    bool volatile           fBlocked;
     73    bool                    fPadding;
     74    /** The timer interval. 0 if one-shot. */
     75    uint64_t volatile       u64NanoInterval;
     76    /** The start of the current run (ns).
     77     * This is used to calculate when the timer ought to fire the next time. */
     78    uint64_t volatile       u64StartTS;
     79    /** The start of the current run (ns).
     80     * This is used to calculate when the timer ought to fire the next time. */
     81    uint64_t volatile       u64NextTS;
     82    /** The current tick number (since u64StartTS). */
     83    uint64_t volatile       iTick;
     84
    6485    /** Callback. */
    6586    PFNRTTIMERLR            pfnTimer;
     
    7091    /** Event semaphore on which the thread is blocked. */
    7192    RTSEMEVENT              hEvent;
    72     /** The timer interval. 0 if one-shot. */
    73     uint64_t                u64NanoInterval;
    74     /** The start of the current run (ns).
    75      * This is used to calculate when the timer ought to fire the next time. */
    76     uint64_t volatile       u64StartTS;
    77     /** The start of the current run (ns).
    78      * This is used to calculate when the timer ought to fire the next time. */
    79     uint64_t volatile       u64NextTS;
    80     /** The current tick number (since u64StartTS). */
    81     uint64_t volatile       iTick;
    8293} RTTIMERLRINT;
    8394typedef RTTIMERLRINT *PRTTIMERLRINT;
     
    98109     * We don't support the fancy MP features, nor intervals lower than 100 ms.
    99110     */
    100     if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
    101         return VERR_NOT_SUPPORTED;
    102     if (u64NanoInterval && u64NanoInterval < 100*1000*1000)
    103         return VERR_INVALID_PARAMETER;
     111    AssertReturn(!(fFlags & RTTIMER_FLAGS_CPU_SPECIFIC), VERR_NOT_SUPPORTED);
     112    AssertReturn(!u64NanoInterval || u64NanoInterval >= RTTIMERLR_MIN_INTERVAL, VERR_OUT_OF_RANGE);
    104113
    105114    /*
     
    113122    pThis->fSuspended = true;
    114123    pThis->fDestroyed = false;
     124    pThis->fBlocked = false;
     125    pThis->fPadding = false;
    115126    pThis->pfnTimer = pfnTimer;
    116127    pThis->pvUser = pvUser;
     
    173184
    174185
    175 RTDECL(int) RTTimerLRStart(RTTIMERLR hTimerLR, uint64_t u64First)
    176 {
    177     /*
    178      * Validate input.
    179      */
    180     PRTTIMERLRINT pThis = hTimerLR;
    181     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    182     AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE);
    183     AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE);
    184 
    185     if (u64First && u64First < 100*1000*1000)
    186         return VERR_INVALID_PARAMETER;
    187 
     186/**
     187 * Internal worker fro RTTimerLRStart and RTTiemrLRChangeInterval.
     188 */
     189static int rtTimerLRStart(PRTTIMERLRINT pThis, uint64_t u64First)
     190{
    188191    if (!pThis->fSuspended)
    189192        return VERR_TIMER_ACTIVE;
     
    203206    return rc;
    204207}
    205 RT_EXPORT_SYMBOL(RTTimerLRStart);
    206 
    207 
    208 RTDECL(int) RTTimerLRStop(RTTIMERLR hTimerLR)
     208
     209
     210RTDECL(int) RTTimerLRStart(RTTIMERLR hTimerLR, uint64_t u64First)
    209211{
    210212    /*
     
    215217    AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE);
    216218    AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE);
    217 
     219    AssertReturn(!u64First || u64First >= RTTIMERLR_MIN_INTERVAL, VERR_OUT_OF_RANGE);
     220
     221    /*
     222     * Do the job.
     223     */
     224    return rtTimerLRStart(pThis, u64First);
     225}
     226RT_EXPORT_SYMBOL(RTTimerLRStart);
     227
     228
     229/**
     230 * Internal worker for RTTimerLRStop and RTTimerLRChangeInterval
     231 */
     232static int rtTimerLRStop(PRTTIMERLRINT pThis, bool fSynchronous)
     233{
     234    /*
     235     * Fail if already suspended.
     236     */
    218237    if (pThis->fSuspended)
    219238        return VERR_TIMER_SUSPENDED;
     
    221240    /*
    222241     * Mark it as suspended and kick the thread.
    223      */
     242     * It's simpler to always reset the thread user semaphore, so we do that first.
     243     */
     244    int rc = RTThreadUserReset(pThis->hThread);
     245    AssertRC(rc);
     246
    224247    ASMAtomicWriteBool(&pThis->fSuspended, true);
    225     int rc = RTSemEventSignal(pThis->hEvent);
     248    rc = RTSemEventSignal(pThis->hEvent);
    226249    if (rc == VERR_ALREADY_POSTED)
    227250        rc = VINF_SUCCESS;
    228251    AssertRC(rc);
     252
     253    /*
     254     * Wait for the thread to stop running if synchronous.
     255     */
     256    if (fSynchronous && RT_SUCCESS(rc))
     257    {
     258        rc = RTThreadUserWait(pThis->hThread, RT_MS_1MIN);
     259        AssertRC(rc);
     260    }
     261
    229262    return rc;
    230263}
    231 RT_EXPORT_SYMBOL(RTTimerLRStop);
    232 
    233 RTDECL(int) RTTimerLRChangeInterval(RTTIMERLR hTimerLR, uint64_t u64NanoInterval)
    234 {
     264
     265
     266RTDECL(int) RTTimerLRStop(RTTIMERLR hTimerLR)
     267{
     268    /*
     269     * Validate input.
     270     */
    235271    PRTTIMERLRINT pThis = hTimerLR;
    236272    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     
    238274    AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE);
    239275
    240     if (u64NanoInterval && u64NanoInterval < 100*1000*1000)
    241         return VERR_INVALID_PARAMETER;
    242 
    243 #if 0
    244     if (!pThis->fSuspended)
    245     {
    246         int rc = RTTimerLRStop(hTimerLR);
    247         if (RT_FAILURE(rc))
    248             return rc;
    249 
     276    /*
     277     * Do the job.
     278     */
     279    return rtTimerLRStop(pThis, false);
     280}
     281RT_EXPORT_SYMBOL(RTTimerLRStop);
     282
     283
     284RTDECL(int) RTTimerLRChangeInterval(RTTIMERLR hTimerLR, uint64_t u64NanoInterval)
     285{
     286    /*
     287     * Validate input.
     288     */
     289    PRTTIMERLRINT pThis = hTimerLR;
     290    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     291    AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE);
     292    AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE);
     293    AssertReturn(!u64NanoInterval || u64NanoInterval >= RTTIMERLR_MIN_INTERVAL, VERR_OUT_OF_RANGE);
     294
     295    /*
     296     * Do the job accoring to state and caller.
     297     */
     298    int rc;
     299    if (pThis->fSuspended)
     300    {
     301        /* Stopped: Just update the interval. */
    250302        ASMAtomicWriteU64(&pThis->u64NanoInterval, u64NanoInterval);
    251 
    252         rc = RTTimerLRStart(hTimerLR, 0);
    253         if (RT_FAILURE(rc))
    254             return rc;
     303        rc = VINF_SUCCESS;
     304    }
     305    else if (RTThreadSelf() == pThis->hThread)
     306    {
     307        /* Running: Updating interval from the callback. */
     308        uint64_t u64Now = RTTimeNanoTS();
     309        pThis->iTick           = 0;
     310        pThis->u64StartTS      = u64Now;
     311        pThis->u64NextTS       = u64Now;
     312        ASMAtomicWriteU64(&pThis->u64NanoInterval, u64NanoInterval);
     313        rc = VINF_SUCCESS;
    255314    }
    256315    else
    257 #endif
    258     {
    259         uint64_t u64Now = RTTimeNanoTS();
    260         ASMAtomicWriteU64(&pThis->iTick, 0);
    261         ASMAtomicWriteU64(&pThis->u64StartTS, u64Now);
    262         ASMAtomicWriteU64(&pThis->u64NextTS, u64Now);
    263         ASMAtomicWriteU64(&pThis->u64NanoInterval, u64NanoInterval);
    264         RTSemEventSignal(pThis->hEvent);
    265     }
    266 
    267     return VINF_SUCCESS;
     316    {
     317        /* Running: Stopping  */
     318        rc = rtTimerLRStop(pThis, true);
     319        if (RT_SUCCESS(rc))
     320        {
     321            ASMAtomicWriteU64(&pThis->u64NanoInterval, u64NanoInterval);
     322            rc = rtTimerLRStart(pThis, 0);
     323        }
     324    }
     325
     326    return rc;
    268327}
    269328RT_EXPORT_SYMBOL(RTTimerLRChangeInterval);
     329
    270330
    271331static DECLCALLBACK(int) rtTimerLRThread(RTTHREAD hThreadSelf, void *pvUser)
     
    281341        if (ASMAtomicUoReadBool(&pThis->fSuspended))
    282342        {
    283             int rc = RTSemEventWait(pThis->hEvent, RT_INDEFINITE_WAIT);
     343            /* Signal rtTimerLRStop thread. */
     344            int rc = RTThreadUserSignal(hThreadSelf);
     345            AssertRC(rc);
     346
     347            ASMAtomicWriteBool(&pThis->fBlocked, true);
     348            rc = RTSemEventWait(pThis->hEvent, RT_INDEFINITE_WAIT);
    284349            if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED)
    285350            {
     
    287352                RTThreadSleep(1000); /* Don't cause trouble! */
    288353            }
     354            ASMAtomicWriteBool(&pThis->fBlocked, false);
    289355        }
    290356        else
     
    292358            uint64_t        cNanoSeconds;
    293359            const uint64_t  u64NanoTS = RTTimeNanoTS();
    294             if (u64NanoTS >= pThis->u64NextTS)
     360            uint64_t        u64NextTS = pThis->u64NextTS;
     361            if (u64NanoTS >= u64NextTS)
    295362            {
    296                 pThis->iTick++;
    297                 pThis->pfnTimer(pThis, pThis->pvUser, pThis->iTick);
     363                uint64_t iTick = ++pThis->iTick;
     364                pThis->pfnTimer(pThis, pThis->pvUser, iTick);
    298365
    299366                /* status changed? */
    300                 if (    ASMAtomicUoReadBool(&pThis->fSuspended)
    301                     ||  ASMAtomicUoReadBool(&pThis->fDestroyed))
     367                if (   ASMAtomicUoReadBool(&pThis->fSuspended)
     368                    || ASMAtomicUoReadBool(&pThis->fDestroyed))
    302369                    continue;
    303370
    304                 /* one shot? */
    305                 if (!pThis->u64NanoInterval)
     371                /*
     372                 * Read timer data (it's all volatile and better if we read it all at once):
     373                 */
     374                iTick = pThis->iTick;
     375                uint64_t const u64StartTS       = pThis->u64StartTS;
     376                uint64_t const u64NanoInterval  = pThis->u64NanoInterval;
     377                ASMCompilerBarrier();
     378
     379                /*
     380                 * Suspend if one shot.
     381                 */
     382                if (!u64NanoInterval)
    306383                {
    307384                    ASMAtomicWriteBool(&pThis->fSuspended, true);
     
    318395                 * if we're using a non-monotonic clock as time source.
    319396                 */
    320                 pThis->u64NextTS = pThis->u64StartTS + pThis->iTick * pThis->u64NanoInterval;
    321                 if (RT_LIKELY(pThis->u64NextTS > u64NanoTS))
    322                     cNanoSeconds = pThis->u64NextTS - u64NanoTS;
     397                u64NextTS = u64StartTS + iTick * u64NanoInterval;
     398                if (RT_LIKELY(u64NextTS > u64NanoTS))
     399                    cNanoSeconds = u64NextTS - u64NanoTS;
    323400                else
    324401                {
    325                     uint64_t iActualTick = (u64NanoTS - pThis->u64StartTS) / pThis->u64NanoInterval;
    326                     if (iActualTick - pThis->iTick > 60)
     402                    uint64_t iActualTick = (u64NanoTS - u64StartTS) / u64NanoInterval;
     403                    if (iActualTick - iTick > 60)
    327404                        pThis->iTick = iActualTick - 1;
    328405#ifdef IN_RING0
    329406                    cNanoSeconds = RTTimerGetSystemGranularity() / 2;
    330407#else
    331                     cNanoSeconds = 1000000; /* 1ms */
     408                    cNanoSeconds = RT_NS_1MS;
    332409#endif
    333                     pThis->u64NextTS = u64NanoTS + cNanoSeconds;
     410                    u64NextTS = u64NanoTS + cNanoSeconds;
    334411                }
     412
     413                pThis->u64NextTS = u64NextTS;
    335414            }
    336415            else
    337                 cNanoSeconds = pThis->u64NextTS - u64NanoTS;
     416                cNanoSeconds = u64NextTS - u64NanoTS;
    338417
    339418            /* block. */
     419            ASMAtomicWriteBool(&pThis->fBlocked, true);
    340420            int rc = RTSemEventWait(pThis->hEvent,
    341421                                    (RTMSINTERVAL)(cNanoSeconds < 1000000 ? 1 : cNanoSeconds / 1000000));
     
    345425                RTThreadSleep(1000); /* Don't cause trouble! */
    346426            }
     427            ASMAtomicWriteBool(&pThis->fBlocked, false);
    347428        }
    348429    }
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