VirtualBox

Changeset 32737 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Sep 23, 2010 4:20:05 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
66176
Message:

timer-r0drv-linux.c: Fixes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c

    r32711 r32737  
    123123            /** The start of the current run (ns).
    124124             * This is used to calculate when the timer ought to fire the next time. */
    125             uint64_t                u64StartTS;
    126             /** The start of the current run (ns).
    127              * This is used to calculate when the timer ought to fire the next time. */
    128125            uint64_t                u64NextTS;
    129126            /** The u64NextTS in jiffies. */
    130127            unsigned long           ulNextJiffies;
     128            /** Set when starting or changing the timer so that u64StartTs
     129             *  and u64NextTS gets reinitialized (eliminating some jitter). */
     130            bool volatile           fFirstAfterChg;
    131131        } Std;
    132132    } u;
    133     /** The current tick number (since u.Std.u64StartTS). */
     133    /** The current tick number. */
    134134    uint64_t                iTick;
    135135    /** Restart the single shot timer at this specific time.
     
    179179    /** This is set to the number of jiffies between ticks if the interval is
    180180     * an exact number of jiffies. (Standard timers only.) */
    181     unsigned long           cJiffies;
     181    unsigned long volatile  cJiffies;
     182    /** The change interval spinlock for standard timers only. */
     183    spinlock_t              ChgIntLock;
    182184    /** Sub-timers.
    183185     * Normally there is just one, but for RTTIMER_FLAGS_CPU_ALL this will contain
     
    193195typedef struct RTTIMERLINUXSTARTONCPUARGS
    194196{
    195     /** The current time (RTTimeNanoTS). */
     197    /** The current time (RTTimeSystemNanoTS). */
    196198    uint64_t                u64Now;
    197199    /** When to start firing (delta). */
     
    284286 * Converts a nano second time stamp to ktime_t.
    285287 *
    286  * ASSUMES RTTimeNanoTS() is implemented using ktime_get_ts().
     288 * ASSUMES RTTimeSystemNanoTS() is implemented using ktime_get_ts().
    287289 *
    288290 * @returns ktime_t.
     
    298300 * Converts ktime_t to a nano second time stamp.
    299301 *
    300  * ASSUMES RTTimeNanoTS() is implemented using ktime_get_ts().
     302 * ASSUMES RTTimeSystemNanoTS() is implemented using ktime_get_ts().
    301303 *
    302304 * @returns nano second time stamp.
     
    333335 *
    334336 * @param   pSubTimer   The sub-timer to start.
    335  * @param   u64Now      The current timestamp (RTTimeNanoTS()).
     337 * @param   u64Now      The current timestamp (RTTimeSystemNanoTS()).
    336338 * @param   u64First    The interval from u64Now to the first time the timer should fire.
    337339 * @param   fPinned     true = timer pinned to a specific CPU,
     
    348350    uint64_t u64NextTS = u64Now + u64First;
    349351    if (fHighRes)
    350     {
    351         pSubTimer->u.Std.u64StartTS = u64NextTS;
    352         pSubTimer->u.Std.u64NextTS  = u64NextTS;
    353     }
     352        pSubTimer->u.Std.u64NextTS = u64NextTS;
    354353    dprintf(("startsubtimer %p\n", pSubTimer->pParent));
    355354
     
    364363    {
    365364        unsigned long cJiffies = !u64First ? 0 : rtTimerLnxNanoToJiffies(u64First);
    366         pSubTimer->u.Std.ulNextJiffies = jiffies + cJiffies;
     365        pSubTimer->u.Std.ulNextJiffies  = jiffies + cJiffies;
     366        pSubTimer->u.Std.fFirstAfterChg = true;
    367367#ifdef CONFIG_SMP
    368368        if (fPinned)
     
    697697    {
    698698        /*
    699          * Interval timer, calculate the next timeout and re-arm it.
     699         * Interval timer, calculate the next timeout.
    700700         *
    701          * The first time around, we'll re-adjust the u.Std.u64StartTS to
     701         * The first time around, we'll re-adjust the u.Std.u64NextTS to
    702702         * try prevent some jittering if we were started at a bad time.
    703703         */
    704         const uint64_t u64NanoInterval  = pTimer->u64NanoInterval;
    705         const uint64_t iTick            = ++pSubTimer->iTick;
    706         const uint64_t u64NanoTS        = RTTimeNanoTS();
    707 
    708         if (RT_UNLIKELY(iTick == 1))
    709         {
    710             pSubTimer->u.Std.u64StartTS    = u64NanoTS;
    711             pSubTimer->u.Std.u64NextTS     = u64NanoTS;
    712             pSubTimer->u.Std.ulNextJiffies = jiffies;
    713         }
     704        const uint64_t  iTick = ++pSubTimer->iTick;
     705        uint64_t        u64NanoInterval;
     706        unsigned long   cJiffies;
     707        unsigned long   flFlags;
     708
     709        spin_lock_irqsave(&pTimer->ChgIntLock, flFlags);
     710        u64NanoInterval = pTimer->u64NanoInterval;
     711        cJiffies        = pTimer->cJiffies;
     712        if (RT_UNLIKELY(pSubTimer->u.Std.fFirstAfterChg))
     713        {
     714            pSubTimer->u.Std.fFirstAfterChg = false;
     715            pSubTimer->u.Std.u64NextTS      = RTTimeSystemNanoTS();
     716            pSubTimer->u.Std.ulNextJiffies  = jiffies;
     717        }
     718        spin_unlock_irqrestore(&pTimer->ChgIntLock, flFlags);
    714719
    715720        pSubTimer->u.Std.u64NextTS += u64NanoInterval;
    716         if (pTimer->cJiffies)
    717         {
    718             pSubTimer->u.Std.ulNextJiffies += pTimer->cJiffies;
     721        if (cJiffies)
     722        {
     723            pSubTimer->u.Std.ulNextJiffies += cJiffies;
    719724            /* Prevent overflows when the jiffies counter wraps around.
    720725             * Special thanks to Ken Preslan for helping debugging! */
    721726            while (time_before(pSubTimer->u.Std.ulNextJiffies, jiffies))
    722727            {
    723                 pSubTimer->u.Std.ulNextJiffies += pTimer->cJiffies;
     728                pSubTimer->u.Std.ulNextJiffies += cJiffies;
    724729                pSubTimer->u.Std.u64NextTS     += u64NanoInterval;
    725730            }
     
    727732        else
    728733        {
     734            const uint64_t u64NanoTS = RTTimeSystemNanoTS();
    729735            while (pSubTimer->u.Std.u64NextTS < u64NanoTS)
    730736                pSubTimer->u.Std.u64NextTS += u64NanoInterval;
     
    732738        }
    733739
    734 #ifdef CONFIG_SMP
    735         if (pTimer->fSpecificCpu || pTimer->fAllCpus)
    736             mod_timer_pinned(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
    737         else
    738 #endif
    739             mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
    740 
    741740        /*
    742          * Run the timer.
     741         * Run the timer and re-arm it unless the state changed                                                                                                        .
     742         *                                                                                                                                                             .
     743         * We must re-arm it afterwards as we're not in a position to undo this                                                                                        .
     744         * operation if for instance someone stopped or destroyed us while we                                                                                          .
     745         * were in the callback.  (Linux takes care of any races here.)
    743746         */
    744747        pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick);
    745748        if (RT_LIKELY(rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_CALLBACK)))
     749        {
     750#ifdef CONFIG_SMP
     751            if (pTimer->fSpecificCpu || pTimer->fAllCpus)
     752                mod_timer_pinned(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
     753            else
     754#endif
     755                mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
    746756            return;
     757        }
    747758    }
    748759    else
     
    762773     * Some state change occured while we were in the callback routine.
    763774     */
    764     if (pTimer->u64NanoInterval)
    765         del_timer_sync(&pSubTimer->u.Std.LnxTimer);
    766775    for (;;)
    767776    {
     
    781790                if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_CB_RESTARTING))
    782791                {
    783                     const uint64_t u64NanoTS = RTTimeNanoTS();
    784                     const uint64_t u64NextTS = pSubTimer->uNsRestartAt;
    785                     if (pTimer->fHighRes)
    786                     {
    787                         pSubTimer->u.Std.u64StartTS = u64NextTS;
    788                         pSubTimer->u.Std.u64NextTS  = u64NextTS;
    789                     }
    790                     pSubTimer->iTick = 0;
    791                     pSubTimer->u.Std.ulNextJiffies = u64NextTS > u64NanoTS
    792                                                    ? jiffies + rtTimerLnxNanoToJiffies(u64NextTS - u64NanoTS)
    793                                                    : jiffies;
     792                    uint64_t        u64NanoTS;
     793                    uint64_t        u64NextTS;
     794                    unsigned long   flFlags;
     795
     796                    spin_lock_irqsave(&pTimer->ChgIntLock, flFlags);
     797                    u64NextTS = pSubTimer->uNsRestartAt;
     798                    u64NanoTS = RTTimeSystemNanoTS();
     799                    pSubTimer->iTick                = 0;
     800                    pSubTimer->u.Std.u64NextTS      = u64NextTS;
     801                    pSubTimer->u.Std.fFirstAfterChg = true;
     802                    pSubTimer->u.Std.ulNextJiffies  = u64NextTS > u64NanoTS
     803                                                    ? jiffies + rtTimerLnxNanoToJiffies(u64NextTS - u64NanoTS)
     804                                                    : jiffies;
     805                    spin_unlock_irqrestore(&pTimer->ChgIntLock, flFlags);
     806
    794807#ifdef CONFIG_SMP
    795808                    if (pTimer->fSpecificCpu || pTimer->fAllCpus)
     
    881894     * do this without the cross calls).
    882895     */
    883     pArgs->u64Now = RTTimeNanoTS();
     896    pArgs->u64Now = RTTimeSystemNanoTS();
    884897    rc2 = RTMpOnAll(rtTimerLnxStartAllOnCpu, pTimer, pArgs);
    885898    AssertRC(rc2); /* screw this if it fails. */
     
    10541067                {
    10551068                    RTTIMERLINUXSTARTONCPUARGS Args;
    1056                     Args.u64Now = RTTimeNanoTS();
     1069                    Args.u64Now = RTTimeSystemNanoTS();
    10571070                    Args.u64First = 0;
    10581071
     
    11531166     * Simple timer - Pretty straight forward if it wasn't for restarting.
    11541167     */
    1155     Args.u64Now = RTTimeNanoTS();
     1168    Args.u64Now = RTTimeSystemNanoTS();
    11561169    ASMAtomicWriteU64(&pTimer->aSubTimers[0].uNsRestartAt, Args.u64Now + u64First);
    11571170    for (;;)
     
    12291242        {
    12301243            case RTTIMERLNXSTATE_ACTIVE:
    1231                 if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[0].enmState, RTTIMERLNXSTATE_MP_STOPPING, RTTIMERLNXSTATE_ACTIVE))
     1244                if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[0].enmState, RTTIMERLNXSTATE_STOPPING, RTTIMERLNXSTATE_ACTIVE))
    12321245                {
    12331246                    rtTimerLnxStopSubTimer(&pTimer->aSubTimers[0], pTimer->fHighRes);
     
    12411254                Assert(enmState != RTTIMERLNXSTATE_CB_STOPPING || fForDestroy);
    12421255                if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[0].enmState,
    1243                                            !fForDestroy ? RTTIMERLNXSTATE_STOPPED : RTTIMERLNXSTATE_CB_DESTROYING,
     1256                                           !fForDestroy ? RTTIMERLNXSTATE_CB_STOPPING : RTTIMERLNXSTATE_CB_DESTROYING,
    12441257                                           enmState))
    12451258                    return true;
     
    12881301RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
    12891302{
     1303    unsigned long cJiffies;
     1304    unsigned long flFlags;
     1305
    12901306    /*
    12911307     * Validate.
     
    13141330    if (pTimer->cCpus > 1)
    13151331        return VERR_NOT_SUPPORTED;
    1316     RTTimerStop(pTimer);
    1317     return RTTimerStart(pTimer, u64NanoInterval);
     1332
     1333    cJiffies = u64NanoInterval / RTTimerGetSystemGranularity();
     1334    if (cJiffies * RTTimerGetSystemGranularity() != u64NanoInterval)
     1335        cJiffies = 0;
     1336
     1337    spin_lock_irqsave(&pTimer->ChgIntLock, flFlags);
     1338    pTimer->aSubTimers[0].u.Std.fFirstAfterChg = true;
     1339    pTimer->cJiffies = cJiffies;
     1340    ASMAtomicWriteU64(&pTimer->u64NanoInterval, u64NanoInterval);
     1341    spin_unlock_irqrestore(&pTimer->ChgIntLock, flFlags);
     1342    return VINF_SUCCESS;
    13181343}
    13191344RT_EXPORT_SYMBOL(RTTimerChangeInterval);
     
    14451470    if (pTimer->cJiffies * RTTimerGetSystemGranularity() != u64NanoInterval)
    14461471        pTimer->cJiffies    = 0;
     1472    spin_lock_init(&pTimer->ChgIntLock);
    14471473
    14481474    for (iCpu = 0; iCpu < cCpus; iCpu++)
     
    14611487            pTimer->aSubTimers[iCpu].u.Std.LnxTimer.function    = rtTimerLinuxStdCallback;
    14621488            pTimer->aSubTimers[iCpu].u.Std.LnxTimer.expires     = jiffies;
    1463             pTimer->aSubTimers[iCpu].u.Std.u64StartTS           = 0;
    14641489            pTimer->aSubTimers[iCpu].u.Std.u64NextTS            = 0;
    14651490        }
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