VirtualBox

Changeset 37517 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Jun 16, 2011 7:24:00 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
72345
Message:

TM: Simplified the virtual sync timers by requiring changes to be done while holding the virtual sync lock. This means we can skip all the pending states and move timers on and off the active list immediately, avoiding the problems with timers being on the pending-scheduling list. Also made u64VirtualSync keep track of the last time stamp all the time (when under the lock) and thus really making sure time does not jump backwards.

Location:
trunk/src/VBox/VMM
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/TMAll.cpp

    r37452 r37517  
    55
    66/*
    7  * Copyright (C) 2006-2007 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2323#include <VBox/vmm/tm.h>
    2424#include <VBox/vmm/mm.h>
     25#include <VBox/vmm/dbgftrace.h>
    2526#ifdef IN_RING3
    2627# include <VBox/vmm/rem.h>
     
    4041# include <iprt/thread.h>
    4142#endif
     43
     44#include "TMInline.h"
    4245
    4346
     
    373376 *          and stuff.
    374377 */
    375 DECLINLINE(void) tmTimerLink(PTMTIMERQUEUE pQueue, PTMTIMER pTimer)
     378DECLINLINE(void) tmTimerLinkSchedule(PTMTIMERQUEUE pQueue, PTMTIMER pTimer)
    376379{
    377380    Assert(!pTimer->offScheduleNext);
     
    402405    if (tmTimerTry(pTimer, enmStateNew, enmStateOld))
    403406    {
    404         tmTimerLink(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF(paTimerQueues)[pTimer->enmClock], pTimer);
     407        tmTimerLinkSchedule(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF(paTimerQueues)[pTimer->enmClock], pTimer);
    405408        return true;
    406409    }
     
    408411}
    409412
     413
     414/**
     415 * Links a timer into the active list of a timer queue.
     416 *
     417 * @param   pQueue          The queue.
     418 * @param   pTimer          The timer.
     419 * @param   u64Expire       The timer expiration time.
     420 *
     421 * @remarks Called while owning the relevant queue lock.
     422 */
     423DECL_FORCE_INLINE(void) tmTimerQueueLinkActive(PTMTIMERQUEUE pQueue, PTMTIMER pTimer, uint64_t u64Expire)
     424{
     425    Assert(!pTimer->offNext);
     426    Assert(!pTimer->offPrev);
     427    Assert(pTimer->enmState == TMTIMERSTATE_ACTIVE || pTimer->enmClock != TMCLOCK_VIRTUAL_SYNC); /* (active is not a stable state) */
     428
     429    PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue);
     430    if (pCur)
     431    {
     432        for (;; pCur = TMTIMER_GET_NEXT(pCur))
     433        {
     434            if (pCur->u64Expire > u64Expire)
     435            {
     436                const PTMTIMER pPrev = TMTIMER_GET_PREV(pCur);
     437                TMTIMER_SET_NEXT(pTimer, pCur);
     438                TMTIMER_SET_PREV(pTimer, pPrev);
     439                if (pPrev)
     440                    TMTIMER_SET_NEXT(pPrev, pTimer);
     441                else
     442                {
     443                    TMTIMER_SET_HEAD(pQueue, pTimer);
     444                    ASMAtomicWriteU64(&pQueue->u64Expire, u64Expire);
     445                    DBGFTRACE_U64_TAG2(pTimer->CTX_SUFF(pVM), u64Expire, "tmTimerQueueLinkActive head", R3STRING(pTimer->pszDesc));
     446                }
     447                TMTIMER_SET_PREV(pCur, pTimer);
     448                return;
     449            }
     450            if (!pCur->offNext)
     451            {
     452                TMTIMER_SET_NEXT(pCur, pTimer);
     453                TMTIMER_SET_PREV(pTimer, pCur);
     454                DBGFTRACE_U64_TAG2(pTimer->CTX_SUFF(pVM), u64Expire, "tmTimerQueueLinkActive tail", R3STRING(pTimer->pszDesc));
     455                return;
     456            }
     457        }
     458    }
     459    else
     460    {
     461        TMTIMER_SET_HEAD(pQueue, pTimer);
     462        ASMAtomicWriteU64(&pQueue->u64Expire, u64Expire);
     463        DBGFTRACE_U64_TAG2(pTimer->CTX_SUFF(pVM), u64Expire, "tmTimerQueueLinkActive empty", R3STRING(pTimer->pszDesc));
     464    }
     465}
     466
     467
     468
     469/**
     470 * Schedules the given timer on the given queue.
     471 *
     472 * @param   pQueue      The timer queue.
     473 * @param   pTimer      The timer that needs scheduling.
     474 *
     475 * @remarks Called while owning the lock.
     476 */
     477DECLINLINE(void) tmTimerQueueScheduleOne(PTMTIMERQUEUE pQueue, PTMTIMER pTimer)
     478{
     479    Assert(pQueue->enmClock != TMCLOCK_VIRTUAL_SYNC);
     480
     481    /*
     482     * Processing.
     483     */
     484    unsigned cRetries = 2;
     485    do
     486    {
     487        TMTIMERSTATE enmState = pTimer->enmState;
     488        switch (enmState)
     489        {
     490            /*
     491             * Reschedule timer (in the active list).
     492             */
     493            case TMTIMERSTATE_PENDING_RESCHEDULE:
     494                if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_SCHEDULE, TMTIMERSTATE_PENDING_RESCHEDULE)))
     495                    break; /* retry */
     496                tmTimerQueueUnlinkActive(pQueue, pTimer);
     497                /* fall thru */
     498
     499            /*
     500             * Schedule timer (insert into the active list).
     501             */
     502            case TMTIMERSTATE_PENDING_SCHEDULE:
     503                Assert(!pTimer->offNext); Assert(!pTimer->offPrev);
     504                if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_ACTIVE, TMTIMERSTATE_PENDING_SCHEDULE)))
     505                    break; /* retry */
     506                tmTimerQueueLinkActive(pQueue, pTimer, pTimer->u64Expire);
     507                return;
     508
     509            /*
     510             * Stop the timer in active list.
     511             */
     512            case TMTIMERSTATE_PENDING_STOP:
     513                if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_STOP_SCHEDULE, TMTIMERSTATE_PENDING_STOP)))
     514                    break; /* retry */
     515                tmTimerQueueUnlinkActive(pQueue, pTimer);
     516                /* fall thru */
     517
     518            /*
     519             * Stop the timer (not on the active list).
     520             */
     521            case TMTIMERSTATE_PENDING_STOP_SCHEDULE:
     522                Assert(!pTimer->offNext); Assert(!pTimer->offPrev);
     523                if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_STOPPED, TMTIMERSTATE_PENDING_STOP_SCHEDULE)))
     524                    break;
     525                return;
     526
     527            /*
     528             * The timer is pending destruction by TMR3TimerDestroy, our caller.
     529             * Nothing to do here.
     530             */
     531            case TMTIMERSTATE_DESTROY:
     532                break;
     533
     534            /*
     535             * Postpone these until they get into the right state.
     536             */
     537            case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
     538            case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:
     539                tmTimerLinkSchedule(pQueue, pTimer);
     540                STAM_COUNTER_INC(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatPostponed));
     541                return;
     542
     543            /*
     544             * None of these can be in the schedule.
     545             */
     546            case TMTIMERSTATE_FREE:
     547            case TMTIMERSTATE_STOPPED:
     548            case TMTIMERSTATE_ACTIVE:
     549            case TMTIMERSTATE_EXPIRED_GET_UNLINK:
     550            case TMTIMERSTATE_EXPIRED_DELIVER:
     551            default:
     552                AssertMsgFailed(("Timer (%p) in the scheduling list has an invalid state %s (%d)!",
     553                                 pTimer, tmTimerState(pTimer->enmState), pTimer->enmState));
     554                return;
     555        }
     556    } while (cRetries-- > 0);
     557}
     558
     559
     560/**
     561 * Schedules the specified timer queue.
     562 *
     563 * @param   pVM             The VM to run the timers for.
     564 * @param   pQueue          The queue to schedule.
     565 *
     566 * @remarks Called while owning the lock.
     567 */
     568void tmTimerQueueSchedule(PVM pVM, PTMTIMERQUEUE pQueue)
     569{
     570    TM_ASSERT_LOCK(pVM);
     571
     572    /*
     573     * Dequeue the scheduling list and iterate it.
     574     */
     575    int32_t offNext = ASMAtomicXchgS32(&pQueue->offSchedule, 0);
     576    Log2(("tmTimerQueueSchedule: pQueue=%p:{.enmClock=%d, offNext=%RI32, .u64Expired=%'RU64}\n", pQueue, pQueue->enmClock, offNext, pQueue->u64Expire));
     577    if (!offNext)
     578        return;
     579    PTMTIMER pNext = (PTMTIMER)((intptr_t)pQueue + offNext);
     580    while (pNext)
     581    {
     582        /*
     583         * Unlink the head timer and find the next one.
     584         */
     585        PTMTIMER pTimer = pNext;
     586        pNext = pNext->offScheduleNext ? (PTMTIMER)((intptr_t)pNext + pNext->offScheduleNext) : NULL;
     587        pTimer->offScheduleNext = 0;
     588
     589        /*
     590         * Do the scheduling.
     591         */
     592        Log2(("tmTimerQueueSchedule: %p:{.enmState=%s, .enmClock=%d, .enmType=%d, .pszDesc=%s}\n",
     593              pTimer, tmTimerState(pTimer->enmState), pTimer->enmClock, pTimer->enmType, R3STRING(pTimer->pszDesc)));
     594        tmTimerQueueScheduleOne(pQueue, pTimer);
     595        Log2(("tmTimerQueueSchedule: %p: new %s\n", pTimer, tmTimerState(pTimer->enmState)));
     596    } /* foreach timer in current schedule batch. */
     597    Log2(("tmTimerQueueSchedule: u64Expired=%'RU64\n", pQueue->u64Expire));
     598}
     599
     600
     601#ifdef VBOX_STRICT
     602/**
     603 * Checks that the timer queues are sane.
     604 *
     605 * @param   pVM     VM handle.
     606 *
     607 * @remarks Called while owning the lock.
     608 */
     609void tmTimerQueuesSanityChecks(PVM pVM, const char *pszWhere)
     610{
     611    TM_ASSERT_LOCK(pVM);
     612
     613    /*
     614     * Check the linking of the active lists.
     615     */
     616    bool fHaveVirtualSyncLock = false;
     617    for (int i = 0; i < TMCLOCK_MAX; i++)
     618    {
     619        PTMTIMERQUEUE pQueue = &pVM->tm.s.CTX_SUFF(paTimerQueues)[i];
     620        Assert((int)pQueue->enmClock == i);
     621        if (pQueue->enmClock == TMCLOCK_VIRTUAL_SYNC)
     622        {
     623            if (PDMCritSectTryEnter(&pVM->tm.s.VirtualSyncLock) != VINF_SUCCESS)
     624                continue;
     625            fHaveVirtualSyncLock = true;
     626        }
     627        PTMTIMER pPrev = NULL;
     628        for (PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue); pCur; pPrev = pCur, pCur = TMTIMER_GET_NEXT(pCur))
     629        {
     630            AssertMsg((int)pCur->enmClock == i, ("%s: %d != %d\n", pszWhere, pCur->enmClock, i));
     631            AssertMsg(TMTIMER_GET_PREV(pCur) == pPrev, ("%s: %p != %p\n", pszWhere, TMTIMER_GET_PREV(pCur), pPrev));
     632            TMTIMERSTATE enmState = pCur->enmState;
     633            switch (enmState)
     634            {
     635                case TMTIMERSTATE_ACTIVE:
     636                    AssertMsg(  !pCur->offScheduleNext
     637                              || pCur->enmState != TMTIMERSTATE_ACTIVE,
     638                              ("%s: %RI32\n", pszWhere, pCur->offScheduleNext));
     639                    break;
     640                case TMTIMERSTATE_PENDING_STOP:
     641                case TMTIMERSTATE_PENDING_RESCHEDULE:
     642                case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
     643                    break;
     644                default:
     645                    AssertMsgFailed(("%s: Invalid state enmState=%d %s\n", pszWhere, enmState, tmTimerState(enmState)));
     646                    break;
     647            }
     648        }
     649    }
     650
     651
     652# ifdef IN_RING3
     653    /*
     654     * Do the big list and check that active timers all are in the active lists.
     655     */
     656    PTMTIMERR3 pPrev = NULL;
     657    for (PTMTIMERR3 pCur = pVM->tm.s.pCreated; pCur; pPrev = pCur, pCur = pCur->pBigNext)
     658    {
     659        Assert(pCur->pBigPrev == pPrev);
     660        Assert((unsigned)pCur->enmClock < (unsigned)TMCLOCK_MAX);
     661
     662        TMTIMERSTATE enmState = pCur->enmState;
     663        switch (enmState)
     664        {
     665            case TMTIMERSTATE_ACTIVE:
     666            case TMTIMERSTATE_PENDING_STOP:
     667            case TMTIMERSTATE_PENDING_RESCHEDULE:
     668            case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
     669                if (fHaveVirtualSyncLock || pCur->enmClock != TMCLOCK_VIRTUAL_SYNC)
     670                {
     671                    PTMTIMERR3 pCurAct = TMTIMER_GET_HEAD(&pVM->tm.s.CTX_SUFF(paTimerQueues)[pCur->enmClock]);
     672                    Assert(pCur->offPrev || pCur == pCurAct);
     673                    while (pCurAct && pCurAct != pCur)
     674                        pCurAct = TMTIMER_GET_NEXT(pCurAct);
     675                    Assert(pCurAct == pCur);
     676                }
     677                break;
     678
     679            case TMTIMERSTATE_PENDING_SCHEDULE:
     680            case TMTIMERSTATE_PENDING_STOP_SCHEDULE:
     681            case TMTIMERSTATE_STOPPED:
     682            case TMTIMERSTATE_EXPIRED_DELIVER:
     683                if (fHaveVirtualSyncLock || pCur->enmClock != TMCLOCK_VIRTUAL_SYNC)
     684                {
     685                    Assert(!pCur->offNext);
     686                    Assert(!pCur->offPrev);
     687                    for (PTMTIMERR3 pCurAct = TMTIMER_GET_HEAD(&pVM->tm.s.CTX_SUFF(paTimerQueues)[pCur->enmClock]);
     688                          pCurAct;
     689                          pCurAct = TMTIMER_GET_NEXT(pCurAct))
     690                    {
     691                        Assert(pCurAct != pCur);
     692                        Assert(TMTIMER_GET_NEXT(pCurAct) != pCur);
     693                        Assert(TMTIMER_GET_PREV(pCurAct) != pCur);
     694                    }
     695                }
     696                break;
     697
     698            /* ignore */
     699            case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:
     700                break;
     701
     702            /* shouldn't get here! */
     703            case TMTIMERSTATE_EXPIRED_GET_UNLINK:
     704            case TMTIMERSTATE_DESTROY:
     705            default:
     706                AssertMsgFailed(("Invalid state enmState=%d %s\n", enmState, tmTimerState(enmState)));
     707                break;
     708        }
     709    }
     710# endif /* IN_RING3 */
     711
     712    if (fHaveVirtualSyncLock)
     713        PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock);
     714}
     715#endif /* !VBOX_STRICT */
    410716
    411717#ifdef VBOX_HIGH_RES_TIMERS_HACK
     
    8541160
    8551161/**
    856  * Links a timer into the active list of a timer queue.
    857  *
    858  * The caller must have taken the TM semaphore before calling this function.
    859  *
    860  * @param   pQueue          The queue.
    861  * @param   pTimer          The timer.
    862  * @param   u64Expire       The timer expiration time.
    863  */
    864 DECL_FORCE_INLINE(void) tmTimerActiveLink(PTMTIMERQUEUE pQueue, PTMTIMER pTimer, uint64_t u64Expire)
    865 {
    866     PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue);
    867     if (pCur)
    868     {
    869         for (;; pCur = TMTIMER_GET_NEXT(pCur))
    870         {
    871             if (pCur->u64Expire > u64Expire)
    872             {
    873                 const PTMTIMER pPrev = TMTIMER_GET_PREV(pCur);
    874                 TMTIMER_SET_NEXT(pTimer, pCur);
    875                 TMTIMER_SET_PREV(pTimer, pPrev);
    876                 if (pPrev)
    877                     TMTIMER_SET_NEXT(pPrev, pTimer);
    878                 else
    879                 {
    880                     TMTIMER_SET_HEAD(pQueue, pTimer);
    881                     pQueue->u64Expire = u64Expire;
    882                 }
    883                 TMTIMER_SET_PREV(pCur, pTimer);
    884                 return;
    885             }
    886             if (!pCur->offNext)
    887             {
    888                 TMTIMER_SET_NEXT(pCur, pTimer);
    889                 TMTIMER_SET_PREV(pTimer, pCur);
    890                 return;
    891             }
    892         }
    893     }
    894     else
    895     {
    896         TMTIMER_SET_HEAD(pQueue, pTimer);
    897         pQueue->u64Expire = u64Expire;
    898     }
    899 }
    900 
    901 
    902 /**
    9031162 * Optimized TMTimerSet code path for starting an inactive timer.
    9041163 *
     
    9151174    Assert(pTimer->enmState == TMTIMERSTATE_ACTIVE);
    9161175
     1176    TMCLOCK const enmClock = pTimer->enmClock;
     1177
    9171178    /*
    9181179     * Calculate and set the expiration time.
    9191180     */
    920     pTimer->u64Expire = u64Expire;
     1181    if (enmClock == TMCLOCK_VIRTUAL_SYNC)
     1182    {
     1183        uint64_t u64Last = ASMAtomicReadU64(&pVM->tm.s.u64VirtualSync);
     1184        AssertMsgStmt(u64Expire >= u64Last,
     1185                      ("exp=%#llx last=%#llx\n", u64Expire, u64Last),
     1186                      u64Expire = u64Last);
     1187    }
     1188    ASMAtomicWriteU64(&pTimer->u64Expire, u64Expire);
    9211189    Log2(("tmTimerSetOptimizedStart: %p:{.pszDesc='%s', .u64Expire=%'RU64}\n", pTimer, R3STRING(pTimer->pszDesc), u64Expire));
    9221190
     
    9241192     * Link the timer into the active list.
    9251193     */
    926     TMCLOCK const enmClock = pTimer->enmClock;
    927     tmTimerActiveLink(&pVM->tm.s.CTX_SUFF(paTimerQueues)[enmClock], pTimer, u64Expire);
     1194    tmTimerQueueLinkActive(&pVM->tm.s.CTX_SUFF(paTimerQueues)[enmClock], pTimer, u64Expire);
    9281195
    9291196    STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetOpt);
     
    9331200
    9341201
    935 
     1202/**
     1203 * TMTimerSet for the virtual sync timer queue.
     1204 *
     1205 * This employs a greatly simplified state machine by always acquiring the
     1206 * queue lock and bypassing the scheduling list.
     1207 *
     1208 * @returns VBox status code
     1209 * @param   pVM                 The VM handle.
     1210 * @param   pTimer              The timer handle.
     1211 * @param   u64Expire           The expiration time.
     1212 */
     1213static int tmTimerVirtualSyncSet(PVM pVM, PTMTIMER pTimer, uint64_t u64Expire)
     1214{
     1215    STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatTimerSetVs), a);
     1216    VM_ASSERT_EMT(pVM);
     1217    int rc = PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VINF_SUCCESS);
     1218    AssertRCReturn(rc, rc);
     1219
     1220    PTMTIMERQUEUE   pQueue   = &pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC];
     1221    TMTIMERSTATE    enmState = pTimer->enmState;
     1222    switch (enmState)
     1223    {
     1224        case TMTIMERSTATE_EXPIRED_DELIVER:
     1225        case TMTIMERSTATE_STOPPED:
     1226            if (enmState == TMTIMERSTATE_EXPIRED_DELIVER)
     1227                STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetVsStExpDeliver);
     1228            else
     1229                STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetVsStStopped);
     1230
     1231            AssertMsg(u64Expire >= pVM->tm.s.u64VirtualSync,
     1232                      ("%'RU64 < %'RU64 %s\n", u64Expire, pVM->tm.s.u64VirtualSync, R3STRING(pTimer->pszDesc)));
     1233            pTimer->u64Expire = u64Expire;
     1234            TM_SET_STATE(pTimer, TMTIMERSTATE_ACTIVE);
     1235            tmTimerQueueLinkActive(pQueue, pTimer, u64Expire);
     1236            rc = VINF_SUCCESS;
     1237            break;
     1238
     1239        case TMTIMERSTATE_ACTIVE:
     1240            STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetVsStActive);
     1241            tmTimerQueueUnlinkActive(pQueue, pTimer);
     1242            pTimer->u64Expire = u64Expire;
     1243            tmTimerQueueLinkActive(pQueue, pTimer, u64Expire);
     1244            rc = VINF_SUCCESS;
     1245            break;
     1246
     1247        case TMTIMERSTATE_PENDING_RESCHEDULE:
     1248        case TMTIMERSTATE_PENDING_STOP:
     1249        case TMTIMERSTATE_PENDING_SCHEDULE:
     1250        case TMTIMERSTATE_PENDING_STOP_SCHEDULE:
     1251        case TMTIMERSTATE_EXPIRED_GET_UNLINK:
     1252        case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:
     1253        case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
     1254        case TMTIMERSTATE_DESTROY:
     1255        case TMTIMERSTATE_FREE:
     1256            AssertLogRelMsgFailed(("Invalid timer state %s: %s\n", tmTimerState(enmState), R3STRING(pTimer->pszDesc)));
     1257            rc = VERR_TM_INVALID_STATE;
     1258            break;
     1259
     1260        default:
     1261            AssertMsgFailed(("Unknown timer state %d: %s\n", enmState, R3STRING(pTimer->pszDesc)));
     1262            rc = VERR_TM_UNKNOWN_STATE;
     1263            break;
     1264    }
     1265
     1266    STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerSetVs), a);
     1267    PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock);
     1268    return rc;
     1269}
    9361270
    9371271
     
    9461280{
    9471281    PVM pVM = pTimer->CTX_SUFF(pVM);
     1282
     1283    /* Treat virtual sync timers specially. */
     1284    if (pTimer->enmClock == TMCLOCK_VIRTUAL_SYNC)
     1285        return tmTimerVirtualSyncSet(pVM, pTimer, u64Expire);
     1286
    9481287    STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatTimerSet), a);
    9491288    TMTIMER_ASSERT_CRITSECT(pTimer);
    9501289
     1290    DBGFTRACE_U64_TAG2(pVM, u64Expire, "TMTimerSet", R3STRING(pTimer->pszDesc));
     1291
    9511292#ifdef VBOX_WITH_STATISTICS
    952     /* Gather optimization info. */
     1293    /*
     1294     * Gather optimization info.
     1295     */
    9531296    STAM_COUNTER_INC(&pVM->tm.s.StatTimerSet);
    9541297    TMTIMERSTATE enmOrgState = pTimer->enmState;
     
    9821325            {
    9831326                tmTimerSetOptimizedStart(pVM, pTimer, u64Expire);
    984                 STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
     1327                STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerSet), a);
    9851328                return VINF_SUCCESS;
    9861329            }
     
    10101353                    Assert(!pTimer->offPrev);
    10111354                    Assert(!pTimer->offNext);
    1012                     AssertMsg(      pTimer->enmClock != TMCLOCK_VIRTUAL_SYNC
    1013                               ||    pVM->tm.s.fVirtualSyncTicking
    1014                               ||    u64Expire >= pVM->tm.s.u64VirtualSync,
    1015                               ("%'RU64 < %'RU64 %s\n", u64Expire, pVM->tm.s.u64VirtualSync, R3STRING(pTimer->pszDesc)));
    10161355                    pTimer->u64Expire = u64Expire;
    10171356                    TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_SCHEDULE);
     
    11491488     * Link the timer into the active list.
    11501489     */
    1151     tmTimerActiveLink(&pVM->tm.s.CTX_SUFF(paTimerQueues)[enmClock], pTimer, u64Expire);
     1490    DBGFTRACE_U64_TAG2(pVM, u64Expire, "tmTimerSetRelativeOptimizedStart", R3STRING(pTimer->pszDesc));
     1491    tmTimerQueueLinkActive(&pVM->tm.s.CTX_SUFF(paTimerQueues)[enmClock], pTimer, u64Expire);
    11521492
    11531493    STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeOpt);
    11541494    tmTimerUnlock(pVM);
    11551495    return VINF_SUCCESS;
     1496}
     1497
     1498
     1499/**
     1500 * TMTimerSetRelative for the virtual sync timer queue.
     1501 *
     1502 * This employs a greatly simplified state machine by always acquiring the
     1503 * queue lock and bypassing the scheduling list.
     1504 *
     1505 * @returns VBox status code
     1506 * @param   pVM                 The VM handle.
     1507 * @param   cTicksToNext        Clock ticks until the next time expiration.
     1508 * @param   pu64Now             Where to return the current time stamp used.
     1509 *                              Optional.
     1510 */
     1511static int tmTimerVirtualSyncSetRelative(PVM pVM, PTMTIMER pTimer, uint64_t cTicksToNext, uint64_t *pu64Now)
     1512{
     1513    STAM_PROFILE_START(pVM->tm.s.CTX_SUFF_Z(StatTimerSetRelativeVs), a);
     1514    VM_ASSERT_EMT(pVM);
     1515    int rc = PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VINF_SUCCESS);
     1516    AssertRCReturn(rc, rc);
     1517
     1518    /* Calculate the expiration tick. */
     1519    uint64_t u64Expire = TMVirtualSyncGetNoCheck(pVM);
     1520    if (pu64Now)
     1521        *pu64Now = u64Expire;
     1522    u64Expire += cTicksToNext;
     1523
     1524    /* Update the timer. */
     1525    PTMTIMERQUEUE   pQueue    = &pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC];
     1526    TMTIMERSTATE    enmState  = pTimer->enmState;
     1527    switch (enmState)
     1528    {
     1529        case TMTIMERSTATE_EXPIRED_DELIVER:
     1530        case TMTIMERSTATE_STOPPED:
     1531            if (enmState == TMTIMERSTATE_EXPIRED_DELIVER)
     1532                STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeVsStExpDeliver);
     1533            else
     1534                STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeVsStStopped);
     1535            pTimer->u64Expire = u64Expire;
     1536            TM_SET_STATE(pTimer, TMTIMERSTATE_ACTIVE);
     1537            tmTimerQueueLinkActive(pQueue, pTimer, u64Expire);
     1538            rc = VINF_SUCCESS;
     1539            break;
     1540
     1541        case TMTIMERSTATE_ACTIVE:
     1542            STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeVsStActive);
     1543            tmTimerQueueUnlinkActive(pQueue, pTimer);
     1544            pTimer->u64Expire = u64Expire;
     1545            tmTimerQueueLinkActive(pQueue, pTimer, u64Expire);
     1546            rc = VINF_SUCCESS;
     1547            break;
     1548
     1549        case TMTIMERSTATE_PENDING_RESCHEDULE:
     1550        case TMTIMERSTATE_PENDING_STOP:
     1551        case TMTIMERSTATE_PENDING_SCHEDULE:
     1552        case TMTIMERSTATE_PENDING_STOP_SCHEDULE:
     1553        case TMTIMERSTATE_EXPIRED_GET_UNLINK:
     1554        case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:
     1555        case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
     1556        case TMTIMERSTATE_DESTROY:
     1557        case TMTIMERSTATE_FREE:
     1558            AssertLogRelMsgFailed(("Invalid timer state %s: %s\n", tmTimerState(enmState), R3STRING(pTimer->pszDesc)));
     1559            rc = VERR_TM_INVALID_STATE;
     1560            break;
     1561
     1562        default:
     1563            AssertMsgFailed(("Unknown timer state %d: %s\n", enmState, R3STRING(pTimer->pszDesc)));
     1564            rc = VERR_TM_UNKNOWN_STATE;
     1565            break;
     1566    }
     1567
     1568    STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerSetRelativeVs), a);
     1569    PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock);
     1570    return rc;
    11561571}
    11571572
     
    11681583VMMDECL(int) TMTimerSetRelative(PTMTIMER pTimer, uint64_t cTicksToNext, uint64_t *pu64Now)
    11691584{
    1170     STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
     1585    PVM pVM = pTimer->CTX_SUFF(pVM);
     1586
     1587    /* Treat virtual sync timers specially. */
     1588    if (pTimer->enmClock == TMCLOCK_VIRTUAL_SYNC)
     1589        return tmTimerVirtualSyncSetRelative(pVM, pTimer, cTicksToNext, pu64Now);
     1590
     1591    STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
    11711592    TMTIMER_ASSERT_CRITSECT(pTimer);
    1172     PVM             pVM = pTimer->CTX_SUFF(pVM);
    1173     int             rc;
     1593
     1594    DBGFTRACE_U64_TAG2(pVM, cTicksToNext, "TMTimerSetRelative", R3STRING(pTimer->pszDesc));
    11741595
    11751596#ifdef VBOX_WITH_STATISTICS
    1176     /* Gather optimization info. */
     1597    /*
     1598     * Gather optimization info.
     1599     */
    11771600    STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelative);
    11781601    TMTIMERSTATE enmOrgState = pTimer->enmState;
     
    12251648     * Unoptimized path.
    12261649     */
     1650    int             rc;
    12271651    TMCLOCK const   enmClock = pTimer->enmClock;
    1228     bool            fOwnVirtSyncLock;
    1229     fOwnVirtSyncLock = !fOwnTMLock
    1230                     && enmClock == TMCLOCK_VIRTUAL_SYNC
    1231                     && RT_SUCCESS(tmVirtualSyncTryLock(pVM));
    12321652    for (int cRetries = 1000; ; cRetries--)
    12331653    {
     
    13581778         */
    13591779        if (!fOwnTMLock)
    1360         {
    13611780            fOwnTMLock = RT_SUCCESS_NP(tmTimerTryLock(pVM));
    1362             if (    !fOwnTMLock
    1363                 &&  enmClock == TMCLOCK_VIRTUAL_SYNC
    1364                 &&  !fOwnVirtSyncLock)
    1365                 fOwnVirtSyncLock = RT_SUCCESS_NP(tmVirtualSyncTryLock(pVM));
    1366         }
    13671781
    13681782    } /* for (;;) */
     
    13711785     * Clean up and return.
    13721786     */
    1373     if (fOwnVirtSyncLock)
    1374         tmVirtualSyncUnlock(pVM);
    13751787    if (fOwnTMLock)
    13761788        tmTimerUnlock(pVM);
    1377 
    1378     if (    !fOwnTMLock
    1379         &&  !fOwnVirtSyncLock
    1380         &&  enmClock == TMCLOCK_VIRTUAL_SYNC)
    1381         STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeRacyVirtSync);
    13821789
    13831790    STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
     
    15181925
    15191926/**
     1927 * TMTimerStop for the virtual sync timer queue.
     1928 *
     1929 * This employs a greatly simplified state machine by always acquiring the
     1930 * queue lock and bypassing the scheduling list.
     1931 *
     1932 * @returns VBox status code
     1933 * @param   pVM                 The VM handle.
     1934 * @param   pTimer              The timer handle.
     1935 */
     1936static int tmTimerVirtualSyncStop(PVM pVM, PTMTIMER pTimer)
     1937{
     1938    STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatTimerStopVs), a);
     1939    VM_ASSERT_EMT(pVM);
     1940    int rc = PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VINF_SUCCESS);
     1941    AssertRCReturn(rc, rc);
     1942
     1943    /* Reset the HZ hint. */
     1944    if (pTimer->uHzHint)
     1945    {
     1946        if (pTimer->uHzHint >= pVM->tm.s.uMaxHzHint)
     1947            ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, true);
     1948        pTimer->uHzHint = 0;
     1949    }
     1950
     1951    /* Update the timer state. */
     1952    PTMTIMERQUEUE   pQueue   = &pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC];
     1953    TMTIMERSTATE    enmState = pTimer->enmState;
     1954    switch (enmState)
     1955    {
     1956        case TMTIMERSTATE_ACTIVE:
     1957            tmTimerQueueUnlinkActive(pQueue, pTimer);
     1958            TM_SET_STATE(pTimer, TMTIMERSTATE_STOPPED);
     1959            rc = VINF_SUCCESS;
     1960            break;
     1961
     1962        case TMTIMERSTATE_EXPIRED_DELIVER:
     1963            TM_SET_STATE(pTimer, TMTIMERSTATE_STOPPED);
     1964            rc = VINF_SUCCESS;
     1965            break;
     1966
     1967        case TMTIMERSTATE_STOPPED:
     1968            rc = VINF_SUCCESS;
     1969            break;
     1970
     1971        case TMTIMERSTATE_PENDING_RESCHEDULE:
     1972        case TMTIMERSTATE_PENDING_STOP:
     1973        case TMTIMERSTATE_PENDING_SCHEDULE:
     1974        case TMTIMERSTATE_PENDING_STOP_SCHEDULE:
     1975        case TMTIMERSTATE_EXPIRED_GET_UNLINK:
     1976        case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:
     1977        case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
     1978        case TMTIMERSTATE_DESTROY:
     1979        case TMTIMERSTATE_FREE:
     1980            AssertLogRelMsgFailed(("Invalid timer state %s: %s\n", tmTimerState(enmState), R3STRING(pTimer->pszDesc)));
     1981            rc = VERR_TM_INVALID_STATE;
     1982            break;
     1983
     1984        default:
     1985            AssertMsgFailed(("Unknown timer state %d: %s\n", enmState, R3STRING(pTimer->pszDesc)));
     1986            rc = VERR_TM_UNKNOWN_STATE;
     1987            break;
     1988    }
     1989
     1990    STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerStopVs), a);
     1991    PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock);
     1992    return rc;
     1993}
     1994
     1995
     1996/**
    15201997 * Stop the timer.
    15211998 * Use TMR3TimerArm() to "un-stop" the timer.
     
    15262003VMMDECL(int) TMTimerStop(PTMTIMER pTimer)
    15272004{
    1528     STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);
     2005    PVM pVM = pTimer->CTX_SUFF(pVM);
     2006
     2007    /* Treat virtual sync timers specially. */
     2008    if (pTimer->enmClock == TMCLOCK_VIRTUAL_SYNC)
     2009        return tmTimerVirtualSyncStop(pVM, pTimer);
     2010
     2011    STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatTimerStop), a);
    15292012    TMTIMER_ASSERT_CRITSECT(pTimer);
    15302013
    1531     /* Reset the HZ hint. */
     2014    /*
     2015     * Reset the HZ hint.
     2016     */
    15322017    if (pTimer->uHzHint)
    15332018    {
    1534         PVM pVM = pTimer->CTX_SUFF(pVM);
    15352019        if (pTimer->uHzHint >= pVM->tm.s.uMaxHzHint)
    15362020            ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, true);
     
    15572041            case TMTIMERSTATE_PENDING_STOP:
    15582042            case TMTIMERSTATE_PENDING_STOP_SCHEDULE:
    1559                 STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);
     2043                STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerStop), a);
    15602044                return VINF_SUCCESS;
    15612045
     
    15642048                {
    15652049                    tmSchedule(pTimer);
    1566                     STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);
     2050                    STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerStop), a);
    15672051                    return VINF_SUCCESS;
    15682052                }
     
    15722056                {
    15732057                    tmSchedule(pTimer);
    1574                     STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);
     2058                    STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerStop), a);
    15752059                    return VINF_SUCCESS;
    15762060                }
     
    15812065                {
    15822066                    tmSchedule(pTimer);
    1583                     STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);
     2067                    STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerStop), a);
    15842068                    return VINF_SUCCESS;
    15852069                }
     
    16112095
    16122096    AssertMsgFailed(("Failed waiting for stable state. state=%d (%s)\n", pTimer->enmState, R3STRING(pTimer->pszDesc)));
    1613     STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);
     2097    STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerStop), a);
    16142098    return VERR_INTERNAL_ERROR;
    16152099}
     
    16252109VMMDECL(uint64_t) TMTimerGet(PTMTIMER pTimer)
    16262110{
     2111    PVM pVM = pTimer->CTX_SUFF(pVM);
     2112
    16272113    uint64_t u64;
    1628     PVM      pVM   = pTimer->CTX_SUFF(pVM);
    1629 
    16302114    switch (pTimer->enmClock)
    16312115    {
     
    16412125        default:
    16422126            AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
    1643             return ~(uint64_t)0;
     2127            return UINT64_MAX;
    16442128    }
    16452129    //Log2(("TMTimerGet: returns %'RU64 (pTimer=%p:{.enmState=%s, .pszDesc='%s'})\n",
     
    18012285 * @returns timer clock ticks.
    18022286 * @param   pTimer          Timer handle as returned by one of the create functions.
    1803  * @param   u64NanoTS       The nanosecond value ticks to convert.
     2287 * @param   cNanoSecs       The nanosecond value ticks to convert.
    18042288 * @remark  There could be rounding and overflow errors here.
    18052289 */
    1806 VMMDECL(uint64_t) TMTimerFromNano(PTMTIMER pTimer, uint64_t u64NanoTS)
     2290VMMDECL(uint64_t) TMTimerFromNano(PTMTIMER pTimer, uint64_t cNanoSecs)
    18072291{
    18082292    switch (pTimer->enmClock)
     
    18112295        case TMCLOCK_VIRTUAL_SYNC:
    18122296            AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
    1813             return u64NanoTS;
     2297            return cNanoSecs;
    18142298
    18152299        case TMCLOCK_REAL:
    18162300            AssertCompile(TMCLOCK_FREQ_REAL == 1000);
    1817             return u64NanoTS / 1000000;
     2301            return cNanoSecs / 1000000;
    18182302
    18192303        default:
     
    18292313 * @returns timer clock ticks.
    18302314 * @param   pTimer          Timer handle as returned by one of the create functions.
    1831  * @param   u64MicroTS      The microsecond value ticks to convert.
     2315 * @param   cMicroSecs      The microsecond value ticks to convert.
    18322316 * @remark  There could be rounding and overflow errors here.
    18332317 */
    1834 VMMDECL(uint64_t) TMTimerFromMicro(PTMTIMER pTimer, uint64_t u64MicroTS)
     2318VMMDECL(uint64_t) TMTimerFromMicro(PTMTIMER pTimer, uint64_t cMicroSecs)
    18352319{
    18362320    switch (pTimer->enmClock)
     
    18392323        case TMCLOCK_VIRTUAL_SYNC:
    18402324            AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
    1841             return u64MicroTS * 1000;
     2325            return cMicroSecs * 1000;
    18422326
    18432327        case TMCLOCK_REAL:
    18442328            AssertCompile(TMCLOCK_FREQ_REAL == 1000);
    1845             return u64MicroTS / 1000;
     2329            return cMicroSecs / 1000;
    18462330
    18472331        default:
     
    18572341 * @returns timer clock ticks.
    18582342 * @param   pTimer          Timer handle as returned by one of the create functions.
    1859  * @param   u64MilliTS      The millisecond value ticks to convert.
     2343 * @param   cMilliSecs      The millisecond value ticks to convert.
    18602344 * @remark  There could be rounding and overflow errors here.
    18612345 */
    1862 VMMDECL(uint64_t) TMTimerFromMilli(PTMTIMER pTimer, uint64_t u64MilliTS)
     2346VMMDECL(uint64_t) TMTimerFromMilli(PTMTIMER pTimer, uint64_t cMilliSecs)
    18632347{
    18642348    switch (pTimer->enmClock)
     
    18672351        case TMCLOCK_VIRTUAL_SYNC:
    18682352            AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
    1869             return u64MilliTS * 1000000;
     2353            return cMilliSecs * 1000000;
    18702354
    18712355        case TMCLOCK_REAL:
    18722356            AssertCompile(TMCLOCK_FREQ_REAL == 1000);
    1873             return u64MilliTS;
     2357            return cMilliSecs;
    18742358
    18752359        default:
     
    19512435VMMDECL(bool) TMTimerIsActive(PTMTIMER pTimer)
    19522436{
    1953     TMTIMERSTATE    enmState = pTimer->enmState;
     2437    TMTIMERSTATE enmState = pTimer->enmState;
    19542438    switch (enmState)
    19552439    {
     
    19852469            return false;
    19862470    }
     2471}
     2472
     2473
     2474/**
     2475 * Gets the current warp drive percent.
     2476 *
     2477 * @returns The warp drive percent.
     2478 * @param   pVM         The VM handle.
     2479 */
     2480VMMDECL(uint32_t) TMGetWarpDrive(PVM pVM)
     2481{
     2482    return pVM->tm.s.u32VirtualWarpDrivePercentage;
    19872483}
    19882484
     
    20192515#undef CASE
    20202516    }
    2021 }
    2022 
    2023 
    2024 /**
    2025  * Schedules the given timer on the given queue.
    2026  *
    2027  * @param   pQueue      The timer queue.
    2028  * @param   pTimer      The timer that needs scheduling.
    2029  *
    2030  * @remarks Called while owning the lock.
    2031  */
    2032 DECLINLINE(void) tmTimerQueueScheduleOne(PTMTIMERQUEUE pQueue, PTMTIMER pTimer)
    2033 {
    2034     /*
    2035      * Processing.
    2036      */
    2037     unsigned cRetries = 2;
    2038     do
    2039     {
    2040         TMTIMERSTATE enmState = pTimer->enmState;
    2041         switch (enmState)
    2042         {
    2043             /*
    2044              * Reschedule timer (in the active list).
    2045              */
    2046             case TMTIMERSTATE_PENDING_RESCHEDULE:
    2047             {
    2048                 if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_SCHEDULE, TMTIMERSTATE_PENDING_RESCHEDULE)))
    2049                     break; /* retry */
    2050 
    2051                 const PTMTIMER pPrev = TMTIMER_GET_PREV(pTimer);
    2052                 const PTMTIMER pNext = TMTIMER_GET_NEXT(pTimer);
    2053                 if (pPrev)
    2054                     TMTIMER_SET_NEXT(pPrev, pNext);
    2055                 else
    2056                 {
    2057                     TMTIMER_SET_HEAD(pQueue, pNext);
    2058                     pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX;
    2059                 }
    2060                 if (pNext)
    2061                     TMTIMER_SET_PREV(pNext, pPrev);
    2062                 pTimer->offNext = 0;
    2063                 pTimer->offPrev = 0;
    2064                 /* fall thru */
    2065             }
    2066 
    2067             /*
    2068              * Schedule timer (insert into the active list).
    2069              */
    2070             case TMTIMERSTATE_PENDING_SCHEDULE:
    2071             {
    2072                 Assert(!pTimer->offNext); Assert(!pTimer->offPrev);
    2073                 if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_ACTIVE, TMTIMERSTATE_PENDING_SCHEDULE)))
    2074                     break; /* retry */
    2075 
    2076                 PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue);
    2077                 if (pCur)
    2078                 {
    2079                     const uint64_t u64Expire = pTimer->u64Expire;
    2080                     for (;; pCur = TMTIMER_GET_NEXT(pCur))
    2081                     {
    2082                         if (pCur->u64Expire > u64Expire)
    2083                         {
    2084                             const PTMTIMER pPrev = TMTIMER_GET_PREV(pCur);
    2085                             TMTIMER_SET_NEXT(pTimer, pCur);
    2086                             TMTIMER_SET_PREV(pTimer, pPrev);
    2087                             if (pPrev)
    2088                                 TMTIMER_SET_NEXT(pPrev, pTimer);
    2089                             else
    2090                             {
    2091                                 TMTIMER_SET_HEAD(pQueue, pTimer);
    2092                                 pQueue->u64Expire = u64Expire;
    2093                             }
    2094                             TMTIMER_SET_PREV(pCur, pTimer);
    2095                             return;
    2096                         }
    2097                         if (!pCur->offNext)
    2098                         {
    2099                             TMTIMER_SET_NEXT(pCur, pTimer);
    2100                             TMTIMER_SET_PREV(pTimer, pCur);
    2101                             return;
    2102                         }
    2103                     }
    2104                 }
    2105                 else
    2106                 {
    2107                     TMTIMER_SET_HEAD(pQueue, pTimer);
    2108                     pQueue->u64Expire = pTimer->u64Expire;
    2109                 }
    2110                 return;
    2111             }
    2112 
    2113             /*
    2114              * Stop the timer in active list.
    2115              */
    2116             case TMTIMERSTATE_PENDING_STOP:
    2117             {
    2118                 if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_STOP_SCHEDULE, TMTIMERSTATE_PENDING_STOP)))
    2119                     break; /* retry */
    2120 
    2121                 const PTMTIMER pPrev = TMTIMER_GET_PREV(pTimer);
    2122                 const PTMTIMER pNext = TMTIMER_GET_NEXT(pTimer);
    2123                 if (pPrev)
    2124                     TMTIMER_SET_NEXT(pPrev, pNext);
    2125                 else
    2126                 {
    2127                     TMTIMER_SET_HEAD(pQueue, pNext);
    2128                     pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX;
    2129                 }
    2130                 if (pNext)
    2131                     TMTIMER_SET_PREV(pNext, pPrev);
    2132                 pTimer->offNext = 0;
    2133                 pTimer->offPrev = 0;
    2134                 /* fall thru */
    2135             }
    2136 
    2137             /*
    2138              * Stop the timer (not on the active list).
    2139              */
    2140             case TMTIMERSTATE_PENDING_STOP_SCHEDULE:
    2141                 Assert(!pTimer->offNext); Assert(!pTimer->offPrev);
    2142                 if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_STOPPED, TMTIMERSTATE_PENDING_STOP_SCHEDULE)))
    2143                     break;
    2144                 return;
    2145 
    2146             /*
    2147              * The timer is pending destruction by TMR3TimerDestroy, our caller.
    2148              * Nothing to do here.
    2149              */
    2150             case TMTIMERSTATE_DESTROY:
    2151                 break;
    2152 
    2153             /*
    2154              * Postpone these until they get into the right state.
    2155              */
    2156             case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
    2157             case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:
    2158                 tmTimerLink(pQueue, pTimer);
    2159                 STAM_COUNTER_INC(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatPostponed));
    2160                 return;
    2161 
    2162             /*
    2163              * None of these can be in the schedule.
    2164              */
    2165             case TMTIMERSTATE_FREE:
    2166             case TMTIMERSTATE_STOPPED:
    2167             case TMTIMERSTATE_ACTIVE:
    2168             case TMTIMERSTATE_EXPIRED_GET_UNLINK:
    2169             case TMTIMERSTATE_EXPIRED_DELIVER:
    2170             default:
    2171                 AssertMsgFailed(("Timer (%p) in the scheduling list has an invalid state %s (%d)!",
    2172                                  pTimer, tmTimerState(pTimer->enmState), pTimer->enmState));
    2173                 return;
    2174         }
    2175     } while (cRetries-- > 0);
    2176 }
    2177 
    2178 
    2179 /**
    2180  * Schedules the specified timer queue.
    2181  *
    2182  * @param   pVM             The VM to run the timers for.
    2183  * @param   pQueue          The queue to schedule.
    2184  *
    2185  * @remarks Called while owning the lock.
    2186  */
    2187 void tmTimerQueueSchedule(PVM pVM, PTMTIMERQUEUE pQueue)
    2188 {
    2189     TM_ASSERT_LOCK(pVM);
    2190 
    2191     /*
    2192      * Dequeue the scheduling list and iterate it.
    2193      */
    2194     int32_t offNext = ASMAtomicXchgS32(&pQueue->offSchedule, 0);
    2195     Log2(("tmTimerQueueSchedule: pQueue=%p:{.enmClock=%d, offNext=%RI32, .u64Expired=%'RU64}\n", pQueue, pQueue->enmClock, offNext, pQueue->u64Expire));
    2196     if (!offNext)
    2197         return;
    2198     PTMTIMER pNext = (PTMTIMER)((intptr_t)pQueue + offNext);
    2199     while (pNext)
    2200     {
    2201         /*
    2202          * Unlink the head timer and find the next one.
    2203          */
    2204         PTMTIMER pTimer = pNext;
    2205         pNext = pNext->offScheduleNext ? (PTMTIMER)((intptr_t)pNext + pNext->offScheduleNext) : NULL;
    2206         pTimer->offScheduleNext = 0;
    2207 
    2208         /*
    2209          * Do the scheduling.
    2210          */
    2211         Log2(("tmTimerQueueSchedule: %p:{.enmState=%s, .enmClock=%d, .enmType=%d, .pszDesc=%s}\n",
    2212               pTimer, tmTimerState(pTimer->enmState), pTimer->enmClock, pTimer->enmType, R3STRING(pTimer->pszDesc)));
    2213         tmTimerQueueScheduleOne(pQueue, pTimer);
    2214         Log2(("tmTimerQueueSchedule: %p: new %s\n", pTimer, tmTimerState(pTimer->enmState)));
    2215     } /* foreach timer in current schedule batch. */
    2216     Log2(("tmTimerQueueSchedule: u64Expired=%'RU64\n", pQueue->u64Expire));
    2217 }
    2218 
    2219 
    2220 #ifdef VBOX_STRICT
    2221 /**
    2222  * Checks that the timer queues are sane.
    2223  *
    2224  * @param   pVM     VM handle.
    2225  *
    2226  * @remarks Called while owning the lock.
    2227  */
    2228 void tmTimerQueuesSanityChecks(PVM pVM, const char *pszWhere)
    2229 {
    2230     TM_ASSERT_LOCK(pVM);
    2231 
    2232     /*
    2233      * Check the linking of the active lists.
    2234      */
    2235     for (int i = 0; i < TMCLOCK_MAX; i++)
    2236     {
    2237         PTMTIMERQUEUE pQueue = &pVM->tm.s.CTX_SUFF(paTimerQueues)[i];
    2238         Assert((int)pQueue->enmClock == i);
    2239         PTMTIMER pPrev = NULL;
    2240         for (PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue); pCur; pPrev = pCur, pCur = TMTIMER_GET_NEXT(pCur))
    2241         {
    2242             AssertMsg((int)pCur->enmClock == i, ("%s: %d != %d\n", pszWhere, pCur->enmClock, i));
    2243             AssertMsg(TMTIMER_GET_PREV(pCur) == pPrev, ("%s: %p != %p\n", pszWhere, TMTIMER_GET_PREV(pCur), pPrev));
    2244             TMTIMERSTATE enmState = pCur->enmState;
    2245             switch (enmState)
    2246             {
    2247                 case TMTIMERSTATE_ACTIVE:
    2248                     AssertMsg(  !pCur->offScheduleNext
    2249                               || pCur->enmState != TMTIMERSTATE_ACTIVE,
    2250                               ("%s: %RI32\n", pszWhere, pCur->offScheduleNext));
    2251                     break;
    2252                 case TMTIMERSTATE_PENDING_STOP:
    2253                 case TMTIMERSTATE_PENDING_RESCHEDULE:
    2254                 case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
    2255                     break;
    2256                 default:
    2257                     AssertMsgFailed(("%s: Invalid state enmState=%d %s\n", pszWhere, enmState, tmTimerState(enmState)));
    2258                     break;
    2259             }
    2260         }
    2261     }
    2262 
    2263 
    2264 # ifdef IN_RING3
    2265     /*
    2266      * Do the big list and check that active timers all are in the active lists.
    2267      */
    2268     PTMTIMERR3 pPrev = NULL;
    2269     for (PTMTIMERR3 pCur = pVM->tm.s.pCreated; pCur; pPrev = pCur, pCur = pCur->pBigNext)
    2270     {
    2271         Assert(pCur->pBigPrev == pPrev);
    2272         Assert((unsigned)pCur->enmClock < (unsigned)TMCLOCK_MAX);
    2273 
    2274         TMTIMERSTATE enmState = pCur->enmState;
    2275         switch (enmState)
    2276         {
    2277             case TMTIMERSTATE_ACTIVE:
    2278             case TMTIMERSTATE_PENDING_STOP:
    2279             case TMTIMERSTATE_PENDING_RESCHEDULE:
    2280             case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
    2281             {
    2282                 PTMTIMERR3 pCurAct = TMTIMER_GET_HEAD(&pVM->tm.s.CTX_SUFF(paTimerQueues)[pCur->enmClock]);
    2283                 Assert(pCur->offPrev || pCur == pCurAct);
    2284                 while (pCurAct && pCurAct != pCur)
    2285                     pCurAct = TMTIMER_GET_NEXT(pCurAct);
    2286                 Assert(pCurAct == pCur);
    2287                 break;
    2288             }
    2289 
    2290             case TMTIMERSTATE_PENDING_SCHEDULE:
    2291             case TMTIMERSTATE_PENDING_STOP_SCHEDULE:
    2292             case TMTIMERSTATE_STOPPED:
    2293             case TMTIMERSTATE_EXPIRED_DELIVER:
    2294             {
    2295                 Assert(!pCur->offNext);
    2296                 Assert(!pCur->offPrev);
    2297                 for (PTMTIMERR3 pCurAct = TMTIMER_GET_HEAD(&pVM->tm.s.CTX_SUFF(paTimerQueues)[pCur->enmClock]);
    2298                       pCurAct;
    2299                       pCurAct = TMTIMER_GET_NEXT(pCurAct))
    2300                 {
    2301                     Assert(pCurAct != pCur);
    2302                     Assert(TMTIMER_GET_NEXT(pCurAct) != pCur);
    2303                     Assert(TMTIMER_GET_PREV(pCurAct) != pCur);
    2304                 }
    2305                 break;
    2306             }
    2307 
    2308             /* ignore */
    2309             case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:
    2310                 break;
    2311 
    2312             /* shouldn't get here! */
    2313             case TMTIMERSTATE_EXPIRED_GET_UNLINK:
    2314             case TMTIMERSTATE_DESTROY:
    2315             default:
    2316                 AssertMsgFailed(("Invalid state enmState=%d %s\n", enmState, tmTimerState(enmState)));
    2317                 break;
    2318         }
    2319     }
    2320 # endif /* IN_RING3 */
    2321 }
    2322 #endif /* !VBOX_STRICT */
    2323 
    2324 
    2325 /**
    2326  * Gets the current warp drive percent.
    2327  *
    2328  * @returns The warp drive percent.
    2329  * @param   pVM         The VM handle.
    2330  */
    2331 VMMDECL(uint32_t) TMGetWarpDrive(PVM pVM)
    2332 {
    2333     return pVM->tm.s.u32VirtualWarpDrivePercentage;
    23342517}
    23352518
  • trunk/src/VBox/VMM/VMMAll/TMAllVirtual.cpp

    r37439 r37517  
    462462     */
    463463    u64 -= off;
     464
     465    uint64_t u64Last = ASMAtomicUoReadU64(&pVM->tm.s.u64VirtualSync);
     466    if (u64Last > u64)
     467    {
     468        u64 = u64Last + 1;
     469        STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetAdjLast);
     470    }
     471
    464472    uint64_t u64Expire = ASMAtomicReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire);
    465473    if (u64 < u64Expire)
    466474    {
     475        ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSync, u64);
    467476        if (fUpdateOff)
    468477            ASMAtomicWriteU64(&pVM->tm.s.offVirtualSync, off);
     
    551560     */
    552561    u64 -= off;
     562
     563    uint64_t u64Last = ASMAtomicUoReadU64(&pVM->tm.s.u64VirtualSync);
     564    if (u64Last > u64)
     565    {
     566        u64 = u64Last + 1;
     567        STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetAdjLast);
     568    }
     569
    553570    uint64_t u64Expire = ASMAtomicReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire);
    554571    if (u64 < u64Expire)
    555572    {
     573        ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSync, u64);
    556574        tmVirtualSyncUnlock(pVM);
    557575        if (pcNsToDeadline)
     
    632650        }
    633651    }
     652
     653    /*
     654     * If we can get the lock, get it.  The result is much more reliable.
     655     *
     656     * Note! This is where all clock source devices branch off because they
     657     *       will be owning the lock already.  The 'else' is taken by code
     658     *       which is less picky or hasn't been adjusted yet
     659     */
     660    if (tmVirtualSyncTryLock(pVM) == VINF_SUCCESS)
     661        return tmVirtualSyncGetLocked(pVM, u64, pcNsToDeadline);
    634662
    635663    /*
     
    773801     */
    774802    u64 -= off;
     803/** @todo u64VirtualSyncLast */
    775804    uint64_t u64Expire = ASMAtomicReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire);
    776805    if (u64 >= u64Expire)
  • trunk/src/VBox/VMM/VMMR3/TM.cpp

    r37466 r37517  
    127127#include <VBox/vmm/ssm.h>
    128128#include <VBox/vmm/dbgf.h>
     129#include <VBox/vmm/dbgftrace.h>
    129130#include <VBox/vmm/rem.h>
    130131#include <VBox/vmm/pdmapi.h>
     
    147148#include <iprt/string.h>
    148149#include <iprt/env.h>
     150
     151#include "TMInline.h"
    149152
    150153
     
    617620    STAM_REG(pVM, &pVM->tm.s.StatScheduleSetFF,                       STAMTYPE_COUNTER, "/TM/ScheduleSetFF",                   STAMUNIT_OCCURENCES, "The number of times the timer FF was set instead of doing scheduling.");
    618621
    619     STAM_REG(pVM, &pVM->tm.s.StatTimerSet,                            STAMTYPE_COUNTER, "/TM/TimerSet",                        STAMUNIT_OCCURENCES, "Calls");
     622    STAM_REG(pVM, &pVM->tm.s.StatTimerSet,                            STAMTYPE_COUNTER, "/TM/TimerSet",                        STAMUNIT_OCCURENCES, "Calls, except virtual sync timers");
    620623    STAM_REG(pVM, &pVM->tm.s.StatTimerSetOpt,                         STAMTYPE_COUNTER, "/TM/TimerSet/Opt",                    STAMUNIT_OCCURENCES, "Optimized path taken.");
    621624    STAM_REG(pVM, &pVM->tm.s.StatTimerSetR3,                          STAMTYPE_PROFILE, "/TM/TimerSet/R3",                 STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSet calls made in ring-3.");
     
    630633    STAM_REG(pVM, &pVM->tm.s.StatTimerSetStStopped,                   STAMTYPE_COUNTER, "/TM/TimerSet/StStopped",              STAMUNIT_OCCURENCES, "STOPPED");
    631634
    632     STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelative,                    STAMTYPE_COUNTER, "/TM/TimerSetRelative",                STAMUNIT_OCCURENCES, "Calls");
     635    STAM_REG(pVM, &pVM->tm.s.StatTimerSetVs,                          STAMTYPE_COUNTER, "/TM/TimerSetVs",                      STAMUNIT_OCCURENCES, "TMTimerSet calls on virtual sync timers");
     636    STAM_REG(pVM, &pVM->tm.s.StatTimerSetVsR3,                        STAMTYPE_PROFILE, "/TM/TimerSetVs/R3",               STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSet calls made in ring-3 on virtual sync timers.");
     637    STAM_REG(pVM, &pVM->tm.s.StatTimerSetVsRZ,                        STAMTYPE_PROFILE, "/TM/TimerSetVs/RZ",               STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSet calls made in ring-0 / RC on virtual sync timers.");
     638    STAM_REG(pVM, &pVM->tm.s.StatTimerSetVsStActive,                  STAMTYPE_COUNTER, "/TM/TimerSetVs/StActive",             STAMUNIT_OCCURENCES, "ACTIVE");
     639    STAM_REG(pVM, &pVM->tm.s.StatTimerSetVsStExpDeliver,              STAMTYPE_COUNTER, "/TM/TimerSetVs/StExpDeliver",         STAMUNIT_OCCURENCES, "EXPIRED_DELIVER");
     640    STAM_REG(pVM, &pVM->tm.s.StatTimerSetVsStStopped,                 STAMTYPE_COUNTER, "/TM/TimerSetVs/StStopped",            STAMUNIT_OCCURENCES, "STOPPED");
     641
     642    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelative,                    STAMTYPE_COUNTER, "/TM/TimerSetRelative",                STAMUNIT_OCCURENCES, "Calls, except virtual sync timers");
    633643    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeOpt,                 STAMTYPE_COUNTER, "/TM/TimerSetRelative/Opt",            STAMUNIT_OCCURENCES, "Optimized path taken.");
    634     STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeR3,                  STAMTYPE_PROFILE, "/TM/TimerSetRelative/R3",         STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetRelative calls made in ring-3.");
    635     STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeRZ,                  STAMTYPE_PROFILE, "/TM/TimerSetRelative/RZ",         STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetReltaive calls made in ring-0 / RC.");
    636     STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeRacyVirtSync,        STAMTYPE_COUNTER, "/TM/TimerSetRelative/RacyVirtSync",   STAMUNIT_OCCURENCES, "Potentially racy virtual sync timer update.");
     644    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeR3,                  STAMTYPE_PROFILE, "/TM/TimerSetRelative/R3",         STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetRelative calls made in ring-3 (sans virtual sync).");
     645    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeRZ,                  STAMTYPE_PROFILE, "/TM/TimerSetRelative/RZ",         STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetReltaive calls made in ring-0 / RC (sans virtual sync).");
    637646    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStActive,            STAMTYPE_COUNTER, "/TM/TimerSetRelative/StActive",       STAMUNIT_OCCURENCES, "ACTIVE");
    638647    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStExpDeliver,        STAMTYPE_COUNTER, "/TM/TimerSetRelative/StExpDeliver",   STAMUNIT_OCCURENCES, "EXPIRED_DELIVER");
     
    644653    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStStopped,           STAMTYPE_COUNTER, "/TM/TimerSetRelative/StStopped",      STAMUNIT_OCCURENCES, "STOPPED");
    645654
     655    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeVs,                  STAMTYPE_COUNTER, "/TM/TimerSetRelativeVs",              STAMUNIT_OCCURENCES, "TMTimerSetRelative calls on virtual sync timers");
     656    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeVsR3,                STAMTYPE_PROFILE, "/TM/TimerSetRelativeVs/R3",       STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetRelative calls made in ring-3 on virtual sync timers.");
     657    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeVsRZ,                STAMTYPE_PROFILE, "/TM/TimerSetRelativeVs/RZ",       STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetReltaive calls made in ring-0 / RC on virtual sync timers.");
     658    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeVsStActive,          STAMTYPE_COUNTER, "/TM/TimerSetRelativeVs/StActive",     STAMUNIT_OCCURENCES, "ACTIVE");
     659    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeVsStExpDeliver,      STAMTYPE_COUNTER, "/TM/TimerSetRelativeVs/StExpDeliver", STAMUNIT_OCCURENCES, "EXPIRED_DELIVER");
     660    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeVsStStopped,         STAMTYPE_COUNTER, "/TM/TimerSetRelativeVs/StStopped",    STAMUNIT_OCCURENCES, "STOPPED");
     661
    646662    STAM_REG(pVM, &pVM->tm.s.StatTimerStopR3,                         STAMTYPE_PROFILE, "/TM/TimerStopR3",                 STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerStop calls made in ring-3.");
    647663    STAM_REG(pVM, &pVM->tm.s.StatTimerStopRZ,                         STAMTYPE_PROFILE, "/TM/TimerStopRZ",                 STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerStop calls made in ring-0 / RC.");
     
    650666    STAM_REG(pVM, &pVM->tm.s.StatVirtualGetSetFF,                     STAMTYPE_COUNTER, "/TM/VirtualGetSetFF",                 STAMUNIT_OCCURENCES, "Times we set the FF when calling TMTimerGet.");
    651667    STAM_REG(pVM, &pVM->tm.s.StatVirtualSyncGet,                      STAMTYPE_COUNTER, "/TM/VirtualSyncGet",                  STAMUNIT_OCCURENCES, "The number of times tmVirtualSyncGetEx was called.");
     668    STAM_REG(pVM, &pVM->tm.s.StatVirtualSyncGetAdjLast,               STAMTYPE_COUNTER, "/TM/VirtualSyncGet/AdjLast",          STAMUNIT_OCCURENCES, "Times we've adjusted against the last returned time stamp .");
    652669    STAM_REG(pVM, &pVM->tm.s.StatVirtualSyncGetELoop,                 STAMTYPE_COUNTER, "/TM/VirtualSyncGet/ELoop",            STAMUNIT_OCCURENCES, "Times tmVirtualSyncGetEx has given up getting a consistent virtual sync data set.");
    653670    STAM_REG(pVM, &pVM->tm.s.StatVirtualSyncGetExpired,               STAMTYPE_COUNTER, "/TM/VirtualSyncGet/Expired",          STAMUNIT_OCCURENCES, "Times tmVirtualSyncGetEx encountered an expired timer stopping the clock.");
     
    18981915    VMCPU_FF_CLEAR(pVCpuDst, VMCPU_FF_TIMER);   /* Clear the FF once we started working for real. */
    18991916
    1900     if (pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC].offSchedule)
    1901         tmTimerQueueSchedule(pVM, &pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC]);
     1917    Assert(!pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC].offSchedule);
    19021918    tmR3TimerQueueRunVirtualSync(pVM);
    19031919    if (pVM->tm.s.fVirtualSyncTicking) /** @todo move into tmR3TimerQueueRunVirtualSync - FIXME */
     
    20342050 * @param   pVM             The VM to run the timers for.
    20352051 *
    2036  * @remarks The caller must own both the TM/EMT and the Virtual Sync locks.
     2052 * @remarks The caller must the Virtual Sync lock.  Owning the TM lock is no
     2053 *          longer important.
    20372054 */
    20382055static void tmR3TimerQueueRunVirtualSync(PVM pVM)
     
    20402057    PTMTIMERQUEUE const pQueue = &pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC];
    20412058    VM_ASSERT_EMT(pVM);
     2059    Assert(PDMCritSectIsOwner(&pVM->tm.s.VirtualSyncLock));
    20422060
    20432061    /*
     
    21032121        u64Now = u64VirtualNow - off;
    21042122
     2123        /* Adjust against last returned time. */
     2124        uint64_t u64Last = ASMAtomicUoReadU64(&pVM->tm.s.u64VirtualSync);
     2125        if (u64Last > u64Now)
     2126        {
     2127            u64Now = u64Last + 1;
     2128            STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetAdjLast);
     2129        }
     2130
    21052131        /* Check if stopped by expired timer. */
    21062132        uint64_t u64Expire = pNext->u64Expire;
     
    21132139            Log4(("TM: %'RU64/-%'8RU64: exp tmr [tmR3TimerQueueRunVirtualSync]\n", u64Now, u64VirtualNow - u64Now - offSyncGivenUp));
    21142140        }
    2115         else if (fUpdateStuff)
     2141        else
    21162142        {
    2117             ASMAtomicWriteU64(&pVM->tm.s.offVirtualSync, off);
    2118             ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSyncCatchUpPrev, u64VirtualNow);
    2119             if (fStopCatchup)
     2143            ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSync, u64Now);
     2144            if (fUpdateStuff)
    21202145            {
    2121                 ASMAtomicWriteBool(&pVM->tm.s.fVirtualSyncCatchUp, false);
    2122                 Log4(("TM: %'RU64/0: caught up [tmR3TimerQueueRunVirtualSync]\n", u64VirtualNow));
     2146                ASMAtomicWriteU64(&pVM->tm.s.offVirtualSync, off);
     2147                ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSyncCatchUpPrev, u64VirtualNow);
     2148                ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSync, u64Now);
     2149                if (fStopCatchup)
     2150                {
     2151                    ASMAtomicWriteBool(&pVM->tm.s.fVirtualSyncCatchUp, false);
     2152                    Log4(("TM: %'RU64/0: caught up [tmR3TimerQueueRunVirtualSync]\n", u64VirtualNow));
     2153                }
    21232154            }
    21242155        }
     
    21482179    while (pNext && pNext->u64Expire <= u64Max)
    21492180    {
    2150         PTMTIMER        pTimer    = pNext;
     2181        /* Advance */
     2182        PTMTIMER pTimer = pNext;
    21512183        pNext = TMTIMER_GET_NEXT(pTimer);
    2152         PPDMCRITSECT    pCritSect = pTimer->pCritSect;
     2184
     2185        /* Take the associated lock. */
     2186        PPDMCRITSECT pCritSect = pTimer->pCritSect;
    21532187        if (pCritSect)
    21542188            PDMCritSectEnter(pCritSect, VERR_INTERNAL_ERROR);
     2189
    21552190        Log2(("tmR3TimerQueueRun: %p:{.enmState=%s, .enmClock=%d, .enmType=%d, u64Expire=%llx (now=%llx) .pszDesc=%s}\n",
    21562191              pTimer, tmTimerState(pTimer->enmState), pTimer->enmClock, pTimer->enmType, pTimer->u64Expire, u64Now, pTimer->pszDesc));
    2157         bool fRc;
    2158         TM_TRY_SET_STATE(pTimer, TMTIMERSTATE_EXPIRED_GET_UNLINK, TMTIMERSTATE_ACTIVE, fRc);
    2159         if (fRc)
    2160         {
    2161             /* unlink */
    2162             const PTMTIMER pPrev = TMTIMER_GET_PREV(pTimer);
    2163             if (pPrev)
    2164                 TMTIMER_SET_NEXT(pPrev, pNext);
    2165             else
    2166             {
    2167                 TMTIMER_SET_HEAD(pQueue, pNext);
    2168                 pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX;
    2169             }
    2170             if (pNext)
    2171                 TMTIMER_SET_PREV(pNext, pPrev);
    2172             pTimer->offNext = 0;
    2173             pTimer->offPrev = 0;
    2174 
    2175             /* advance the clock - don't permit timers to be out of order or armed in the 'past'. */
     2192
     2193        /* Advance the clock - don't permit timers to be out of order or armed
     2194           in the 'past'. */
    21762195#ifdef DEBUG_bird
    21772196#ifdef VBOX_STRICT
    2178             AssertMsg(pTimer->u64Expire >= u64Prev, ("%'RU64 < %'RU64 %s\n", pTimer->u64Expire, u64Prev, pTimer->pszDesc));
    2179             u64Prev = pTimer->u64Expire;
     2197        AssertMsg(pTimer->u64Expire >= u64Prev, ("%'RU64 < %'RU64 %s\n", pTimer->u64Expire, u64Prev, pTimer->pszDesc));
     2198        u64Prev = pTimer->u64Expire;
    21802199#endif
    21812200#endif
    2182             ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSync, pTimer->u64Expire);
    2183             ASMAtomicWriteBool(&pVM->tm.s.fVirtualSyncTicking, false);
    2184 
    2185             /* fire */
    2186             TM_SET_STATE(pTimer, TMTIMERSTATE_EXPIRED_DELIVER);
    2187             switch (pTimer->enmType)
    2188             {
    2189                 case TMTIMERTYPE_DEV:       pTimer->u.Dev.pfnTimer(pTimer->u.Dev.pDevIns, pTimer, pTimer->pvUser); break;
    2190                 case TMTIMERTYPE_USB:       pTimer->u.Usb.pfnTimer(pTimer->u.Usb.pUsbIns, pTimer, pTimer->pvUser); break;
    2191                 case TMTIMERTYPE_DRV:       pTimer->u.Drv.pfnTimer(pTimer->u.Drv.pDrvIns, pTimer, pTimer->pvUser); break;
    2192                 case TMTIMERTYPE_INTERNAL:  pTimer->u.Internal.pfnTimer(pVM, pTimer, pTimer->pvUser); break;
    2193                 case TMTIMERTYPE_EXTERNAL:  pTimer->u.External.pfnTimer(pTimer->pvUser); break;
    2194                 default:
    2195                     AssertMsgFailed(("Invalid timer type %d (%s)\n", pTimer->enmType, pTimer->pszDesc));
    2196                     break;
    2197             }
    2198 
    2199             /* Change the state if it wasn't changed already in the handler.
    2200                Reset the Hz hint too since this is the same as TMTimerStop. */
    2201             TM_TRY_SET_STATE(pTimer, TMTIMERSTATE_STOPPED, TMTIMERSTATE_EXPIRED_DELIVER, fRc);
    2202             if (fRc && pTimer->uHzHint)
    2203             {
    2204                 if (pTimer->uHzHint >= pVM->tm.s.uMaxHzHint)
    2205                     ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, true);
    2206                 pTimer->uHzHint = 0;
    2207             }
    2208             Log2(("tmR3TimerQueueRun: new state %s\n", tmTimerState(pTimer->enmState)));
     2201        ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSync, pTimer->u64Expire);
     2202        ASMAtomicWriteBool(&pVM->tm.s.fVirtualSyncTicking, false);
     2203
     2204        /* Unlink it, change the state and do the callout. */
     2205        tmTimerQueueUnlinkActive(pQueue, pTimer);
     2206        TM_SET_STATE(pTimer, TMTIMERSTATE_EXPIRED_DELIVER);
     2207        switch (pTimer->enmType)
     2208        {
     2209            case TMTIMERTYPE_DEV:       pTimer->u.Dev.pfnTimer(pTimer->u.Dev.pDevIns, pTimer, pTimer->pvUser); break;
     2210            case TMTIMERTYPE_USB:       pTimer->u.Usb.pfnTimer(pTimer->u.Usb.pUsbIns, pTimer, pTimer->pvUser); break;
     2211            case TMTIMERTYPE_DRV:       pTimer->u.Drv.pfnTimer(pTimer->u.Drv.pDrvIns, pTimer, pTimer->pvUser); break;
     2212            case TMTIMERTYPE_INTERNAL:  pTimer->u.Internal.pfnTimer(pVM, pTimer, pTimer->pvUser); break;
     2213            case TMTIMERTYPE_EXTERNAL:  pTimer->u.External.pfnTimer(pTimer->pvUser); break;
     2214            default:
     2215                AssertMsgFailed(("Invalid timer type %d (%s)\n", pTimer->enmType, pTimer->pszDesc));
     2216                break;
    22092217        }
     2218
     2219        /* Change the state if it wasn't changed already in the handler.
     2220           Reset the Hz hint too since this is the same as TMTimerStop. */
     2221        bool fRc;
     2222        TM_TRY_SET_STATE(pTimer, TMTIMERSTATE_STOPPED, TMTIMERSTATE_EXPIRED_DELIVER, fRc);
     2223        if (fRc && pTimer->uHzHint)
     2224        {
     2225            if (pTimer->uHzHint >= pVM->tm.s.uMaxHzHint)
     2226                ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, true);
     2227            pTimer->uHzHint = 0;
     2228        }
     2229        Log2(("tmR3TimerQueueRun: new state %s\n", tmTimerState(pTimer->enmState)));
     2230
     2231        /* Leave the associated lock. */
    22102232        if (pCritSect)
    22112233            PDMCritSectLeave(pCritSect);
    22122234    } /* run loop */
     2235
    22132236
    22142237    /*
     
    23872410                Log2(("TMR3VirtualSyncFF: running queue\n"));
    23882411
    2389                 if (pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC].offSchedule)
    2390                     tmTimerQueueSchedule(pVM, &pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC]);
     2412                Assert(!pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC].offSchedule);
    23912413                tmR3TimerQueueRunVirtualSync(pVM);
    23922414                if (pVM->tm.s.fVirtualSyncTicking) /** @todo move into tmR3TimerQueueRunVirtualSync - FIXME */
  • trunk/src/VBox/VMM/include/TMInternal.h

    r37358 r37517  
    400400    /** Alignment. */
    401401    RTRCPTR                     AlignmentRCPtr;
    402     /** The guest virtual timer synchronous time when fVirtualSyncTicking is cleared. */
     402    /** The guest virtual timer synchronous time when fVirtualSyncTicking is cleared.
     403     * When fVirtualSyncTicking is set it holds the last time returned to
     404     * the guest (while the lock was held). */
    403405    uint64_t volatile           u64VirtualSync;
    404406    /** The offset of the timer synchronous virtual clock (TMCLOCK_VIRTUAL_SYNC) relative
     
    505507    /** Lock serializing access to the timer lists. */
    506508    PDMCRITSECT                 TimerCritSect;
    507     /** Lock serializing access to the VirtualSync clock. */
     509    /** Lock serializing access to the VirtualSync clock and the associated
     510     * timer queue. */
    508511    PDMCRITSECT                 VirtualSyncLock;
    509512
     
    529532    STAMCOUNTER                 StatVirtualGetSetFF;
    530533    STAMCOUNTER                 StatVirtualSyncGet;
     534    STAMCOUNTER                 StatVirtualSyncGetAdjLast;
    531535    STAMCOUNTER                 StatVirtualSyncGetELoop;
    532536    STAMCOUNTER                 StatVirtualSyncGetExpired;
     
    536540    STAMCOUNTER                 StatVirtualPause;
    537541    STAMCOUNTER                 StatVirtualResume;
    538     /* @} */
     542    /** @} */
    539543    /** TMTimerPoll
    540544     * @{ */
     
    548552    STAMCOUNTER                 StatPollVirtualSync;
    549553    /** @} */
    550     /** TMTimerSet
     554    /** TMTimerSet sans virtual sync timers.
    551555     * @{ */
    552556    STAMCOUNTER                 StatTimerSet;
     
    562566    STAMCOUNTER                 StatTimerSetStPendResched;
    563567    STAMCOUNTER                 StatTimerSetStOther;
    564     /** @} */
    565     /** TMTimerSetRelative
     568    /** @}  */
     569    /** TMTimerSet on virtual sync timers.
     570     * @{ */
     571    STAMCOUNTER                 StatTimerSetVs;
     572    STAMPROFILE                 StatTimerSetVsRZ;
     573    STAMPROFILE                 StatTimerSetVsR3;
     574    STAMCOUNTER                 StatTimerSetVsStStopped;
     575    STAMCOUNTER                 StatTimerSetVsStExpDeliver;
     576    STAMCOUNTER                 StatTimerSetVsStActive;
     577    /** @} */
     578    /** TMTimerSetRelative sans virtual sync timers
    566579     * @{ */
    567580    STAMCOUNTER                 StatTimerSetRelative;
     
    569582    STAMPROFILE                 StatTimerSetRelativeR3;
    570583    STAMCOUNTER                 StatTimerSetRelativeOpt;
    571     STAMCOUNTER                 StatTimerSetRelativeRacyVirtSync;
    572584    STAMCOUNTER                 StatTimerSetRelativeStStopped;
    573585    STAMCOUNTER                 StatTimerSetRelativeStExpDeliver;
     
    579591    STAMCOUNTER                 StatTimerSetRelativeStOther;
    580592    /** @} */
    581     /** TMTimerStop
     593    /** TMTimerSetRelative on virtual sync timers.
     594     * @{ */
     595    STAMCOUNTER                 StatTimerSetRelativeVs;
     596    STAMPROFILE                 StatTimerSetRelativeVsRZ;
     597    STAMPROFILE                 StatTimerSetRelativeVsR3;
     598    STAMCOUNTER                 StatTimerSetRelativeVsStStopped;
     599    STAMCOUNTER                 StatTimerSetRelativeVsStExpDeliver;
     600    STAMCOUNTER                 StatTimerSetRelativeVsStActive;
     601    /** @} */
     602    /** TMTimerStop sans virtual sync.
    582603     * @{ */
    583604    STAMPROFILE                 StatTimerStopRZ;
    584605    STAMPROFILE                 StatTimerStopR3;
     606    /** @} */
     607    /** TMTimerStop on virtual sync timers.
     608     * @{ */
     609    STAMPROFILE                 StatTimerStopVsRZ;
     610    STAMPROFILE                 StatTimerStopVsR3;
    585611    /** @} */
    586612    /** VirtualSync - Running and Catching Up
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