VirtualBox

Changeset 87812 in vbox


Ignore:
Timestamp:
Feb 19, 2021 8:54:49 PM (4 years ago)
Author:
vboxsync
Message:

VMM/TM: Replaced the global timer active list lock with per queue locks. bugref:9943

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/vm.h

    r87792 r87812  
    13641364        struct TM   s;
    13651365#endif
    1366         uint8_t     padding[9152];      /* multiple of 64 */
     1366        uint8_t     padding[9920];      /* multiple of 64 */
    13671367    } tm;
    13681368
     
    14631463
    14641464    /** Padding for aligning the structure size on a page boundrary. */
    1465     uint8_t         abAlignment2[2392 - sizeof(PVMCPUR3) * VMM_MAX_CPU_COUNT];
     1465    uint8_t         abAlignment2[1624 - sizeof(PVMCPUR3) * VMM_MAX_CPU_COUNT];
    14661466
    14671467    /* ---- end small stuff ---- */
  • trunk/include/VBox/vmm/vm.mac

    r87792 r87812  
    6363    alignb 64
    6464    .hm                     resb 5888
     65    alignb 64
    6566    .nem                    resb 512
     67    alignb 64
    6668    .trpm                   resb 128
     69    alignb 64
    6770    .tm                     resb 5760
     71    alignb 64
    6872    .vmm                    resb 896
     73    alignb 64
    6974    .pdm                    resb 256
     75    alignb 64
    7076    .iom                    resb 512
     77    alignb 64
    7178    .dbgf                   resb 512
     79    alignb 64
    7280    .gim                    resb 512
     81    alignb 64
    7382    .apic                   resb 3840
    7483
     84    alignb 64
    7585    .fTraceGroups           resd 1
    7686    .uAdHoc                 resd 1
     
    121131    alignb 64
    122132    .cpum                   resb 1536
     133    alignb 64
    123134    .vmm                    resb 1600
     135    alignb 64
    124136    .pgm                    resb 21120
     137    alignb 64
    125138    .hm                     resb 5504
     139    alignb 64
    126140    .trpm                   resb 2048
     141    alignb 64
    127142    .selm                   resb 768
     143    alignb 64
    128144    .mm                     resb 192
     145    alignb 64
    129146    .pdm                    resb 8128
     147    alignb 64
    130148    .iom                    resb 1152
     149    alignb 64
    131150    .em                     resb 256
     151    alignb 64
    132152    .nem                    resb 128
    133     .tm                     resb 9152
     153    alignb 64
     154    .tm                     resb 9920
     155    alignb 64
    134156    .dbgf                   resb 2432
     157    alignb 64
    135158    .ssm                    resb 128
     159    alignb 64
    136160    .gim                    resb 448
     161    alignb 64
    137162    .apic                   resb 128
     163    alignb 64
    138164    .vm                     resb 32
    139165    .cfgm                   resb 8
  • trunk/src/VBox/VMM/VMMAll/TMAll.cpp

    r87792 r87812  
    365365    PTMTIMERQUEUECC const   pQueueCC = TM_GET_TIMER_QUEUE_CC(pVM, enmClock, pQueue);
    366366
    367     if (    VM_IS_EMT(pVM)
    368         &&  RT_SUCCESS(TM_TRY_LOCK_TIMERS(pVM)))
    369     {
    370         STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatScheduleOne), a);
    371         Log3(("tmSchedule: tmTimerQueueSchedule\n"));
    372         tmTimerQueueSchedule(pVM, pQueueCC, pQueue);
     367    if (VM_IS_EMT(pVM)) /** @todo drop EMT requirement here. */
     368    {
     369        int rc = PDMCritSectTryEnter(&pQueue->TimerLock);
     370        if (RT_SUCCESS_NP(rc))
     371        {
     372            STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatScheduleOne), a);
     373            Log3(("tmSchedule: tmTimerQueueSchedule\n"));
     374            tmTimerQueueSchedule(pVM, pQueueCC, pQueue);
    373375#ifdef VBOX_STRICT
    374         tmTimerQueuesSanityChecks(pVM, "tmSchedule");
     376            tmTimerQueuesSanityChecks(pVM, "tmSchedule");
    375377#endif
    376         STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatScheduleOne), a);
    377         TM_UNLOCK_TIMERS(pVM);
    378     }
    379     else
    380     {
    381         TMTIMERSTATE enmState = pTimer->enmState;
    382         if (TMTIMERSTATE_IS_PENDING_SCHEDULING(enmState))
    383             tmScheduleNotify(pVM);
    384     }
     378            STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatScheduleOne), a);
     379            PDMCritSectLeave(&pQueue->TimerLock);
     380            return;
     381        }
     382    }
     383
     384    TMTIMERSTATE enmState = pTimer->enmState;
     385    if (TMTIMERSTATE_IS_PENDING_SCHEDULING(enmState))
     386        tmScheduleNotify(pVM);
    385387}
    386388
     
    624626void tmTimerQueueSchedule(PVMCC pVM, PTMTIMERQUEUECC pQueueCC, PTMTIMERQUEUE pQueue)
    625627{
    626     TM_ASSERT_TIMER_LOCK_OWNERSHIP(pVM);
    627     NOREF(pVM);
     628    Assert(PDMCritSectIsOwner(&pQueue->TimerLock));
    628629
    629630    /*
     
    661662 * @param   pVM         The cross context VM structure.
    662663 * @param   pszWhere    Caller location clue.
    663  *
    664  * @remarks Called while owning the lock.
    665664 */
    666665void tmTimerQueuesSanityChecks(PVMCC pVM, const char *pszWhere)
    667666{
    668     TM_ASSERT_TIMER_LOCK_OWNERSHIP(pVM);
    669 
    670667    for (uint32_t idxQueue = 0; idxQueue < RT_ELEMENTS(pVM->tm.s.aTimerQueues); idxQueue++)
    671668    {
     
    674671        Assert(pQueue->enmClock == (TMCLOCK)idxQueue);
    675672
    676         int rc = PDMCritSectRwTryEnterShared(&pQueue->AllocLock);
     673        int rc = PDMCritSectTryEnter(&pQueue->TimerLock);
    677674        if (RT_SUCCESS(rc))
    678675        {
     
    780777                    PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock);
    781778            }
    782             PDMCritSectRwLeaveShared(&pQueue->AllocLock);
     779            PDMCritSectLeave(&pQueue->TimerLock);
    783780        }
    784781    }
     
    11981195 * @param   pTimer          The timer handle.
    11991196 * @param   u64Expire       The new expire time.
    1200  */
    1201 static int tmTimerSetOptimizedStart(PVMCC pVM, PTMTIMER pTimer, uint64_t u64Expire)
     1197 * @param   pQueue          Pointer to the shared timer queue data.
     1198 * @param   enmClock        The sanitized clock.
     1199 */
     1200static int tmTimerSetOptimizedStart(PVMCC pVM, PTMTIMER pTimer, uint64_t u64Expire, PTMTIMERQUEUE pQueue, TMCLOCK enmClock)
    12021201{
    12031202    Assert(pTimer->idxPrev == UINT32_MAX);
    12041203    Assert(pTimer->idxNext == UINT32_MAX);
    12051204    Assert(pTimer->enmState == TMTIMERSTATE_ACTIVE);
    1206 
    1207     TMCLOCK const enmClock = pTimer->enmClock;
    1208     AssertReturn((unsigned)enmClock < TMCLOCK_MAX, VERR_TM_IPE_2);
    12091205
    12101206    /*
     
    12241220     * Link the timer into the active list.
    12251221     */
    1226     PTMTIMERQUEUE const pQueue = &pVM->tm.s.aTimerQueues[enmClock];
    12271222    tmTimerQueueLinkActive(pVM, TM_GET_TIMER_QUEUE_CC(pVM, enmClock, pQueue), pQueue, pTimer, u64Expire);
    12281223
    12291224    STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetOpt);
    1230     TM_UNLOCK_TIMERS(pVM);
    12311225    return VINF_SUCCESS;
    12321226}
     
    13581352    {
    13591353        /* Try take the TM lock and check the state again. */
    1360         if (RT_SUCCESS_NP(TM_TRY_LOCK_TIMERS(pVM)))
     1354        TMCLOCK const       enmClock = pTimer->enmClock;
     1355        AssertReturn((unsigned)enmClock < TMCLOCK_MAX, VERR_TM_IPE_2);
     1356        PTMTIMERQUEUE const pQueue   = &pVM->tm.s.aTimerQueues[enmClock];
     1357
     1358        int rc = PDMCritSectTryEnter(&pQueue->TimerLock);
     1359        if (RT_SUCCESS_NP(rc))
    13611360        {
    13621361            if (RT_LIKELY(tmTimerTry(pTimer, TMTIMERSTATE_ACTIVE, enmState1)))
    13631362            {
    1364                 tmTimerSetOptimizedStart(pVM, pTimer, u64Expire);
     1363                tmTimerSetOptimizedStart(pVM, pTimer, u64Expire, pQueue, enmClock);
    13651364                STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerSet), a);
     1365                PDMCritSectLeave(&pQueue->TimerLock);
    13661366                return VINF_SUCCESS;
    13671367            }
    1368             TM_UNLOCK_TIMERS(pVM);
     1368            PDMCritSectLeave(&pQueue->TimerLock);
    13691369        }
    13701370    }
     
    15081508 * @param   pu64Now         Where to return the current time stamp used.
    15091509 *                          Optional.
    1510  */
    1511 static int tmTimerSetRelativeOptimizedStart(PVMCC pVM, PTMTIMER pTimer, uint64_t cTicksToNext, uint64_t *pu64Now)
     1510 * @param   pQueue          Pointer to the shared timer queue data.
     1511 * @param   enmClock        The sanitized clock.
     1512 */
     1513static int tmTimerSetRelativeOptimizedStart(PVMCC pVM, PTMTIMER pTimer, uint64_t cTicksToNext, uint64_t *pu64Now,
     1514                                            PTMTIMERQUEUE pQueue, TMCLOCK enmClock)
    15121515{
    15131516    Assert(pTimer->idxPrev == UINT32_MAX);
     
    15181521     * Calculate and set the expiration time.
    15191522     */
    1520     TMCLOCK const   enmClock  = pTimer->enmClock;
    1521     AssertReturn((unsigned)enmClock < (unsigned)TMCLOCK_MAX, VERR_TM_IPE_2);
    15221523    uint64_t const  u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
    15231524    pTimer->u64Expire         = u64Expire;
     
    15281529     */
    15291530    DBGFTRACE_U64_TAG2(pVM, u64Expire, "tmTimerSetRelativeOptimizedStart", pTimer->szName);
    1530     PTMTIMERQUEUE const pQueue = &pVM->tm.s.aTimerQueues[enmClock];
    15311531    tmTimerQueueLinkActive(pVM, TM_GET_TIMER_QUEUE_CC(pVM, enmClock, pQueue), pQueue, pTimer, u64Expire);
    15321532
    15331533    STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeOpt);
    1534     TM_UNLOCK_TIMERS(pVM);
    15351534    return VINF_SUCCESS;
    15361535}
     
    16301629
    16311630    /* Treat virtual sync timers specially. */
    1632     if (pTimer->enmClock == TMCLOCK_VIRTUAL_SYNC)
     1631    TMCLOCK enmClock = pTimer->enmClock;
     1632    if (enmClock == TMCLOCK_VIRTUAL_SYNC)
    16331633        return tmTimerVirtualSyncSetRelative(pVM, pTimer, cTicksToNext, pu64Now);
     1634    AssertReturn((unsigned)enmClock < (unsigned)TMCLOCK_MAX, VERR_TM_IPE_2);
    16341635
    16351636    STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
     
    16701671     *       get the innermost locks.
    16711672     */
    1672     bool fOwnTMLock = RT_SUCCESS_NP(TM_TRY_LOCK_TIMERS(pVM));
     1673    PTMTIMERQUEUE pQueue = &pVM->tm.s.aTimerQueues[enmClock];
     1674    bool fOwnTMLock = RT_SUCCESS_NP(PDMCritSectTryEnter(&pQueue->TimerLock));
    16731675#if 1
    16741676    if (    fOwnTMLock
     
    16801682                      && tmTimerTry(pTimer, TMTIMERSTATE_ACTIVE, enmState)))
    16811683        {
    1682             tmTimerSetRelativeOptimizedStart(pVM, pTimer, cTicksToNext, pu64Now);
     1684            tmTimerSetRelativeOptimizedStart(pVM, pTimer, cTicksToNext, pu64Now, pQueue, enmClock);
    16831685            STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
     1686            PDMCritSectLeave(&pQueue->TimerLock);
    16841687            return VINF_SUCCESS;
    16851688        }
     
    16921695     * Unoptimized path.
    16931696     */
    1694     int             rc;
    1695     TMCLOCK const   enmClock = pTimer->enmClock;
     1697    int rc;
    16961698    for (int cRetries = 1000; ; cRetries--)
    16971699    {
     
    18221824         */
    18231825        if (!fOwnTMLock)
    1824             fOwnTMLock = RT_SUCCESS_NP(TM_TRY_LOCK_TIMERS(pVM));
     1826            fOwnTMLock = RT_SUCCESS_NP(PDMCritSectTryEnter(&pQueue->TimerLock));
    18251827
    18261828    } /* for (;;) */
     
    18301832     */
    18311833    if (fOwnTMLock)
    1832         TM_UNLOCK_TIMERS(pVM);
     1834        PDMCritSectLeave(&pQueue->TimerLock);
    18331835
    18341836    STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
     
    18721874VMMDECL(int) TMTimerSetFrequencyHint(PVMCC pVM, TMTIMERHANDLE hTimer, uint32_t uHzHint)
    18731875{
    1874     PTMTIMER pTimer;
    1875     TMTIMER_HANDLE_TO_PTR_RETURN(pVM, hTimer, pTimer);
     1876    TMTIMER_HANDLE_TO_VARS_RETURN(pVM, hTimer); /* => pTimer, pQueueCC, pQueue, idxTimer, idxQueue */
    18761877    TMTIMER_ASSERT_CRITSECT(pVM, pTimer);
    18771878
     
    18791880    pTimer->uHzHint = uHzHint;
    18801881
    1881     uint32_t const uMaxHzHint = pVM->tm.s.uMaxHzHint;
     1882    uint32_t const uMaxHzHint = pQueue->uMaxHzHint;
    18821883    if (   uHzHint    >  uMaxHzHint
    18831884        || uHzOldHint >= uMaxHzHint)
    1884         ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, true);
     1885        ASMAtomicOrU64(&pVM->tm.s.HzHint.u64Combined, RT_BIT_32(idxQueue) | RT_BIT_32(idxQueue + 16));
    18851886
    18861887    return VINF_SUCCESS;
     
    19071908
    19081909    /* Reset the HZ hint. */
    1909     if (pTimer->uHzHint)
    1910     {
    1911         if (pTimer->uHzHint >= pVM->tm.s.uMaxHzHint)
    1912             ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, true);
     1910    uint32_t uOldHzHint = pTimer->uHzHint;
     1911    if (uOldHzHint)
     1912    {
     1913        if (uOldHzHint >= pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL_SYNC].uMaxHzHint)
     1914            ASMAtomicOrU64(&pVM->tm.s.HzHint.u64Combined, RT_BIT_32(TMCLOCK_VIRTUAL_SYNC) | RT_BIT_32(TMCLOCK_VIRTUAL_SYNC + 16));
    19131915        pTimer->uHzHint = 0;
    19141916    }
    19151917
    19161918    /* Update the timer state. */
    1917     TMTIMERSTATE const      enmState = pTimer->enmState;
     1919    TMTIMERSTATE const enmState = pTimer->enmState;
    19181920    switch (enmState)
    19191921    {
     
    19711973VMMDECL(int) TMTimerStop(PVMCC pVM, TMTIMERHANDLE hTimer)
    19721974{
    1973     PTMTIMER pTimer;
    1974     TMTIMER_HANDLE_TO_PTR_RETURN(pVM, hTimer, pTimer);
     1975    TMTIMER_HANDLE_TO_VARS_RETURN(pVM, hTimer); /* => pTimer, pQueueCC, pQueue, idxTimer, idxQueue */
    19751976    STAM_COUNTER_INC(&pTimer->StatStop);
    19761977
    19771978    /* Treat virtual sync timers specially. */
    1978     if (pTimer->enmClock == TMCLOCK_VIRTUAL_SYNC)
     1979    if (idxQueue == TMCLOCK_VIRTUAL_SYNC)
    19791980        return tmTimerVirtualSyncStop(pVM, pTimer);
    19801981
     
    19851986     * Reset the HZ hint.
    19861987     */
    1987     if (pTimer->uHzHint)
    1988     {
    1989         if (pTimer->uHzHint >= pVM->tm.s.uMaxHzHint)
    1990             ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, true);
     1988    uint32_t const uOldHzHint = pTimer->uHzHint;
     1989    if (uOldHzHint)
     1990    {
     1991        if (uOldHzHint >= pQueue->uMaxHzHint)
     1992            ASMAtomicOrU64(&pVM->tm.s.HzHint.u64Combined, RT_BIT_32(idxQueue) | RT_BIT_32(idxQueue + 16));
    19911993        pTimer->uHzHint = 0;
    19921994    }
     
    26142616
    26152617/**
    2616  * Gets the highest frequency hint for all the important timers.
     2618 * The slow path of tmGetFrequencyHint() where we try to recalculate the value.
    26172619 *
    26182620 * @returns The highest frequency.  0 if no timers care.
    2619  * @param   pVM         The cross context VM structure.
    2620  */
    2621 static uint32_t tmGetFrequencyHint(PVMCC pVM)
    2622 {
     2621 * @param   pVM             The cross context VM structure.
     2622 * @param   uOldMaxHzHint   The old global hint.
     2623 */
     2624DECL_NO_INLINE(static, uint32_t) tmGetFrequencyHintSlow(PVMCC pVM, uint32_t uOldMaxHzHint)
     2625{
     2626    /* Set two bits, though not entirely sure it's needed (too exhaused to think clearly)
     2627       but it should force other callers thru the slow path while we're recalculating and
     2628       help us detect changes while we're recalculating. */
     2629    AssertCompile(RT_ELEMENTS(pVM->tm.s.aTimerQueues) <= 16);
     2630
    26232631    /*
    2624      * Query the value, recalculate it if necessary.
    2625      *
    26262632     * The "right" highest frequency value isn't so important that we'll block
    2627      * waiting on the timer semaphore.
     2633     * waiting on the timer semaphores.
    26282634     */
    2629     uint32_t uMaxHzHint = ASMAtomicUoReadU32(&pVM->tm.s.uMaxHzHint);
    2630     if (RT_UNLIKELY(ASMAtomicReadBool(&pVM->tm.s.fHzHintNeedsUpdating)))
    2631     {
    2632         if (RT_SUCCESS(TM_TRY_LOCK_TIMERS(pVM)))
     2635    uint32_t uMaxHzHint = 0;
     2636    for (uint32_t idxQueue = 0; idxQueue < RT_ELEMENTS(pVM->tm.s.aTimerQueues); idxQueue++)
     2637    {
     2638        PTMTIMERQUEUE pQueue = &pVM->tm.s.aTimerQueues[idxQueue];
     2639
     2640        /* Get the max Hz hint for the queue. */
     2641        uint32_t uMaxHzHintQueue;
     2642        if (  !(ASMAtomicUoReadU64(&pVM->tm.s.HzHint.u64Combined) & (RT_BIT_32(idxQueue) | RT_BIT_32(idxQueue + 16)))
     2643            || RT_FAILURE_NP(PDMCritSectTryEnter(&pQueue->TimerLock)))
     2644            uMaxHzHintQueue = ASMAtomicReadU32(&pQueue->uMaxHzHint);
     2645        else
    26332646        {
    2634             ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, false);
    2635 
    2636             /*
    2637              * Loop over the timers associated with each clock.
    2638              */
    2639             uMaxHzHint = 0;
    2640             for (uint32_t idxQueue = 0; idxQueue < RT_ELEMENTS(pVM->tm.s.aTimerQueues); idxQueue++)
     2647            /* Is it still necessary to do updating? */
     2648            if (ASMAtomicUoReadU64(&pVM->tm.s.HzHint.u64Combined) & (RT_BIT_32(idxQueue) | RT_BIT_32(idxQueue + 16)))
    26412649            {
    2642                 PTMTIMERQUEUE   pQueue   = &pVM->tm.s.aTimerQueues[idxQueue];
     2650                ASMAtomicAndU64(&pVM->tm.s.HzHint.u64Combined, ~RT_BIT_64(idxQueue + 16)); /* clear one flag up front */
     2651
    26432652                PTMTIMERQUEUECC pQueueCC = TM_GET_TIMER_QUEUE_CC(pVM, idxQueue, pQueue);
    2644                 for (PTMTIMER pCur = tmTimerQueueGetHead(pQueueCC, pQueue); pCur; pCur = tmTimerGetNext(pQueueCC, pCur))
     2653                uMaxHzHintQueue = 0;
     2654                for (PTMTIMER pCur = tmTimerQueueGetHead(pQueueCC, pQueue);
     2655                     pCur;
     2656                     pCur = tmTimerGetNext(pQueueCC, pCur))
    26452657                {
    26462658                    uint32_t uHzHint = ASMAtomicUoReadU32(&pCur->uHzHint);
    2647                     if (uHzHint > uMaxHzHint)
     2659                    if (uHzHint > uMaxHzHintQueue)
    26482660                    {
    2649                         switch (pCur->enmState)
     2661                        TMTIMERSTATE enmState = pCur->enmState;
     2662                        switch (enmState)
    26502663                        {
    26512664                            case TMTIMERSTATE_ACTIVE:
     
    26562669                            case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
    26572670                            case TMTIMERSTATE_PENDING_RESCHEDULE:
    2658                                 uMaxHzHint = uHzHint;
     2671                                uMaxHzHintQueue = uHzHint;
    26592672                                break;
    26602673
     
    26702683                    }
    26712684                }
     2685
     2686                /* Write the new Hz hint for the quest and clear the other update flag. */
     2687                ASMAtomicUoWriteU32(&pQueue->uMaxHzHint, uMaxHzHintQueue);
     2688                ASMAtomicAndU64(&pVM->tm.s.HzHint.u64Combined, ~RT_BIT_64(idxQueue));
    26722689            }
    2673             ASMAtomicWriteU32(&pVM->tm.s.uMaxHzHint, uMaxHzHint);
    2674             Log(("tmGetFrequencyHint: New value %u Hz\n", uMaxHzHint));
    2675             TM_UNLOCK_TIMERS(pVM);
     2690            else
     2691                uMaxHzHintQueue = ASMAtomicUoReadU32(&pQueue->uMaxHzHint);
     2692
     2693            PDMCritSectLeave(&pQueue->TimerLock);
    26762694        }
    2677     }
     2695
     2696        /* Update the global max Hz hint. */
     2697        if (uMaxHzHint < uMaxHzHintQueue)
     2698            uMaxHzHint = uMaxHzHintQueue;
     2699    }
     2700
     2701    /*
     2702     * Update the frequency hint if no pending frequency changes and we didn't race anyone thru here.
     2703     */
     2704    uint64_t u64Actual = RT_MAKE_U64(0 /*no pending updates*/, uOldMaxHzHint);
     2705    if (ASMAtomicCmpXchgExU64(&pVM->tm.s.HzHint.u64Combined, RT_MAKE_U64(0, uMaxHzHint), u64Actual, &u64Actual))
     2706        Log(("tmGetFrequencyHintSlow: New value %u Hz\n", uMaxHzHint));
     2707    else
     2708        for (uint32_t iTry = 1;; iTry++)
     2709        {
     2710            if (RT_LO_U32(u64Actual) != 0)
     2711                Log(("tmGetFrequencyHintSlow: Outdated value %u Hz (%#x, try %u)\n", uMaxHzHint, RT_LO_U32(u64Actual), iTry));
     2712            else if (iTry >= 4)
     2713                Log(("tmGetFrequencyHintSlow: Unable to set %u Hz (try %u)\n", uMaxHzHint, iTry));
     2714            else if (ASMAtomicCmpXchgExU64(&pVM->tm.s.HzHint.u64Combined, RT_MAKE_U64(0, uMaxHzHint), u64Actual, &u64Actual))
     2715                Log(("tmGetFrequencyHintSlow: New value %u Hz (try %u)\n", uMaxHzHint, iTry));
     2716            else
     2717                continue;
     2718            break;
     2719        }
    26782720    return uMaxHzHint;
     2721}
     2722
     2723
     2724/**
     2725 * Gets the highest frequency hint for all the important timers.
     2726 *
     2727 * @returns The highest frequency.  0 if no timers care.
     2728 * @param   pVM         The cross context VM structure.
     2729 */
     2730DECLINLINE(uint32_t) tmGetFrequencyHint(PVMCC pVM)
     2731{
     2732    /*
     2733     * Query the value, recalculate it if necessary.
     2734     */
     2735    uint64_t u64Combined = ASMAtomicReadU64(&pVM->tm.s.HzHint.u64Combined);
     2736    if (RT_HI_U32(u64Combined) == 0)
     2737        return RT_LO_U32(u64Combined); /* hopefully somewhat likely */
     2738    return tmGetFrequencyHintSlow(pVM, RT_LO_U32(u64Combined));
    26792739}
    26802740
  • trunk/src/VBox/VMM/VMMR3/TM.cpp

    r87796 r87812  
    210210    AssertCompileMemberAlignment(VM, tm.s, 32);
    211211    AssertCompile(sizeof(pVM->tm.s) <= sizeof(pVM->tm.padding));
    212     AssertCompileMemberAlignment(TM, TimerCritSect, 8);
    213212    AssertCompileMemberAlignment(TM, VirtualSyncLock, 8);
    214213
     
    217216     */
    218217    pVM->tm.s.idTimerCpu = pVM->cCpus - 1; /* The last CPU. */
     218
     219    int rc = PDMR3CritSectInit(pVM, &pVM->tm.s.VirtualSyncLock, RT_SRC_POS, "TM VirtualSync Lock");
     220    AssertLogRelRCReturn(rc, rc);
    219221
    220222    strcpy(pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL].szName,      "virtual");
     
    231233        pVM->tm.s.aTimerQueues[i].idxSchedule = UINT32_MAX;
    232234        pVM->tm.s.aTimerQueues[i].idxFreeHint = 1;
    233         int rc = PDMR3CritSectRwInit(pVM, &pVM->tm.s.aTimerQueues[i].AllocLock, RT_SRC_POS,
    234                                      "TM queue %s", pVM->tm.s.aTimerQueues[i].szName);
     235        rc = PDMR3CritSectInit(pVM, &pVM->tm.s.aTimerQueues[i].TimerLock, RT_SRC_POS,
     236                               "TM %s queue timer lock", pVM->tm.s.aTimerQueues[i].szName);
     237        AssertLogRelRCReturn(rc, rc);
     238
     239        rc = PDMR3CritSectRwInit(pVM, &pVM->tm.s.aTimerQueues[i].AllocLock, RT_SRC_POS,
     240                                 "TM %s queue alloc lock", pVM->tm.s.aTimerQueues[i].szName);
    235241        AssertLogRelRCReturn(rc, rc);
    236242    }
     
    249255
    250256    RTHCPHYS HCPhysGIP;
    251     int rc = SUPR3GipGetPhys(&HCPhysGIP);
     257    rc = SUPR3GipGetPhys(&HCPhysGIP);
    252258    AssertMsgRCReturn(rc, ("Failed to get GIP physical address!\n"), rc);
    253259
     
    305311    AssertRelease(pVM->tm.s.VirtualGetRawDataR0.pu64Prev);
    306312    /* The rest is done in TMR3InitFinalize() since it's too early to call PDM. */
    307 
    308     /*
    309      * Init the locks.
    310      */
    311     rc = PDMR3CritSectInit(pVM, &pVM->tm.s.TimerCritSect, RT_SRC_POS, "TM Timer Lock");
    312     if (RT_FAILURE(rc))
    313         return rc;
    314     rc = PDMR3CritSectInit(pVM, &pVM->tm.s.VirtualSyncLock, RT_SRC_POS, "TM VirtualSync Lock");
    315     if (RT_FAILURE(rc))
    316         return rc;
    317313
    318314    /*
     
    699695    STAM_REL_REG(     pVM,(void*)&pVM->tm.s.offVirtualSync,               STAMTYPE_U64, "/TM/VirtualSync/CurrentOffset",               STAMUNIT_NS, "The current offset. (subtract GivenUp to get the lag)");
    700696    STAM_REL_REG_USED(pVM,(void*)&pVM->tm.s.offVirtualSyncGivenUp,        STAMTYPE_U64, "/TM/VirtualSync/GivenUp",                     STAMUNIT_NS, "Nanoseconds of the 'CurrentOffset' that's been given up and won't ever be attempted caught up with.");
    701     STAM_REL_REG(     pVM,(void*)&pVM->tm.s.uMaxHzHint,                   STAMTYPE_U32, "/TM/MaxHzHint",                               STAMUNIT_HZ, "Max guest timer frequency hint.");
     697    STAM_REL_REG(     pVM,(void*)&pVM->tm.s.HzHint.s.uMax,                STAMTYPE_U32, "/TM/MaxHzHint",                               STAMUNIT_HZ, "Max guest timer frequency hint.");
     698    for (uint32_t i = 0; i < RT_ELEMENTS(pVM->tm.s.aTimerQueues); i++)
     699    {
     700        rc = STAMR3RegisterF(pVM, (void *)&pVM->tm.s.aTimerQueues[i].uMaxHzHint, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_HZ,
     701                             "", "/TM/MaxHzHint/%s", pVM->tm.s.aTimerQueues[i].szName);
     702        AssertRC(rc);
     703    }
    702704
    703705#ifdef VBOX_WITH_STATISTICS
     
    709711    STAM_REG_USED(pVM,(void *)&pVM->tm.s.VirtualGetRawDataRC.cUpdateRaces,STAMTYPE_U32, "/TM/RC/cUpdateRaces",                 STAMUNIT_OCCURENCES, "Thread races when updating the previous timestamp.");
    710712    STAM_REG(pVM, &pVM->tm.s.StatDoQueues,                            STAMTYPE_PROFILE, "/TM/DoQueues",                    STAMUNIT_TICKS_PER_CALL, "Profiling timer TMR3TimerQueuesDo.");
    711     STAM_REG(pVM, &pVM->tm.s.aStatDoQueues[TMCLOCK_VIRTUAL],      STAMTYPE_PROFILE_ADV, "/TM/DoQueues/Virtual",            STAMUNIT_TICKS_PER_CALL, "Time spent on the virtual clock queue.");
    712     STAM_REG(pVM, &pVM->tm.s.aStatDoQueues[TMCLOCK_VIRTUAL_SYNC], STAMTYPE_PROFILE_ADV, "/TM/DoQueues/VirtualSync",        STAMUNIT_TICKS_PER_CALL, "Time spent on the virtual sync clock queue.");
    713     STAM_REG(pVM, &pVM->tm.s.aStatDoQueues[TMCLOCK_REAL],         STAMTYPE_PROFILE_ADV, "/TM/DoQueues/Real",               STAMUNIT_TICKS_PER_CALL, "Time spent on the real clock queue.");
     713    STAM_REG(pVM, &pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL].StatDo,    STAMTYPE_PROFILE, "/TM/DoQueues/Virtual",            STAMUNIT_TICKS_PER_CALL, "Time spent on the virtual clock queue.");
     714    STAM_REG(pVM, &pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL_SYNC].StatDo,STAMTYPE_PROFILE,"/TM/DoQueues/VirtualSync",        STAMUNIT_TICKS_PER_CALL, "Time spent on the virtual sync clock queue.");
     715    STAM_REG(pVM, &pVM->tm.s.aTimerQueues[TMCLOCK_REAL].StatDo,       STAMTYPE_PROFILE, "/TM/DoQueues/Real",               STAMUNIT_TICKS_PER_CALL, "Time spent on the real clock queue.");
    714716
    715717    STAM_REG(pVM, &pVM->tm.s.StatPoll,                                STAMTYPE_COUNTER, "/TM/Poll",                            STAMUNIT_OCCURENCES, "TMTimerPoll calls.");
     
    12121214    LogFlow(("TMR3Reset:\n"));
    12131215    VM_ASSERT_EMT(pVM);
    1214     TM_LOCK_TIMERS(pVM);
    12151216
    12161217    /*
     
    12391240     * Process the queues.
    12401241     */
    1241     for (int i = 0; i < TMCLOCK_MAX; i++)
    1242         tmTimerQueueSchedule(pVM, &pVM->tm.s.aTimerQueues[i], &pVM->tm.s.aTimerQueues[i]);
     1242    for (uint32_t idxQueue = 0; idxQueue < RT_ELEMENTS(pVM->tm.s.aTimerQueues); idxQueue++)
     1243    {
     1244        PTMTIMERQUEUE pQueue = &pVM->tm.s.aTimerQueues[idxQueue];
     1245        PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED);
     1246        tmTimerQueueSchedule(pVM, pQueue, pQueue);
     1247        PDMCritSectLeave(&pQueue->TimerLock);
     1248    }
    12431249#ifdef VBOX_STRICT
    12441250    tmTimerQueuesSanityChecks(pVM, "TMR3Reset");
     
    12921298        pVCpu->tm.s.u64TSCLastSeen = 0;
    12931299    }
    1294 
    1295     TM_UNLOCK_TIMERS(pVM);
    12961300}
    12971301
     
    16931697
    16941698#ifdef VBOX_STRICT
    1695     TM_LOCK_TIMERS(pVM);
    16961699    tmTimerQueuesSanityChecks(pVM, "tmR3TimerCreate");
    1697     TM_UNLOCK_TIMERS(pVM);
    16981700#endif
    16991701
     
    19001902     */
    19011903    PDMCritSectRwEnterExcl(&pQueue->AllocLock, VERR_IGNORED);
    1902     TM_LOCK_TIMERS(pVM);
     1904    PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED);
     1905
    19031906    for (int cRetries = 1000;; cRetries--)
    19041907    {
     
    19371940            case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
    19381941                AssertMsgFailed(("%p:.enmState=%s %s\n", pTimer, tmTimerState(enmState), pTimer->szName));
    1939                 TM_UNLOCK_TIMERS(pVM);
     1942                PDMCritSectLeave(&pQueue->TimerLock);
    19401943                PDMCritSectRwLeaveExcl(&pQueue->AllocLock);
    19411944
     
    19461949
    19471950                PDMCritSectRwEnterExcl(&pQueue->AllocLock, VERR_IGNORED);
    1948                 TM_LOCK_TIMERS(pVM);
     1951                PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED);
    19491952                continue;
    19501953
     
    19541957            case TMTIMERSTATE_FREE:
    19551958            case TMTIMERSTATE_DESTROY:
    1956                 TM_UNLOCK_TIMERS(pVM);
     1959                PDMCritSectLeave(&pQueue->TimerLock);
    19571960                PDMCritSectRwLeaveExcl(&pQueue->AllocLock);
    19581961                AssertLogRelMsgFailedReturn(("pTimer=%p %s\n", pTimer, tmTimerState(enmState)), VERR_TM_INVALID_STATE);
     
    19601963            default:
    19611964                AssertMsgFailed(("Unknown timer state %d (%s)\n", enmState, pTimer->szName));
    1962                 TM_UNLOCK_TIMERS(pVM);
     1965                PDMCritSectLeave(&pQueue->TimerLock);
    19631966                PDMCritSectRwLeaveExcl(&pQueue->AllocLock);
    19641967                return VERR_TM_UNKNOWN_STATE;
     
    19741977            break;
    19751978        AssertMsgFailed(("%p:.enmState=%s %s\n", pTimer, tmTimerState(enmState), pTimer->szName));
    1976         TM_UNLOCK_TIMERS(pVM);
     1979        PDMCritSectLeave(&pQueue->TimerLock);
    19771980        PDMCritSectRwLeaveExcl(&pQueue->AllocLock);
    19781981
     
    19811984
    19821985        PDMCritSectRwEnterExcl(&pQueue->AllocLock, VERR_IGNORED);
    1983         TM_LOCK_TIMERS(pVM);
     1986        PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED);
    19841987    }
    19851988
     
    20382041    tmTimerQueuesSanityChecks(pVM, "TMR3TimerDestroy");
    20392042#endif
    2040     TM_UNLOCK_TIMERS(pVM);
     2043    PDMCritSectLeave(&pQueue->TimerLock);
    20412044    PDMCritSectRwLeaveExcl(&pQueue->AllocLock);
    20422045    return VINF_SUCCESS;
     
    23242327    Assert(!pVM->tm.s.fRunningQueues);
    23252328    ASMAtomicWriteBool(&pVM->tm.s.fRunningQueues, true);
    2326     TM_LOCK_TIMERS(pVM);
    23272329
    23282330    /*
     
    23312333    AssertCompile(TMCLOCK_MAX == 4);
    23322334
    2333     /* TMCLOCK_VIRTUAL_SYNC (see also TMR3VirtualSyncFF) */
    2334     STAM_PROFILE_ADV_START(&pVM->tm.s.aStatDoQueues[TMCLOCK_VIRTUAL_SYNC], s1);
     2335    /*
     2336     * TMCLOCK_VIRTUAL_SYNC (see also TMR3VirtualSyncFF)
     2337     */
     2338    PTMTIMERQUEUE pQueue = &pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL_SYNC];
     2339    STAM_PROFILE_START(&pQueue->StatDo, s1);
     2340    PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED);
    23352341    PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VERR_IGNORED);
    23362342    ASMAtomicWriteBool(&pVM->tm.s.fRunningVirtualSyncQueue, true);
    23372343    VMCPU_FF_CLEAR(pVCpuDst, VMCPU_FF_TIMER);   /* Clear the FF once we started working for real. */
    23382344
    2339     Assert(pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL_SYNC].idxSchedule == UINT32_MAX);
     2345    Assert(pQueue->idxSchedule == UINT32_MAX);
    23402346    tmR3TimerQueueRunVirtualSync(pVM);
    23412347    if (pVM->tm.s.fVirtualSyncTicking) /** @todo move into tmR3TimerQueueRunVirtualSync - FIXME */
     
    23442350    ASMAtomicWriteBool(&pVM->tm.s.fRunningVirtualSyncQueue, false);
    23452351    PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock);
    2346     STAM_PROFILE_ADV_STOP(&pVM->tm.s.aStatDoQueues[TMCLOCK_VIRTUAL_SYNC], s1);
    2347 
    2348     /* TMCLOCK_VIRTUAL */
    2349     STAM_PROFILE_ADV_START(&pVM->tm.s.aStatDoQueues[TMCLOCK_VIRTUAL], s2);
    2350     if (pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL].idxSchedule != UINT32_MAX)
    2351         tmTimerQueueSchedule(pVM, &pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL], &pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL]);
    2352     tmR3TimerQueueRun(pVM, &pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL]);
    2353     STAM_PROFILE_ADV_STOP(&pVM->tm.s.aStatDoQueues[TMCLOCK_VIRTUAL], s2);
    2354 
    2355     /* TMCLOCK_TSC */
     2352    PDMCritSectLeave(&pQueue->TimerLock);
     2353    STAM_PROFILE_STOP(&pQueue->StatDo, s1);
     2354
     2355    /*
     2356     * TMCLOCK_VIRTUAL
     2357     */
     2358    pQueue = &pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL];
     2359    STAM_PROFILE_START(&pQueue->StatDo, s2);
     2360    PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED);
     2361    if (pQueue->idxSchedule != UINT32_MAX)
     2362        tmTimerQueueSchedule(pVM, pQueue, pQueue);
     2363    tmR3TimerQueueRun(pVM, pQueue);
     2364    PDMCritSectLeave(&pQueue->TimerLock);
     2365    STAM_PROFILE_STOP(&pQueue->StatDo, s2);
     2366
     2367    /*
     2368     * TMCLOCK_TSC
     2369     */
    23562370    Assert(pVM->tm.s.aTimerQueues[TMCLOCK_TSC].idxActive == UINT32_MAX); /* not used */
    23572371
    2358     /* TMCLOCK_REAL */
    2359     STAM_PROFILE_ADV_START(&pVM->tm.s.aStatDoQueues[TMCLOCK_REAL], s3);
    2360     if (pVM->tm.s.aTimerQueues[TMCLOCK_REAL].idxSchedule != UINT32_MAX)
    2361         tmTimerQueueSchedule(pVM, &pVM->tm.s.aTimerQueues[TMCLOCK_REAL], &pVM->tm.s.aTimerQueues[TMCLOCK_REAL]);
    2362     tmR3TimerQueueRun(pVM, &pVM->tm.s.aTimerQueues[TMCLOCK_REAL]);
    2363     STAM_PROFILE_ADV_STOP(&pVM->tm.s.aStatDoQueues[TMCLOCK_REAL], s3);
     2372    /*
     2373     * TMCLOCK_REAL
     2374     */
     2375    pQueue = &pVM->tm.s.aTimerQueues[TMCLOCK_REAL];
     2376    STAM_PROFILE_START(&pQueue->StatDo, s3);
     2377    PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED);
     2378    if (pQueue->idxSchedule != UINT32_MAX)
     2379        tmTimerQueueSchedule(pVM, pQueue, pQueue);
     2380    tmR3TimerQueueRun(pVM, pQueue);
     2381    PDMCritSectLeave(&pQueue->TimerLock);
     2382    STAM_PROFILE_STOP(&pQueue->StatDo, s3);
    23642383
    23652384#ifdef VBOX_STRICT
    23662385    /* check that we didn't screw up. */
    2367     TM_LOCK_TIMERS(pVM);
    23682386    tmTimerQueuesSanityChecks(pVM, "TMR3TimerQueuesDo");
    2369     TM_UNLOCK_TIMERS(pVM);
    23702387#endif
    23712388
     
    23732390    Log2(("TMR3TimerQueuesDo: returns void\n"));
    23742391    ASMAtomicWriteBool(&pVM->tm.s.fRunningQueues, false);
    2375     TM_UNLOCK_TIMERS(pVM);
    23762392    STAM_PROFILE_STOP(&pVM->tm.s.StatDoQueues, a);
    23772393}
     
    26492665        if (fRc && pTimer->uHzHint)
    26502666        {
    2651             if (pTimer->uHzHint >= pVM->tm.s.uMaxHzHint)
    2652                 ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, true);
     2667            if (pTimer->uHzHint >= pQueue->uMaxHzHint)
     2668                ASMAtomicOrU64(&pVM->tm.s.HzHint.u64Combined, RT_BIT_32(TMCLOCK_VIRTUAL_SYNC) | RT_BIT_32(TMCLOCK_VIRTUAL_SYNC + 16));
    26532669            pTimer->uHzHint = 0;
    26542670        }
     
    28252841
    28262842            /* try run it. */
    2827             TM_LOCK_TIMERS(pVM);
     2843            PDMCritSectEnter(&pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL].TimerLock, VERR_IGNORED);
    28282844            PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VERR_IGNORED);
    28292845            if (pVM->tm.s.fVirtualSyncTicking)
     
    28412857                ASMAtomicWriteBool(&pVM->tm.s.fRunningVirtualSyncQueue, false);
    28422858            }
     2859            PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock);
    28432860            STAM_PROFILE_STOP(&pVM->tm.s.StatVirtualSyncFF, a); /* before the unlock! */
    2844             PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock);
    2845             TM_UNLOCK_TIMERS(pVM);
     2861            PDMCritSectLeave(&pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL].TimerLock);
    28462862        }
    28472863    }
     
    31523168{
    31533169    VMCPU_ASSERT_EMT(pVCpu);
     3170    PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VERR_IGNORED); /* Paranoia: Exploiting the virtual sync lock here. */
    31543171
    31553172    /*
    31563173     * The shared virtual clock (includes virtual sync which is tied to it).
    31573174     */
    3158     TM_LOCK_TIMERS(pVM);                        /* Paranoia: Exploiting the timer lock here. */
    31593175    int rc = tmVirtualPauseLocked(pVM);
    3160     TM_UNLOCK_TIMERS(pVM);
    3161     if (RT_FAILURE(rc))
    3162         return rc;
     3176    AssertRCReturnStmt(rc, PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock), rc);
    31633177
    31643178    /*
     
    31683182    if (!pVM->tm.s.fTSCTiedToExecution)
    31693183    {
    3170         TM_LOCK_TIMERS(pVM);    /* Exploit the timer lock for synchronization. */
    31713184        rc = tmCpuTickPauseLocked(pVM, pVCpu);
    3172         TM_UNLOCK_TIMERS(pVM);
    3173         if (RT_FAILURE(rc))
    3174             return rc;
     3185        AssertRCReturnStmt(rc, PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock), rc);
    31753186    }
    31763187
     
    31983209#endif
    31993210
     3211    PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock);
    32003212    return VINF_SUCCESS;
    32013213}
     
    32133225{
    32143226    VMCPU_ASSERT_EMT(pVCpu);
    3215     int rc;
     3227    PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VERR_IGNORED); /* Paranoia: Exploiting the virtual sync lock here. */
    32163228
    32173229#ifndef VBOX_WITHOUT_NS_ACCOUNTING
     
    32333245    if (!pVM->tm.s.fTSCTiedToExecution)
    32343246    {
    3235         TM_LOCK_TIMERS(pVM);    /* Exploit the timer lock for synchronization. */
    3236         rc = tmCpuTickResumeLocked(pVM, pVCpu);
    3237         TM_UNLOCK_TIMERS(pVM);
    3238         if (RT_FAILURE(rc))
    3239             return rc;
     3247        int rc = tmCpuTickResumeLocked(pVM, pVCpu);
     3248        AssertRCReturnStmt(rc, PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock), rc);
    32403249    }
    32413250
     
    32433252     * The shared virtual clock (includes virtual sync which is tied to it).
    32443253     */
    3245     TM_LOCK_TIMERS(pVM);                        /* Paranoia: Exploiting the timer lock here. */
    3246     rc = tmVirtualResumeLocked(pVM);
    3247     TM_UNLOCK_TIMERS(pVM);
    3248 
     3254    int rc = tmVirtualResumeLocked(pVM);
     3255
     3256    PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock);
    32493257    return rc;
    32503258}
     
    32883296 * TM level and make it affect TMR3UTCNow as well! */
    32893297
     3298    PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VERR_IGNORED); /* Paranoia: Exploiting the virtual sync lock here. */
     3299
    32903300    /*
    32913301     * If the time is running we'll have to pause it before we can change
    32923302     * the warp drive settings.
    32933303     */
    3294     TM_LOCK_TIMERS(pVM);                        /* Paranoia: Exploiting the timer lock here. */
    32953304    bool fPaused = !!pVM->tm.s.cVirtualTicking;
    32963305    if (fPaused) /** @todo this isn't really working, but wtf. */
     
    33053314    if (fPaused)
    33063315        TMR3NotifyResume(pVM, pVCpu);
    3307     TM_UNLOCK_TIMERS(pVM);
     3316
     3317    PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock);
    33083318    return VINF_SUCCESS;
    33093319}
     
    38963906        PTMTIMERQUEUE pQueue = &pVM->tm.s.aTimerQueues[idxQueue];
    38973907        PDMCritSectRwEnterShared(&pQueue->AllocLock, VERR_IGNORED);
    3898         TM_LOCK_TIMERS(pVM);
     3908        PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED);
     3909
    38993910        for (PTMTIMERR3 pTimer = tmTimerQueueGetHead(pQueue, pQueue);
    39003911             pTimer;
     
    39143925                            pTimer->szName);
    39153926        }
    3916         TM_UNLOCK_TIMERS(pVM);
     3927
     3928        PDMCritSectLeave(&pQueue->TimerLock);
    39173929        PDMCritSectRwLeaveShared(&pQueue->AllocLock);
    39183930    }
  • trunk/src/VBox/VMM/include/TMInline.h

    r87792 r87812  
    163163}
    164164
     165/** @def TMTIMER_HANDLE_TO_VARS_RETURN_EX
     166 * Converts a timer handle to a timer pointer, returning @a a_rcRet if the
     167 * handle is invalid.
     168 *
     169 * This defines the following variables:
     170 *      - idxQueue: The queue index.
     171 *      - pQueueCC: Pointer to the context specific queue data.
     172 *      - pTimer:   The timer pointer.
     173 *      - idxTimer: The timer index.
     174 *
     175 * @param   a_pVM           The cross context VM structure.
     176 * @param   a_hTimer        The timer handle to translate.
     177 * @param   a_rcRet         What to return on failure.
     178 *
     179 * @note    This macro has no scoping, so careful when using it around
     180 *          conditional statements!
     181 */
     182#ifdef IN_RING3
     183# define TMTIMER_HANDLE_TO_VARS_RETURN_EX(a_pVM, a_hTimer, a_rcRet) \
     184        uintptr_t const idxQueue = (uintptr_t)((a_hTimer) >> TMTIMERHANDLE_QUEUE_IDX_SHIFT) \
     185                                 & (uintptr_t)TMTIMERHANDLE_QUEUE_IDX_SMASK; \
     186        AssertReturn(idxQueue < RT_ELEMENTS((a_pVM)->tm.s.aTimerQueues), a_rcRet); \
     187        PTMTIMERQUEUE const pQueue = &(a_pVM)->tm.s.aTimerQueues[idxQueue]; \
     188        PTMTIMERQUEUE const pQueueCC = pQueue; RT_NOREF(pQueueCC); \
     189        \
     190        uintptr_t const idxTimer = (uintptr_t)((a_hTimer) & TMTIMERHANDLE_TIMER_IDX_MASK); \
     191        AssertReturn(idxQueue < pQueue->cTimersAlloc, a_rcRet); \
     192        \
     193        PTMTIMER const pTimer = &pQueue->paTimers[idxTimer]; \
     194        AssertReturn(pTimer->hSelf == a_hTimer, a_rcRet)
     195#else
     196# define TMTIMER_HANDLE_TO_VARS_RETURN_EX(a_pVM, a_hTimer, a_rcRet) \
     197        uintptr_t const idxQueue = (uintptr_t)((a_hTimer) >> TMTIMERHANDLE_QUEUE_IDX_SHIFT) \
     198                                 & (uintptr_t)TMTIMERHANDLE_QUEUE_IDX_SMASK; \
     199        AssertReturn(idxQueue < RT_ELEMENTS((a_pVM)->tm.s.aTimerQueues), a_rcRet); \
     200        AssertCompile(RT_ELEMENTS((a_pVM)->tm.s.aTimerQueues) == RT_ELEMENTS((a_pVM)->tmr0.s.aTimerQueues)); \
     201        PTMTIMERQUEUE const   pQueue   = &(a_pVM)->tm.s.aTimerQueues[idxQueue]; RT_NOREF(pQueue); \
     202        PTMTIMERQUEUER0 const pQueueCC = &(a_pVM)->tmr0.s.aTimerQueues[idxQueue]; \
     203        \
     204        uintptr_t const idxTimer = (uintptr_t)((a_hTimer) & TMTIMERHANDLE_TIMER_IDX_MASK); \
     205        AssertReturn(idxQueue < pQueueCC->cTimersAlloc, a_rcRet); \
     206        \
     207        PTMTIMER const pTimer = &pQueueCC->paTimers[idxTimer]; \
     208        AssertReturn(pTimer->hSelf == a_hTimer, a_rcRet); \
     209        Assert(pTimer->fFlags & TMTIMER_FLAGS_RING0); \
     210        Assert(VM_IS_EMT(pVM))
     211#endif
     212
     213
     214/** @def TMTIMER_HANDLE_TO_VARS_RETURN_EX
     215 * Converts a timer handle to a timer pointer, returning VERR_INVALID_HANDLE if
     216 * the handle is invalid.
     217 *
     218 * This defines the following variables:
     219 *      - idxQueue: The queue index.
     220 *      - pQueueCC: Pointer to the context specific queue data.
     221 *      - pTimer:   The timer pointer.
     222 *      - idxTimer: The timer index.
     223 *
     224 * @param   a_pVM       The cross context VM structure.
     225 * @param   a_hTimer    The timer handle to translate.
     226 *
     227 * @note    This macro has no scoping, so careful when using it around
     228 *          conditional statements!
     229 */
     230#define TMTIMER_HANDLE_TO_VARS_RETURN(a_pVM, a_hTimer) TMTIMER_HANDLE_TO_VARS_RETURN_EX(a_pVM, a_hTimer, VERR_INVALID_HANDLE)
     231
    165232
    166233/** @def TMTIMER_HANDLE_TO_PTR_RETURN_EX
  • trunk/src/VBox/VMM/include/TMInternal.h

    r87794 r87812  
    284284    bool                    fCannotGrow;
    285285    /** Align on 64-byte boundrary. */
    286     bool                    afAlignment[7];
    287     /** Lock serializing timer allocation and deallocation. */
     286    bool                    afAlignment1[7];
     287    /** Time spent doing scheduling and timer callbacks. */
     288    STAMPROFILE             StatDo;
     289    /** The current max timer Hz hint. */
     290    uint32_t volatile       uMaxHzHint;
     291    uint32_t                u64Alignment2[7];
     292    /** Lock serializing the active timer list and associated work. */
     293    PDMCRITSECT             TimerLock;
     294    /** Lock serializing timer allocation and deallocation.
     295     * @note This may be used in read-mode all over the place if we later
     296     *       implement runtime array growing. */
    288297    PDMCRITSECTRW           AllocLock;
    289298} TMTIMERQUEUE;
     
    391400typedef struct TM
    392401{
     402    /** Timer queues for the different clock types.
     403     * @note is first in the structure to ensure cache-line alignment.  */
     404    TMTIMERQUEUE                aTimerQueues[TMCLOCK_MAX];
     405
    393406    /** The current TSC mode of the VM.
    394407     *  Config variable: Mode (string). */
     
    496509    }                           aVirtualSyncCatchUpPeriods[TM_MAX_CATCHUP_PERIODS];
    497510
    498     /** The current max timer Hz hint. */
    499     uint32_t volatile           uMaxHzHint;
    500     /** Whether to recalulate the HzHint next time its queried. */
    501     bool volatile               fHzHintNeedsUpdating;
    502     /** Alignment */
    503     bool                        afAlignment2[3];
     511    union
     512    {
     513        /** Combined value for updating. */
     514        uint64_t volatile       u64Combined;
     515        struct
     516        {
     517            /** Bitmap indicating which timer queues needs their uMaxHzHint updated. */
     518            uint32_t volatile   bmNeedsUpdating;
     519            /** The current max timer Hz hint. */
     520            uint32_t volatile   uMax;
     521        } s;
     522    } HzHint;
    504523    /** @cfgm{/TM/HostHzMax, uint32_t, Hz, 0, UINT32_MAX, 20000}
    505524     * The max host Hz frequency hint returned by TMCalcHostTimerFrequency.  */
     
    537556    R3PTRTYPE(char *)           pszAlignment2b;
    538557
    539     /** Timer queues for the different clock types. */
    540     TMTIMERQUEUE                aTimerQueues[TMCLOCK_MAX];
    541 
    542558    /** Pointer to our RC mapping of the GIP. */
    543559    RCPTRTYPE(void *)           pvGIPRC;
    544560    /** Pointer to our R3 mapping of the GIP. */
    545561    R3PTRTYPE(void *)           pvGIPR3;
     562
    546563
    547564    /** The schedule timer timer handle (runtime timer).
     
    560577    bool                        afAlignment3[2];
    561578
    562     /** Lock serializing access to the timer lists. */
    563     PDMCRITSECT                 TimerCritSect;
    564579    /** Lock serializing access to the VirtualSync clock and the associated
    565580     * timer queue. */
     
    572587     * @{ */
    573588    STAMPROFILE                 StatDoQueues;
    574     STAMPROFILEADV              aStatDoQueues[TMCLOCK_MAX];
    575589    /** @} */
    576590    /** tmSchedule
     
    836850DECLCALLBACK(DECLEXPORT(uint64_t))  tmVirtualNanoTSRediscover(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra);
    837851DECLCALLBACK(DECLEXPORT(uint64_t))  tmVirtualNanoTSBadCpuIndex(PRTTIMENANOTSDATA pData, PRTITMENANOTSEXTRA pExtra,
    838                                                                uint16_t idApic, uint16_t iCpuSet, uint16_t iGipCpu);
    839 
    840 /**
    841  * Try take the timer lock, wait in ring-3 return VERR_SEM_BUSY in R0/RC.
    842  *
    843  * @retval  VINF_SUCCESS on success (always in ring-3).
    844  * @retval  VERR_SEM_BUSY in RC and R0 if the semaphore is busy.
    845  *
    846  * @param   a_pVM       Pointer to the VM.
    847  *
    848  * @remarks The virtual sync timer queue requires the virtual sync lock.
    849  */
    850 #define TM_LOCK_TIMERS(a_pVM)       PDMCritSectEnter(&(a_pVM)->tm.s.TimerCritSect, VERR_SEM_BUSY)
    851 
    852 /**
    853  * Try take the timer lock, no waiting.
    854  *
    855  * @retval  VINF_SUCCESS on success.
    856  * @retval  VERR_SEM_BUSY if busy.
    857  *
    858  * @param   a_pVM       Pointer to the VM.
    859  *
    860  * @remarks The virtual sync timer queue requires the virtual sync lock.
    861  */
    862 #define TM_TRY_LOCK_TIMERS(a_pVM)   PDMCritSectTryEnter(&(a_pVM)->tm.s.TimerCritSect)
    863 
    864 /** Lock the timers (sans the virtual sync queue). */
    865 #define TM_UNLOCK_TIMERS(a_pVM)     do { PDMCritSectLeave(&(a_pVM)->tm.s.TimerCritSect); } while (0)
    866 
    867 /** Checks that the caller owns the timer lock.  */
    868 #define TM_ASSERT_TIMER_LOCK_OWNERSHIP(a_pVM) \
    869     Assert(PDMCritSectIsOwner(&(a_pVM)->tm.s.TimerCritSect))
    870 
     852                                                              uint16_t idApic, uint16_t iCpuSet, uint16_t iGipCpu);
    871853/** @} */
    872854
     
    874856
    875857#endif /* !VMM_INCLUDED_SRC_include_TMInternal_h */
    876 
  • trunk/src/VBox/VMM/testcase/tstVMStructSize.cpp

    r87563 r87812  
    348348
    349349    /* TM */
    350     CHECK_MEMBER_ALIGNMENT(TM, TimerCritSect, sizeof(uintptr_t));
     350    CHECK_MEMBER_ALIGNMENT(TM, aTimerQueues, 64);
    351351    CHECK_MEMBER_ALIGNMENT(TM, VirtualSyncLock, sizeof(uintptr_t));
    352352
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