VirtualBox

Changeset 19444 in vbox


Ignore:
Timestamp:
May 6, 2009 4:21:00 PM (16 years ago)
Author:
vboxsync
Message:

TM: Serialize EMT access using a critsect.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/TM.cpp

    r19400 r19444  
    264264    /* The rest is done in TMR3InitFinalize since it's too early to call PDM. */
    265265
     266    /*
     267     * Init the lock.
     268     */
     269    rc = PDMR3CritSectInit(pVM, &pVM->tm.s.EmtLock, "TM EMT Lock");
     270    if (RT_FAILURE(rc))
     271        return rc;
    266272
    267273    /*
     
    923929    LogFlow(("TMR3Reset:\n"));
    924930    VM_ASSERT_EMT(pVM);
     931    tmLock(pVM);
    925932
    926933    /*
     
    954961    tmTimerQueuesSanityChecks(pVM, "TMR3Reset");
    955962#endif
     963
    956964    VM_FF_CLEAR(pVM, VM_FF_TIMER);
     965    tmUnlock(pVM);
    957966}
    958967
     
    988997static DECLCALLBACK(int) tmR3Save(PVM pVM, PSSMHANDLE pSSM)
    989998{
    990     unsigned i;
    991 
    992999    LogFlow(("tmR3Save:\n"));
    9931000#ifdef VBOX_STRICT
    994     for (i=0;i<pVM->cCPUs;i++)
     1001    for (VMCPUID i = 0; i < pVM->cCPUs; i++)
    9951002    {
    9961003        PVMCPU pVCpu = &pVM->aCpus[i];
     
    10181025    SSMR3PutU64(pSSM, TMCLOCK_FREQ_REAL);
    10191026
    1020     for (i=0;i<pVM->cCPUs;i++)
     1027    for (VMCPUID i = 0; i < pVM->cCPUs; i++)
    10211028    {
    10221029        PVMCPU pVCpu = &pVM->aCpus[i];
     
    10391046static DECLCALLBACK(int) tmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
    10401047{
    1041     unsigned i;
    10421048    LogFlow(("tmR3Load:\n"));
    10431049
    10441050#ifdef VBOX_STRICT
    1045     for (i=0;i<pVM->cCPUs;i++)
     1051    for (VMCPUID i = 0; i < pVM->cCPUs; i++)
    10461052    {
    10471053        PVMCPU pVCpu = &pVM->aCpus[i];
     
    11061112
    11071113    /* the cpu tick clock. */
    1108     for (i=0;i<pVM->cCPUs;i++)
     1114    for (VMCPUID i = 0; i < pVM->cCPUs; i++)
    11091115    {
    11101116        PVMCPU pVCpu = &pVM->aCpus[i];
     
    11821188
    11831189    /* insert into the list of created timers. */
     1190    tmLock(pVM);
    11841191    pTimer->pBigPrev        = NULL;
    11851192    pTimer->pBigNext        = pVM->tm.s.pCreated;
     
    11901197    tmTimerQueuesSanityChecks(pVM, "tmR3TimerCreate");
    11911198#endif
     1199    tmUnlock(pVM);
    11921200
    11931201    *ppTimer = pTimer;
     
    13321340        return VERR_INVALID_PARAMETER;
    13331341
     1342    tmLock(pVM);
    13341343    PTMTIMER    pCur = pVM->tm.s.pCreated;
    13351344    while (pCur)
     
    13441353        }
    13451354    }
     1355    tmUnlock(pVM);
     1356
    13461357    LogFlow(("TMR3TimerDestroyDevice: returns VINF_SUCCESS\n"));
    13471358    return VINF_SUCCESS;
     
    13621373        return VERR_INVALID_PARAMETER;
    13631374
     1375    tmLock(pVM);
    13641376    PTMTIMER    pCur = pVM->tm.s.pCreated;
    13651377    while (pCur)
     
    13741386        }
    13751387    }
     1388    tmUnlock(pVM);
     1389
    13761390    LogFlow(("TMR3TimerDestroyDriver: returns VINF_SUCCESS\n"));
    13771391    return VINF_SUCCESS;
     
    14761490            )
    14771491        && !VM_FF_ISSET(pVM, VM_FF_TIMER)
     1492        && !pVM->tm.s.fRunningQueues
    14781493       )
    14791494    {
     
    14971512VMMR3DECL(void) TMR3TimerQueuesDo(PVM pVM)
    14981513{
     1514    /*
     1515     * Only one EMT should be doing this at a time.
     1516     */
     1517    VM_FF_CLEAR(pVM, VM_FF_TIMER);
     1518    if (!ASMBitTestAndSet(&pVM->tm.s.fRunningQueues, 0))
     1519        return;
     1520
    14991521    STAM_PROFILE_START(&pVM->tm.s.StatDoQueues, a);
    15001522    Log2(("TMR3TimerQueuesDo:\n"));
    1501 
    1502     /* SMP: quick hack to fend of the wildlife... */ /** @todo SMP */
    1503     if (    pVM->cCPUs > 1
    1504         &&  VMMGetCpuId(pVM) != 0)
    1505         return;
     1523    tmLock(pVM);
    15061524
    15071525    /*
     
    15441562    STAM_PROFILE_ADV_STOP(&pVM->tm.s.StatDoQueuesRun, r3);
    15451563
    1546     /* done. */
    1547     VM_FF_CLEAR(pVM, VM_FF_TIMER);
    1548 
    15491564#ifdef VBOX_STRICT
    15501565    /* check that we didn't screwup. */
     
    15541569    Log2(("TMR3TimerQueuesDo: returns void\n"));
    15551570    STAM_PROFILE_STOP(&pVM->tm.s.StatDoQueues, a);
     1571
     1572    /* done */
     1573    ASMAtomicBitClear(&pVM->tm.s.fRunningQueues, 0);
     1574    tmUnlock(pVM);
    15561575}
    15571576
     
    20432062                                                "Expire",
    20442063                                                "State");
     2064    tmLock(pVM);
    20452065    for (PTMTIMERR3 pTimer = pVM->tm.s.pCreated; pTimer; pTimer = pTimer->pBigNext)
    20462066    {
     
    20572077                        pTimer->pszDesc);
    20582078    }
     2079    tmUnlock(pVM);
    20592080}
    20602081
     
    20832104    for (unsigned iQueue = 0; iQueue < TMCLOCK_MAX; iQueue++)
    20842105    {
     2106        tmLock(pVM);
    20852107        for (PTMTIMERR3 pTimer = TMTIMER_GET_HEAD(&pVM->tm.s.paTimerQueuesR3[iQueue]);
    20862108             pTimer;
     
    21052127                            pTimer->pszDesc);
    21062128        }
     2129        tmUnlock(pVM);
    21072130    }
    21082131}
     
    21232146     * Read the times first to avoid more than necessary time variation.
    21242147     */
    2125     const uint64_t u64Virtual = TMVirtualGet(pVM);
     2148    const uint64_t u64Virtual     = TMVirtualGet(pVM);
    21262149    const uint64_t u64VirtualSync = TMVirtualSyncGet(pVM);
    2127     const uint64_t u64Real = TMRealGet(pVM);
     2150    const uint64_t u64Real        = TMRealGet(pVM);
    21282151
    21292152    for (unsigned i = 0; i < pVM->cCPUs; i++)
  • trunk/src/VBox/VMM/TMInternal.h

    r19325 r19444  
    2828#include <iprt/timer.h>
    2929#include <VBox/stam.h>
     30#include <VBox/pdmcritsect.h>
    3031
    3132__BEGIN_DECLS
     
    419420    uint32_t                    u32TimerMillies;
    420421
    421     /** Alignment padding to ensure that the statistics are 64-bit aligned when using GCC. */
    422     uint32_t                    u32Padding1;
     422    /** Makes sure only one EMT is running the queues. */
     423    bool volatile               fRunningQueues;
     424
     425    /** Lock serializing EMT access to TM. */
     426    PDMCRITSECT                 EmtLock;
    423427
    424428    /** TMR3TimerQueuesDo
     
    518522typedef TMCPU *PTMCPU;
    519523
     524int                     tmLock(PVM pVM);
     525int                     tmTryLock(PVM pVM);
     526void                    tmUnlock(PVM pVM);
     527/** Checks that the caller owns the EMT lock.  */
     528#define TM_ASSERT_EMT_LOCK(pVM) Assert(PDMCritSectIsOwner(&pVM->tm.s.EmtLock))
     529
    520530const char             *tmTimerState(TMTIMERSTATE enmState);
    521531void                    tmTimerQueueSchedule(PVM pVM, PTMTIMERQUEUE pQueue);
  • trunk/src/VBox/VMM/VMMAll/TMAll.cpp

    r19400 r19444  
    4646
    4747/**
     48 * Try take the EMT/TM lock, wait in ring-3 return VERR_SEM_BUSY in R0/RC.
     49 *
     50 * @retval  VINF_SUCCESS on success (always in ring-3).
     51 * @retval  VERR_SEM_BUSY in RC and R0 if the semaphore is busy.
     52 *
     53 * @param   pVM         The VM handle.
     54 */
     55int tmLock(PVM pVM)
     56{
     57    VM_ASSERT_EMT(pVM);
     58    int rc = PDMCritSectEnter(&pVM->tm.s.EmtLock, VERR_SEM_BUSY);
     59    return rc;
     60}
     61
     62
     63/**
     64 * Try take the EMT/TM lock, no waiting.
     65 *
     66 * @retval  VINF_SUCCESS on success.
     67 * @retval  VERR_SEM_BUSY if busy.
     68 *
     69 * @param   pVM         The VM handle.
     70 */
     71int tmTryLock(PVM pVM)
     72{
     73    VM_ASSERT_EMT(pVM);
     74    int rc = PDMCritSectTryEnter(&pVM->tm.s.EmtLock);
     75    return rc;
     76}
     77
     78
     79/**
     80 * Release EMT/TM lock.
     81 *
     82 * @param   pVM         The VM handle.
     83 */
     84void tmUnlock(PVM pVM)
     85{
     86    PDMCritSectLeave(&pVM->tm.s.EmtLock);
     87}
     88
     89
     90/**
    4891 * Notification that execution is about to start.
    4992 *
     
    129172{
    130173    PVM pVM = pTimer->CTX_SUFF(pVM);
    131     if (VM_IS_EMT(pVM))
     174    if (    VM_IS_EMT(pVM)
     175        &&  RT_SUCCESS(tmTryLock(pVM)))
    132176    {
    133177        STAM_PROFILE_START(&pVM->tm.s.CTXALLSUFF(StatScheduleOne), a);
     
    139183#endif
    140184        STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatScheduleOne), a);
     185        tmUnlock(pVM);
    141186    }
    142187    else if (!VM_FF_ISSET(pVM, VM_FF_TIMER))  /**@todo only do this when arming the timer. */
     
    226271VMMDECL(uint64_t) TMTimerPoll(PVM pVM)
    227272{
     273    int rc = tmLock(pVM); /* play safe for now */
     274
    228275    /*
    229276     * Return straight away if the timer FF is already set.
     
    232279    {
    233280        STAM_COUNTER_INC(&pVM->tm.s.StatPollAlreadySet);
     281#ifndef IN_RING3
     282        if (RT_SUCCESS(rc))
     283#endif
     284            tmUnlock(pVM);
    234285        return 0;
    235286    }
     
    247298    if (i64Delta1 <= 0)
    248299    {
     300        STAM_COUNTER_INC(&pVM->tm.s.StatPollVirtual);
    249301        LogFlow(("TMTimerPoll: expire1=%RU64 <= now=%RU64\n", u64Expire1, u64Now));
    250         STAM_COUNTER_INC(&pVM->tm.s.StatPollVirtual);
     302#ifndef IN_RING3
     303        if (RT_SUCCESS(rc))
     304#endif
     305            tmUnlock(pVM);
    251306        VM_FF_SET(pVM, VM_FF_TIMER);
    252307#ifdef IN_RING3
     
    287342    if (i64Delta2 <= 0)
    288343    {
     344        STAM_COUNTER_INC(&pVM->tm.s.StatPollVirtualSync);
     345#ifndef IN_RING3
     346        if (RT_SUCCESS(rc))
     347#endif
     348            tmUnlock(pVM);
    289349        LogFlow(("TMTimerPoll: expire2=%RU64 <= now=%RU64\n", u64Expire2, u64Now));
    290         STAM_COUNTER_INC(&pVM->tm.s.StatPollVirtualSync);
    291350        VM_FF_SET(pVM, VM_FF_TIMER);
    292351#ifdef IN_RING3
     
    302361     */
    303362    STAM_COUNTER_INC(&pVM->tm.s.StatPollMiss);
     363#ifndef IN_RING3
     364    if (RT_SUCCESS(rc))
     365#endif
     366        tmUnlock(pVM);
    304367    return RT_MIN(i64Delta1, i64Delta2);
    305368}
     
    320383VMMDECL(uint64_t) TMTimerPollGIP(PVM pVM, uint64_t *pu64Delta)
    321384{
     385    int rc = tmLock(pVM); /* play safe for now. */
     386
    322387    /*
    323388     * Return straight away if the timer FF is already set.
     
    326391    {
    327392        STAM_COUNTER_INC(&pVM->tm.s.StatPollAlreadySet);
     393#ifndef IN_RING3
     394        if (RT_SUCCESS(rc))
     395#endif
     396            tmUnlock(pVM);
    328397        *pu64Delta = 0;
    329398        return 0;
     
    333402     * Get current time and check the expire times of the two relevant queues.
    334403     */
    335     const uint64_t u64Now = TMVirtualGet(pVM);
     404    const uint64_t  u64Now = TMVirtualGet(pVM);
    336405
    337406    /*
    338407     * TMCLOCK_VIRTUAL
    339408     */
    340     const uint64_t u64Expire1 = pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL].u64Expire;
    341     const int64_t i64Delta1 = u64Expire1 - u64Now;
     409    const uint64_t  u64Expire1 = pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL].u64Expire;
     410    const int64_t   i64Delta1 = u64Expire1 - u64Now;
    342411    if (i64Delta1 <= 0)
    343412    {
     413        STAM_COUNTER_INC(&pVM->tm.s.StatPollVirtual);
     414#ifndef IN_RING3
     415        if (RT_SUCCESS(rc))
     416#endif
     417            tmUnlock(pVM);
    344418        LogFlow(("TMTimerPoll: expire1=%RU64 <= now=%RU64\n", u64Expire1, u64Now));
    345         STAM_COUNTER_INC(&pVM->tm.s.StatPollVirtual);
    346419        VM_FF_SET(pVM, VM_FF_TIMER);
    347420#ifdef IN_RING3
     
    357430     * we have to adjust the 'now' but when have to adjust the delta as well.
    358431     */
    359     const uint64_t u64Expire2 = pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire;
    360     uint64_t u64VirtualSyncNow;
     432    const uint64_t  u64Expire2 = pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire;
     433    uint64_t        u64VirtualSyncNow;
    361434    if (!pVM->tm.s.fVirtualSyncTicking)
    362435        u64VirtualSyncNow = pVM->tm.s.u64VirtualSync;
     
    380453        }
    381454    }
     455
    382456    int64_t i64Delta2 = u64Expire2 - u64VirtualSyncNow;
    383457    if (i64Delta2 <= 0)
    384458    {
     459        STAM_COUNTER_INC(&pVM->tm.s.StatPollVirtualSync);
     460#ifndef IN_RING3
     461        if (RT_SUCCESS(rc))
     462#endif
     463            tmUnlock(pVM);
    385464        LogFlow(("TMTimerPoll: expire2=%RU64 <= now=%RU64\n", u64Expire2, u64Now));
    386         STAM_COUNTER_INC(&pVM->tm.s.StatPollVirtualSync);
    387465        VM_FF_SET(pVM, VM_FF_TIMER);
    388466#ifdef IN_RING3
     
    410488        u64GipTime += pVM->tm.s.u64VirtualWarpDriveStart;
    411489    }
     490
     491#ifndef IN_RING3
     492    if (RT_SUCCESS(rc))
     493#endif
     494        tmUnlock(pVM);
    412495    return u64GipTime;
    413496}
     
    12911374 * @param   pQueue      The timer queue.
    12921375 * @param   pTimer      The timer that needs scheduling.
     1376 *
     1377 * @remarks Called while owning the lock.
    12931378 */
    12941379DECLINLINE(void) tmTimerQueueScheduleOne(PTMTIMERQUEUE pQueue, PTMTIMER pTimer)
     
    14851570 * @param   pVM             The VM to run the timers for.
    14861571 * @param   pQueue          The queue to schedule.
     1572 *
     1573 * @remarks Called while owning the lock.
    14871574 */
    14881575void tmTimerQueueSchedule(PVM pVM, PTMTIMERQUEUE pQueue)
    14891576{
    1490     VM_ASSERT_EMT(pVM);
     1577    TM_ASSERT_EMT_LOCK(pVM);
    14911578
    14921579    /*
     
    15231610 *
    15241611 * @param   pVM     VM handle.
     1612 *
     1613 * @remarks Called while owning the lock.
    15251614 */
    15261615void tmTimerQueuesSanityChecks(PVM pVM, const char *pszWhere)
    15271616{
     1617    TM_ASSERT_EMT_LOCK(pVM);
     1618
    15281619    /*
    15291620     * Check the linking of the active lists.
  • trunk/src/VBox/VMM/VMMAll/TMAllVirtual.cpp

    r19415 r19444  
    337337        if (    fCheckTimers
    338338            &&  !VM_FF_ISSET(pVM, VM_FF_TIMER)
     339            &&  !pVM->tm.s.fRunningQueues
    339340            &&  (   pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL].u64Expire <= u64
    340341                 || (   pVM->tm.s.fVirtualSyncTicking
     
    371372VMMDECL(uint64_t) TMVirtualGet(PVM pVM)
    372373{
    373     return TMVirtualGetEx(pVM, true /* check timers */);
     374    return tmVirtualGet(pVM, true /* check timers */);
    374375}
    375376
     
    403404VMMDECL(uint64_t) TMVirtualSyncGetEx(PVM pVM, bool fCheckTimers)
    404405{
    405     VM_ASSERT_EMT(pVM);
    406 
    407406    uint64_t u64;
    408407    if (pVM->tm.s.fVirtualSyncTicking)
     
    449448        if (pVM->tm.s.fVirtualSyncCatchUp)
    450449        {
     450            int rc = tmTryLock(pVM); /** @todo SMP: Here be dragons... Need to get back to this later. */
     451
    451452            const uint64_t u64Prev = pVM->tm.s.u64VirtualSyncCatchUpPrev;
    452453            uint64_t u64Delta = u64 - u64Prev;
     
    479480                Log(("TMVirtualGetSync: u64Delta=%RX64\n", u64Delta));
    480481            }
     482
     483            if (RT_SUCCESS(rc))
     484                tmUnlock(pVM);
    481485        }
    482486
     
    491495        {
    492496            u64 = u64Expire;
    493             ASMAtomicXchgU64(&pVM->tm.s.u64VirtualSync, u64);
    494             ASMAtomicXchgBool(&pVM->tm.s.fVirtualSyncTicking, false);
     497            int rc = tmTryLock(pVM); /** @todo SMP: Here be dragons... Need to get back to this later. */
     498            if (RT_SUCCESS(rc))
     499            {
     500                ASMAtomicXchgU64(&pVM->tm.s.u64VirtualSync, u64);
     501                ASMAtomicXchgBool(&pVM->tm.s.fVirtualSyncTicking, false);
     502                tmUnlock(pVM);
     503            }
    495504            if (    fCheckTimers
    496505                &&  !VM_FF_ISSET(pVM, VM_FF_TIMER))
     
    597606VMMDECL(int) TMVirtualResume(PVM pVM)
    598607{
    599     /** @note this is done only in specific cases (vcpu 0 init, termination, debug, out of memory conditions;
    600      *  there is at least a race for fVirtualSyncTicking.
     608    /*
     609     * Note! this is done only in specific cases (vcpu 0 init, termination, debug,
     610     * out of memory conditions; there is at least a race for fVirtualSyncTicking.
    601611     */
    602612    if (ASMAtomicIncU32(&pVM->tm.s.cVirtualTicking) == 1)
    603613    {
     614        int rc = tmLock(pVM); /* paranoia */
     615
    604616        STAM_COUNTER_INC(&pVM->tm.s.StatVirtualResume);
    605617        pVM->tm.s.u64VirtualRawPrev         = 0;
     
    607619        pVM->tm.s.u64VirtualOffset          = pVM->tm.s.u64VirtualWarpDriveStart - pVM->tm.s.u64Virtual;
    608620        pVM->tm.s.fVirtualSyncTicking       = true;
     621
     622        if (RT_SUCCESS(rc))
     623            tmUnlock(pVM);
    609624        return VINF_SUCCESS;
    610625    }
     
    623638VMMDECL(int) TMVirtualPause(PVM pVM)
    624639{
    625     /** @note this is done only in specific cases (vcpu 0 init, termination, debug, out of memory conditions;
    626      *  there is at least a race for fVirtualSyncTicking.
     640    /*
     641     * Note! this is done only in specific cases (vcpu 0 init, termination, debug,
     642     * out of memory conditions; there is at least a race for fVirtualSyncTicking.
    627643     */
    628644    if (ASMAtomicDecU32(&pVM->tm.s.cVirtualTicking) == 0)
    629645    {
     646        int rc = tmLock(pVM); /* paranoia */
     647
    630648        STAM_COUNTER_INC(&pVM->tm.s.StatVirtualPause);
    631649        pVM->tm.s.u64Virtual            = tmVirtualGetRaw(pVM);
    632650        pVM->tm.s.fVirtualSyncTicking   = false;
     651
     652        if (RT_SUCCESS(rc))
     653            tmUnlock(pVM);
    633654        return VINF_SUCCESS;
    634655    }
     
    693714                    ("%RX32 is not between 2 and 20000 (inclusive).\n", u32Percent),
    694715                    VERR_INVALID_PARAMETER);
     716    tmLock(pVM);
    695717
    696718    /*
     
    702724    {
    703725        int rc = TMVirtualPause(pVM);
    704         AssertRCReturn(rc, rc);
     726        AssertRC(rc);
    705727        rc = TMCpuTickPause(pVCpu);
    706         AssertRCReturn(rc, rc);
     728        AssertRC(rc);
    707729    }
    708730
     
    715737    {
    716738        int rc = TMVirtualResume(pVM);
    717         AssertRCReturn(rc, rc);
     739        AssertRC(rc);
    718740        rc = TMCpuTickResume(pVCpu);
    719         AssertRCReturn(rc, rc);
    720     }
    721 
     741        AssertRC(rc);
     742    }
     743
     744    tmUnlock(pVM);
    722745    return VINF_SUCCESS;
    723746}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette