VirtualBox

Changeset 92825 in vbox for trunk/src/VBox/Runtime/r0drv


Ignore:
Timestamp:
Dec 8, 2021 3:32:59 PM (3 years ago)
Author:
vboxsync
Message:

IPRT/timer-r0drv-nt.cpp: Implemented high resolution timers using the ExAllocateTimer API from windows 8.1.

Location:
trunk/src/VBox/Runtime/r0drv/nt
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp

    r92183 r92825  
    4949/** ExSetTimerResolution, introduced in W2K. */
    5050PFNMYEXSETTIMERRESOLUTION               g_pfnrtNtExSetTimerResolution;
     51/** ExAllocateTimer, introduced in Windows 8.1 */
     52PFNEXALLOCATETIMER                      g_pfnrtExAllocateTimer;
     53/** ExDeleteTimer, introduced in Windows 8.1 */
     54PFNEXDELETETIMER                        g_pfnrtExDeleteTimer;
     55/** ExSetTimer, introduced in Windows 8.1 */
     56PFNEXSETTIMER                           g_pfnrtExSetTimer;
     57/** ExCancelTimer, introduced in Windows 8.1 */
     58PFNEXCANCELTIMER                        g_pfnrtExCancelTimer;
    5159/** KeFlushQueuedDpcs, introduced in XP. */
    5260PFNMYKEFLUSHQUEUEDDPCS                  g_pfnrtNtKeFlushQueuedDpcs;
     
    303311    GET_SYSTEM_ROUTINE(ExFreePoolWithTag);
    304312    GET_SYSTEM_ROUTINE_PRF(Nt,ExSetTimerResolution);
     313    GET_SYSTEM_ROUTINE_TYPE(ExAllocateTimer, PFNEXALLOCATETIMER);
     314    GET_SYSTEM_ROUTINE_TYPE(ExDeleteTimer, PFNEXDELETETIMER);
     315    GET_SYSTEM_ROUTINE_TYPE(ExSetTimer, PFNEXSETTIMER);
     316    GET_SYSTEM_ROUTINE_TYPE(ExCancelTimer, PFNEXCANCELTIMER);
    305317    GET_SYSTEM_ROUTINE_PRF(Nt,KeFlushQueuedDpcs);
    306318    GET_SYSTEM_ROUTINE(KeIpiGenericCall);
  • trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h

    r91449 r92825  
    3636RT_C_DECLS_BEGIN
    3737
    38 /*******************************************************************************
    39 *   Structures and Typedefs                                                    *
    40 *******************************************************************************/
     38/*********************************************************************************************************************************
     39*   Structures and Typedefs                                                                                                      *
     40*********************************************************************************************************************************/
    4141typedef ULONG (__stdcall *PFNMYEXSETTIMERRESOLUTION)(ULONG, BOOLEAN);
    4242typedef VOID (__stdcall *PFNMYKEFLUSHQUEUEDDPCS)(VOID);
     
    5454                                                     SIZE_T, MEMORY_CACHING_TYPE, ULONG);
    5555
     56#ifndef EX_TIMER_HIGH_RESOLUTION /* Too old DDK, so add missing bits. */
     57# define EX_TIMER_NO_WAKE               RT_BIT_32(3)
     58# define EX_TIMER_HIGH_RESOLUTION       RT_BIT_32(2)
     59# define EX_TIMER_NOTIFICATION          RT_BIT_32(31)
     60typedef struct _EX_TIMER *PEX_TIMER;
     61typedef VOID (__stdcall *PEXT_CALLBACK)(PEX_TIMER, void *);
     62typedef PEX_TIMER (__stdcall *PFNEXALLOCATETIMER)(PEXT_CALLBACK pfnCallback, void *pvUser, ULONG fFlags);
    5663
    57 /*******************************************************************************
    58 *   Global Variables                                                           *
    59 *******************************************************************************/
     64typedef VOID (__stdcall *PEXT_DELETE_CALLBACK)(void *);
     65typedef struct _EXT_DELETE_PARAMETERS
     66{
     67    ULONG                   Version;
     68    ULONG                   Reserved;
     69    PEXT_DELETE_CALLBACK    DeleteCallback;
     70    void                   *DeleteContext;
     71} EXT_DELETE_PARAMETERS;
     72typedef EXT_DELETE_PARAMETERS *PEXT_DELETE_PARAMETERS;
     73DECLINLINE(void) ExInitializeDeleteTimerParameters(PEXT_DELETE_PARAMETERS pParams)
     74{
     75    pParams->Version        = 0;
     76    pParams->Reserved       = 0;
     77    pParams->DeleteCallback = NULL;
     78    pParams->DeleteContext  = NULL;
     79}
     80typedef BOOLEAN   (__stdcall *PFNEXDELETETIMER)(PEX_TIMER pTimer, BOOLEAN fCancel, BOOLEAN fWait, PEXT_DELETE_PARAMETERS pParams);
     81
     82typedef struct _EXT_SET_PARAMETERS_V0
     83{
     84    ULONG       Version;
     85    ULONG       Reserved;
     86    LONGLONG    NoWakeTolerance;
     87} EXT_SET_PARAMETERS;
     88typedef EXT_SET_PARAMETERS *PEXT_SET_PARAMETERS;
     89DECLINLINE(void) ExInitializeSetTimerParameters(PEXT_SET_PARAMETERS pParams)
     90{
     91    pParams->Version         = 0;
     92    pParams->Reserved        = 0;
     93    pParams->NoWakeTolerance = 0;
     94}
     95typedef BOOLEAN   (__stdcall *PFNEXSETTIMER)(PEX_TIMER pTimer, LONGLONG DueTime, LONGLONG Period, PEXT_SET_PARAMETERS pParams);
     96
     97typedef BOOLEAN   (__stdcall *PFNEXCANCELTIMER)(PEX_TIMER pTimer, void *pvReserved);
     98
     99#else
     100typedef decltype(ExAllocateTimer) *PFNEXALLOCATETIMER;
     101typedef decltype(ExDeleteTimer)   *PFNEXDELETETIMER;
     102typedef decltype(ExSetTimer)      *PFNEXSETTIMER;
     103typedef decltype(ExCancelTimer)   *PFNEXCANCELTIMER;
     104#endif
     105
     106
     107/*********************************************************************************************************************************
     108*   Global Variables                                                                                                             *
     109*********************************************************************************************************************************/
    60110extern RTCPUSET                                g_rtMpNtCpuSet;
    61111extern uint32_t                                g_cRtMpNtMaxGroups;
     
    66116extern decltype(ExFreePoolWithTag)            *g_pfnrtExFreePoolWithTag;
    67117extern PFNMYEXSETTIMERRESOLUTION               g_pfnrtNtExSetTimerResolution;
     118extern PFNEXALLOCATETIMER                      g_pfnrtExAllocateTimer;
     119extern PFNEXDELETETIMER                        g_pfnrtExDeleteTimer;
     120extern PFNEXSETTIMER                           g_pfnrtExSetTimer;
     121extern PFNEXCANCELTIMER                        g_pfnrtExCancelTimer;
    68122extern PFNMYKEFLUSHQUEUEDDPCS                  g_pfnrtNtKeFlushQueuedDpcs;
    69123extern PFNHALREQUESTIPI_W7PLUS                 g_pfnrtHalRequestIpiW7Plus;
  • trunk/src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp

    r82968 r92825  
    4343#include "internal/magics.h"
    4444
     45
     46/*********************************************************************************************************************************
     47*   Defined Constants And Macros                                                                                                 *
     48*********************************************************************************************************************************/
    4549/** This seems to provide better accuracy. */
    4650#define RTR0TIMER_NT_MANUAL_RE_ARM 1
     51
     52#if !defined(IN_GUEST) || defined(DOXYGEN_RUNNING)
     53/** This using high resolution timers introduced with windows 8.1. */
     54# define RTR0TIMER_NT_HIGH_RES 1
     55#endif
    4756
    4857
     
    99108    uint64_t                uNtStartTime;
    100109#endif
    101     /** The Nt timer object. */
     110    /** The NT timer object. */
    102111    KTIMER                  NtTimer;
     112#ifdef RTR0TIMER_NT_HIGH_RES
     113    /** High resolution timer.  If not NULL, this must be used instead of NtTimer. */
     114    PEX_TIMER               pHighResTimer;
     115#endif
    103116    /** The number of sub-timers. */
    104117    RTCPUID                 cSubTimers;
     
    145158 * @param   pTimer              The timer.
    146159 * @param   iTick               The current timer tick.
    147  * @param   pMasterDpc          The master DPC.
    148  */
    149 DECLINLINE(void) rtTimerNtRearmInternval(PRTTIMER pTimer, uint64_t iTick, PKDPC pMasterDpc)
     160 */
     161DECLINLINE(void) rtTimerNtRearmInternval(PRTTIMER pTimer, uint64_t iTick)
    150162{
    151163#ifdef RTR0TIMER_NT_MANUAL_RE_ARM
    152164    Assert(pTimer->u64NanoInterval);
    153     RT_NOREF1(pMasterDpc);
    154165
    155166    uint64_t uNtNext = (iTick * pTimer->u64NanoInterval) / 100 - 10; /* 1us fudge */
     
    163174        DueTime.QuadPart = -2500; /* 0.25ms */
    164175
    165     KeSetTimerEx(&pTimer->NtTimer, DueTime, 0, &pTimer->aSubTimers[0].NtDpc);
     176# ifdef RTR0TIMER_NT_HIGH_RES
     177    if (pTimer->pHighResTimer)
     178        g_pfnrtExSetTimer(pTimer->pHighResTimer, DueTime.QuadPart, 0, NULL);
     179    else
     180# endif
     181        KeSetTimerEx(&pTimer->NtTimer, DueTime, 0, &pTimer->aSubTimers[0].NtDpc);
    166182#else
    167     RT_NOREF3(pTimer, iTick, pMasterDpc);
    168 #endif
    169 }
    170 
    171 
    172 /**
    173  * Timer callback function for the non-omni timers.
     183    RT_NOREF(pTimer, iTick);
     184#endif
     185}
     186
     187
     188/**
     189 * Common timer callback worker for the non-omni timers.
    174190 *
    175191 * @returns HRTIMER_NORESTART or HRTIMER_RESTART depending on whether it's a one-shot or interval timer.
     192 * @param   pTimer          The timer.
     193 */
     194static void rtTimerNtSimpleCallbackWorker(PRTTIMER pTimer)
     195{
     196    /*
     197     * Check that we haven't been suspended before doing the callout.
     198     */
     199    if (    !ASMAtomicUoReadBool(&pTimer->fSuspended)
     200        &&  pTimer->u32Magic == RTTIMER_MAGIC)
     201    {
     202        ASMAtomicWriteHandle(&pTimer->aSubTimers[0].hActiveThread, RTThreadNativeSelf());
     203
     204        if (!pTimer->u64NanoInterval)
     205            ASMAtomicWriteBool(&pTimer->fSuspended, true);
     206        uint64_t iTick = ++pTimer->aSubTimers[0].iTick;
     207        if (pTimer->u64NanoInterval)
     208            rtTimerNtRearmInternval(pTimer, iTick);
     209        pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick);
     210
     211        ASMAtomicWriteHandle(&pTimer->aSubTimers[0].hActiveThread, NIL_RTNATIVETHREAD);
     212    }
     213}
     214
     215
     216/**
     217 * Timer callback function for the low-resolution non-omni timers.
     218 *
    176219 * @param   pDpc                Pointer to the DPC.
    177220 * @param   pvUser              Pointer to our internal timer structure.
     
    188231#endif
    189232
    190     /*
    191      * Check that we haven't been suspended before doing the callout.
    192      */
    193     if (    !ASMAtomicUoReadBool(&pTimer->fSuspended)
    194         &&  pTimer->u32Magic == RTTIMER_MAGIC)
    195     {
    196         ASMAtomicWriteHandle(&pTimer->aSubTimers[0].hActiveThread, RTThreadNativeSelf());
    197 
    198         if (!pTimer->u64NanoInterval)
    199             ASMAtomicWriteBool(&pTimer->fSuspended, true);
    200         uint64_t iTick = ++pTimer->aSubTimers[0].iTick;
    201         if (pTimer->u64NanoInterval)
    202             rtTimerNtRearmInternval(pTimer, iTick, &pTimer->aSubTimers[0].NtDpc);
    203         pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick);
    204 
    205         ASMAtomicWriteHandle(&pTimer->aSubTimers[0].hActiveThread, NIL_RTNATIVETHREAD);
    206     }
    207 
    208     NOREF(pDpc); NOREF(SystemArgument1); NOREF(SystemArgument2);
    209 }
     233    rtTimerNtSimpleCallbackWorker(pTimer);
     234
     235    RT_NOREF(pDpc, SystemArgument1, SystemArgument2);
     236}
     237
     238
     239#ifdef RTR0TIMER_NT_HIGH_RES
     240/**
     241 * Timer callback function for the high-resolution non-omni timers.
     242 *
     243 * @param   pExTimer            The windows timer.
     244 * @param   pvUser              Pointer to our internal timer structure.
     245 */
     246static void _stdcall rtTimerNtHighResSimpleCallback(PEX_TIMER pExTimer, void *pvUser)
     247{
     248    PRTTIMER pTimer = (PRTTIMER)pvUser;
     249    AssertPtr(pTimer);
     250    Assert(pTimer->pHighResTimer == pExTimer);
     251# ifdef RT_STRICT
     252    if (KeGetCurrentIrql() < DISPATCH_LEVEL)
     253        RTAssertMsg2Weak("rtTimerNtHighResSimpleCallback: Irql=%d expected >=%d\n", KeGetCurrentIrql(), DISPATCH_LEVEL);
     254# endif
     255
     256    /* If we're not on the desired CPU, trigger the DPC.  That will rearm the
     257       timer and such. */
     258    if (   !pTimer->fSpecificCpu
     259        || pTimer->idCpu == RTMpCpuId())
     260        rtTimerNtSimpleCallbackWorker(pTimer);
     261    else
     262        KeInsertQueueDpc(&pTimer->aSubTimers[0].NtDpc, 0, 0);
     263
     264    RT_NOREF(pExTimer);
     265}
     266#endif /* RTR0TIMER_NT_HIGH_RES */
    210267
    211268
     
    254311
    255312/**
    256  * The timer callback for an omni-timer.
     313 * Common timer callback worker for omni-timers.
    257314 *
    258315 * This is responsible for queueing the DPCs for the other CPUs and
    259316 * perform the callback on the CPU on which it is called.
    260317 *
    261  * @param   pDpc                The DPC object.
    262  * @param   pvUser              Pointer to the sub-timer.
    263  * @param   SystemArgument1     Some system stuff.
    264  * @param   SystemArgument2     Some system stuff.
    265  */
    266 static void _stdcall rtTimerNtOmniMasterCallback(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
    267 {
    268     PRTTIMERNTSUBTIMER pSubTimer = (PRTTIMERNTSUBTIMER)pvUser;
    269     PRTTIMER pTimer = pSubTimer->pParent;
    270     int iCpuSelf = RTMpCpuIdToSetIndex(RTMpCpuId());
    271 
    272     AssertPtr(pTimer);
     318 * @param   pTimer          The timer.
     319 * @param   pSubTimer       The sub-timer of the calling CPU.
     320 * @param   iCpuSelf        The set index of the CPU we're running on.
     321 */
     322static void rtTimerNtOmniMasterCallbackWorker(PRTTIMER pTimer, PRTTIMERNTSUBTIMER pSubTimer, int iCpuSelf)
     323{
    273324#ifdef RT_STRICT
    274325    if (KeGetCurrentIrql() < DISPATCH_LEVEL)
     
    301352
    302353            uint64_t iTick = ++pSubTimer->iTick;
    303             rtTimerNtRearmInternval(pTimer, iTick, &pTimer->aSubTimers[RTMpCpuIdToSetIndex(pTimer->idCpu)].NtDpc);
     354            rtTimerNtRearmInternval(pTimer, iTick);
    304355            pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick);
    305356        }
     
    329380        ASMAtomicWriteHandle(&pSubTimer->hActiveThread, NIL_RTNATIVETHREAD);
    330381    }
    331 
    332     NOREF(pDpc); NOREF(SystemArgument1); NOREF(SystemArgument2);
    333 }
    334 
     382}
     383
     384
     385/**
     386 * The timer callback for an omni-timer, low-resolution.
     387 *
     388 * @param   pDpc                The DPC object.
     389 * @param   pvUser              Pointer to the sub-timer.
     390 * @param   SystemArgument1     Some system stuff.
     391 * @param   SystemArgument2     Some system stuff.
     392 */
     393static void _stdcall rtTimerNtOmniMasterCallback(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
     394{
     395    PRTTIMERNTSUBTIMER const pSubTimer = (PRTTIMERNTSUBTIMER)pvUser;
     396    PRTTIMER const           pTimer    = pSubTimer->pParent;
     397    int const                iCpuSelf  = RTMpCpuIdToSetIndex(RTMpCpuId());
     398
     399    AssertPtr(pTimer);
     400#ifdef RT_STRICT
     401    if (KeGetCurrentIrql() < DISPATCH_LEVEL)
     402        RTAssertMsg2Weak("rtTimerNtOmniMasterCallback: Irql=%d expected >=%d\n", KeGetCurrentIrql(), DISPATCH_LEVEL);
     403    if (pSubTimer - &pTimer->aSubTimers[0] != iCpuSelf)
     404        RTAssertMsg2Weak("rtTimerNtOmniMasterCallback: iCpuSelf=%d pSubTimer=%p / %d\n", iCpuSelf, pSubTimer, pSubTimer - &pTimer->aSubTimers[0]);
     405#endif
     406
     407    rtTimerNtOmniMasterCallbackWorker(pTimer, pSubTimer, iCpuSelf);
     408
     409    RT_NOREF(pDpc, SystemArgument1, SystemArgument2);
     410}
     411
     412
     413#ifdef RTR0TIMER_NT_HIGH_RES
     414/**
     415 * The timer callback for an high-resolution omni-timer.
     416 *
     417 * @param   pExTimer            The windows timer.
     418 * @param   pvUser              Pointer to our internal timer structure.
     419 */
     420static void __stdcall rtTimerNtHighResOmniCallback(PEX_TIMER pExTimer, void *pvUser)
     421{
     422    PRTTIMER const           pTimer    = (PRTTIMER)pvUser;
     423    int const                iCpuSelf  = RTMpCpuIdToSetIndex(RTMpCpuId());
     424    PRTTIMERNTSUBTIMER const pSubTimer = &pTimer->aSubTimers[iCpuSelf];
     425
     426    AssertPtr(pTimer);
     427    Assert(pTimer->pHighResTimer == pExTimer);
     428# ifdef RT_STRICT
     429    if (KeGetCurrentIrql() < DISPATCH_LEVEL)
     430        RTAssertMsg2Weak("rtTimerNtHighResOmniCallback: Irql=%d expected >=%d\n", KeGetCurrentIrql(), DISPATCH_LEVEL);
     431# endif
     432
     433    rtTimerNtOmniMasterCallbackWorker(pTimer, pSubTimer, iCpuSelf);
     434
     435    RT_NOREF(pExTimer);
     436}
     437#endif /* RTR0TIMER_NT_HIGH_RES */
    335438
    336439
     
    373476    for (unsigned iCpu = 0; iCpu < cSubTimers; iCpu++)
    374477        pTimer->aSubTimers[iCpu].iTick = 0;
     478#ifdef RTR0TIMER_NT_MANUAL_RE_ARM
     479    pTimer->uNtStartTime = rtTimerNtQueryInterruptTime() + u64First / 100;
     480#endif
    375481    ASMAtomicWriteS32(&pTimer->cOmniSuspendCountDown, 0);
    376482    ASMAtomicWriteBool(&pTimer->fSuspended, false);
     483
     484#ifdef RTR0TIMER_NT_HIGH_RES
     485    if (pTimer->pHighResTimer)
     486    {
     487# ifdef RTR0TIMER_NT_MANUAL_RE_ARM
     488        g_pfnrtExSetTimer(pTimer->pHighResTimer, DueTime.QuadPart, 0, NULL);
     489# else
     490        g_pfnrtExSetTimer(pTimer->pHighResTimer, DueTime.QuadPart, RT_MIN(pTimer->u64NanoInterval / 100, MAXLONG), NULL);
     491# endif
     492    }
     493    else
     494#endif
     495    {
    377496#ifdef RTR0TIMER_NT_MANUAL_RE_ARM
    378     pTimer->uNtStartTime = rtTimerNtQueryInterruptTime() + u64First / 100;
    379     KeSetTimerEx(&pTimer->NtTimer, DueTime, 0, pMasterDpc);
     497        KeSetTimerEx(&pTimer->NtTimer, DueTime, 0, pMasterDpc);
    380498#else
    381     KeSetTimerEx(&pTimer->NtTimer, DueTime, ulInterval, pMasterDpc);
    382 #endif
     499        KeSetTimerEx(&pTimer->NtTimer, DueTime, ulInterval, pMasterDpc);
     500#endif
     501    }
    383502    return VINF_SUCCESS;
    384503}
     
    399518    ASMAtomicWriteBool(&pTimer->fSuspended, true);
    400519
    401     KeCancelTimer(&pTimer->NtTimer);
     520#ifdef RTR0TIMER_NT_HIGH_RES
     521    if (pTimer->pHighResTimer)
     522        g_pfnrtExCancelTimer(pTimer->pHighResTimer, NULL);
     523    else
     524#endif
     525        KeCancelTimer(&pTimer->NtTimer);
    402526
    403527    for (RTCPUID iCpu = 0; iCpu < pTimer->cSubTimers; iCpu++)
     
    456580    if (!ASMAtomicUoReadBool(&pTimer->fSuspended))
    457581        rtTimerNtStopWorker(pTimer);
     582
     583#ifdef RTR0TIMER_NT_HIGH_RES
     584    /*
     585     * Destroy the high-resolution timer before flushing DPCs.
     586     */
     587    if (pTimer->pHighResTimer)
     588    {
     589        g_pfnrtExDeleteTimer(pTimer->pHighResTimer, TRUE /*fCancel*/, TRUE /*fWait*/, NULL);
     590        pTimer->pHighResTimer = NULL;
     591    }
     592#endif
    458593
    459594    /*
     
    499634    /*
    500635     * Initialize it.
     636     *
     637     * Note! The difference between a SynchronizationTimer and a NotificationTimer
     638     *       (KeInitializeTimer) is, as far as I can gather, only that the former
     639     *       will wake up exactly one waiting thread and the latter will wake up
     640     *       everyone.  Since we don't do any waiting on the NtTimer, that is not
     641     *       relevant to us.
    501642     */
    502643    pTimer->u32Magic = RTTIMER_MAGIC;
     
    510651    pTimer->pvUser = pvUser;
    511652    pTimer->u64NanoInterval = u64NanoInterval;
    512     if (g_pfnrtKeInitializeTimerEx)
    513         g_pfnrtKeInitializeTimerEx(&pTimer->NtTimer, SynchronizationTimer);
     653
     654    int rc = VINF_SUCCESS;
     655#ifdef RTR0TIMER_NT_HIGH_RES
     656    if (   (fFlags & RTTIMER_FLAGS_HIGH_RES)
     657        && RTTimerCanDoHighResolution())
     658    {
     659        pTimer->pHighResTimer = g_pfnrtExAllocateTimer(pTimer->fOmniTimer ? rtTimerNtHighResOmniCallback
     660                                                       : rtTimerNtHighResSimpleCallback, pTimer,
     661                                                       EX_TIMER_HIGH_RESOLUTION | EX_TIMER_NOTIFICATION);
     662        if (!pTimer->pHighResTimer)
     663            rc = VERR_OUT_OF_RESOURCES;
     664    }
    514665    else
    515         KeInitializeTimer(&pTimer->NtTimer);
    516     int rc = VINF_SUCCESS;
    517     if (pTimer->fOmniTimer)
    518     {
    519         /*
    520          * Initialize the per-cpu "sub-timers", select the first online cpu
    521          * to be the master.
    522          * ASSUMES that no cpus will ever go offline.
    523          */
    524         pTimer->idCpu = NIL_RTCPUID;
    525         for (unsigned iCpu = 0; iCpu < cSubTimers && RT_SUCCESS(rc); iCpu++)
     666#endif
     667    {
     668        if (g_pfnrtKeInitializeTimerEx) /** @todo just call KeInitializeTimer. */
     669            g_pfnrtKeInitializeTimerEx(&pTimer->NtTimer, SynchronizationTimer);
     670        else
     671            KeInitializeTimer(&pTimer->NtTimer);
     672    }
     673    if (RT_SUCCESS(rc))
     674    {
     675        if (pTimer->fOmniTimer)
    526676        {
    527             pTimer->aSubTimers[iCpu].iTick = 0;
    528             pTimer->aSubTimers[iCpu].pParent = pTimer;
    529 
    530             if (    pTimer->idCpu == NIL_RTCPUID
    531                 &&  RTMpIsCpuOnline(RTMpCpuIdFromSetIndex(iCpu)))
     677            /*
     678             * Initialize the per-cpu "sub-timers", select the first online cpu to be
     679             * the master.  This ASSUMES that no cpus will ever go offline.
     680             *
     681             * Note! For the high-resolution scenario, all DPC callbacks are slaves as
     682             *       we have a dedicated timer callback, set above during allocation,
     683             *       and don't control which CPU it (rtTimerNtHighResOmniCallback) is
     684             *       called on.
     685             */
     686            pTimer->idCpu = NIL_RTCPUID;
     687            for (unsigned iCpu = 0; iCpu < cSubTimers && RT_SUCCESS(rc); iCpu++)
    532688            {
    533                 pTimer->idCpu = RTMpCpuIdFromSetIndex(iCpu);
    534                 KeInitializeDpc(&pTimer->aSubTimers[iCpu].NtDpc, rtTimerNtOmniMasterCallback, &pTimer->aSubTimers[iCpu]);
     689                pTimer->aSubTimers[iCpu].iTick = 0;
     690                pTimer->aSubTimers[iCpu].pParent = pTimer;
     691
     692                if (    pTimer->idCpu == NIL_RTCPUID
     693                    &&  RTMpIsCpuOnline(RTMpCpuIdFromSetIndex(iCpu)))
     694                {
     695                    pTimer->idCpu = RTMpCpuIdFromSetIndex(iCpu);
     696#ifdef RTR0TIMER_NT_HIGH_RES
     697                    if (pTimer->pHighResTimer)
     698                        KeInitializeDpc(&pTimer->aSubTimers[iCpu].NtDpc, rtTimerNtOmniSlaveCallback, &pTimer->aSubTimers[iCpu]);
     699                    else
     700#endif
     701                        KeInitializeDpc(&pTimer->aSubTimers[iCpu].NtDpc, rtTimerNtOmniMasterCallback, &pTimer->aSubTimers[iCpu]);
     702                }
     703                else
     704                    KeInitializeDpc(&pTimer->aSubTimers[iCpu].NtDpc, rtTimerNtOmniSlaveCallback, &pTimer->aSubTimers[iCpu]);
     705                if (g_pfnrtKeSetImportanceDpc)
     706                    g_pfnrtKeSetImportanceDpc(&pTimer->aSubTimers[iCpu].NtDpc, HighImportance);
     707                rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[iCpu].NtDpc, iCpu);
    535708            }
    536             else
    537                 KeInitializeDpc(&pTimer->aSubTimers[iCpu].NtDpc, rtTimerNtOmniSlaveCallback, &pTimer->aSubTimers[iCpu]);
     709            Assert(pTimer->idCpu != NIL_RTCPUID);
     710        }
     711        else
     712        {
     713            /*
     714             * Initialize the first "sub-timer", target the DPC on a specific processor
     715             * if requested to do so.
     716             */
     717            pTimer->aSubTimers[0].iTick = 0;
     718            pTimer->aSubTimers[0].pParent = pTimer;
     719
     720            KeInitializeDpc(&pTimer->aSubTimers[0].NtDpc, rtTimerNtSimpleCallback, pTimer);
    538721            if (g_pfnrtKeSetImportanceDpc)
    539                 g_pfnrtKeSetImportanceDpc(&pTimer->aSubTimers[iCpu].NtDpc, HighImportance);
    540             rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[iCpu].NtDpc, iCpu);
     722                g_pfnrtKeSetImportanceDpc(&pTimer->aSubTimers[0].NtDpc, HighImportance);
     723            if (pTimer->fSpecificCpu)
     724                rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[0].NtDpc, (int)pTimer->idCpu);
    541725        }
    542         Assert(pTimer->idCpu != NIL_RTCPUID);
    543     }
    544     else
    545     {
    546         /*
    547          * Initialize the first "sub-timer", target the DPC on a specific processor
    548          * if requested to do so.
    549          */
    550         pTimer->aSubTimers[0].iTick = 0;
    551         pTimer->aSubTimers[0].pParent = pTimer;
    552 
    553         KeInitializeDpc(&pTimer->aSubTimers[0].NtDpc, rtTimerNtSimpleCallback, pTimer);
    554         if (g_pfnrtKeSetImportanceDpc)
    555             g_pfnrtKeSetImportanceDpc(&pTimer->aSubTimers[0].NtDpc, HighImportance);
    556         if (pTimer->fSpecificCpu)
    557             rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[0].NtDpc, (int)pTimer->idCpu);
    558     }
    559     if (RT_SUCCESS(rc))
    560     {
    561         *ppTimer = pTimer;
    562         return VINF_SUCCESS;
     726        if (RT_SUCCESS(rc))
     727        {
     728            *ppTimer = pTimer;
     729            return VINF_SUCCESS;
     730        }
     731
     732#ifdef RTR0TIMER_NT_HIGH_RES
     733        if (pTimer->pHighResTimer)
     734        {
     735            g_pfnrtExDeleteTimer(pTimer->pHighResTimer, FALSE, FALSE, NULL);
     736            pTimer->pHighResTimer = NULL;
     737        }
     738#endif
    563739    }
    564740
     
    593769RTDECL(bool) RTTimerCanDoHighResolution(void)
    594770{
     771#ifdef RTR0TIMER_NT_HIGH_RES
     772    return g_pfnrtExAllocateTimer != NULL
     773        && g_pfnrtExDeleteTimer   != NULL
     774        && g_pfnrtExSetTimer      != NULL
     775        && g_pfnrtExCancelTimer   != NULL;
     776#else
    595777    return false;
    596 }
    597 
     778#endif
     779}
     780
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