VirtualBox

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


Ignore:
Timestamp:
Jan 2, 2015 9:24:23 PM (10 years ago)
Author:
vboxsync
Message:

RTMpPokeCpu+RTMpOn*/r0drv-nt: Reworked RTMpOn* using KeIpiGenericCall after seeing problems with the DPC approach on win 81. Reworked and reenabled the HalSendSoftwareInterrupt implementation of RTMpPokeCpu because KeIpiGenericCall is doing broadcast IPIs, which is potentially very inefficient for poking a single CPU.

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

Legend:

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

    r53456 r53718  
    5858/** HalRequestIpi, introduced in ??. */
    5959PFNHALREQUESTIPI                    g_pfnrtNtHalRequestIpi;
    60 /** HalSendSoftwareInterrupt */
     60/** HalSendSoftwareInterrupt, introduced in AMD64 version of W2K3. */
    6161PFNHALSENDSOFTWAREINTERRUPT         g_pfnrtNtHalSendSoftwareInterrupt;
    62 /** SendIpi handler based on Windows version */
    63 PFNRTSENDIPI                        g_pfnrtSendIpi;
    64 /** KeIpiGenericCall - Windows Server 2003+ only */
     62/** Worker for RTMpPokeCpu. */
     63PFNRTSENDIPI                        g_pfnrtMpPokeCpuWorker;
     64/** KeIpiGenericCall - Introduced in Windows Server 2003. */
    6565PFNRTKEIPIGENERICCALL               g_pfnrtKeIpiGenericCall;
    6666/** RtlGetVersion, introduced in ??. */
     
    386386
    387387    /*
    388      * Special IPI fun.
    389      */
    390     g_pfnrtSendIpi = rtMpSendIpiDummy;
     388     * Special IPI fun for RTMpPokeCpu.
     389     *
     390     * On Vista and later the DPC fallback doesn't seem to reliably send IPIs,
     391     * so we have to use alternative methods.  The NtHalSendSoftwareInterrupt
     392     * is preferrable, but if that's not available we'll settle for broadcast
     393     * IPIs.
     394     */
     395    g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingDpc;
    391396#ifndef IPRT_TARGET_NT4
    392     if (    g_pfnrtNtHalRequestIpi
    393         &&  OsVerInfo.uMajorVer == 6
    394         &&  OsVerInfo.uMinorVer == 0)
    395     {
    396         /* Vista or Windows Server 2008 */
    397         g_pfnrtSendIpi = rtMpSendIpiVista;
    398     }
    399     else if (   g_pfnrtNtHalSendSoftwareInterrupt
    400              && OsVerInfo.uMajorVer == 6
    401              && OsVerInfo.uMinorVer == 1)
    402     {
    403         /* Windows 7 or Windows Server 2008 R2 */
    404         g_pfnrtSendIpi = rtMpSendIpiWin7;
    405     }
    406     /* Windows XP should send always send an IPI -> VERIFY */
     397    if (g_pfnrtNtHalSendSoftwareInterrupt)
     398        g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingHalSendSoftwareInterrupt;
     399    else if (OsVerInfo.uMajorVer >= 6 && g_pfnrtKeIpiGenericCall)
     400        g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingBroadcastIpi;
     401    /* else: Windows XP should send always send an IPI -> VERIFY */
    407402#endif
    408403
  • trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h

    r53456 r53718  
    5858extern PFNHALREQUESTIPI                 g_pfnrtNtHalRequestIpi;
    5959extern PFNHALSENDSOFTWAREINTERRUPT      g_pfnrtNtHalSendSoftwareInterrupt;
    60 extern PFNRTSENDIPI                     g_pfnrtSendIpi;
     60extern PFNRTSENDIPI                     g_pfnrtMpPokeCpuWorker;
    6161extern PFNRTKEIPIGENERICCALL            g_pfnrtKeIpiGenericCall;
    6262extern PFNRTRTLGETVERSION               g_pfnrtRtlGetVersion;
     
    7272
    7373
    74 int rtMpSendIpiVista(RTCPUID idCpu);
    75 int rtMpSendIpiWin7(RTCPUID idCpu);
    76 int rtMpSendIpiDummy(RTCPUID idCpu);
     74int rtMpPokeCpuUsingDpc(RTCPUID idCpu);
     75int rtMpPokeCpuUsingBroadcastIpi(RTCPUID idCpu);
     76int rtMpPokeCpuUsingHalSendSoftwareInterrupt(RTCPUID idCpu);
    7777
    7878RT_C_DECLS_END
  • trunk/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp

    r53717 r53718  
    188188
    189189/**
    190  * Wrapper between the native nt per-cpu callbacks and PFNRTWORKER
    191  *
    192  * @param   Dpc                 DPC object
    193  * @param   DeferredContext     Context argument specified by KeInitializeDpc
    194  * @param   SystemArgument1     Argument specified by KeInsertQueueDpc
    195  * @param   SystemArgument2     Argument specified by KeInsertQueueDpc
    196  */
    197 static VOID rtmpNtDPCWrapper(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
    198 {
    199     PRTMPARGS pArgs = (PRTMPARGS)DeferredContext;
    200     ASMAtomicIncU32(&pArgs->cHits);
    201 
     190 * Wrapper between the native KIPI_BROADCAST_WORKER and IPRT's PFNRTMPWORKER for
     191 * the RTMpOnAll case.
     192 *
     193 * @param   uUserCtx            The user context argument (PRTMPARGS).
     194 */
     195static ULONG_PTR __stdcall rtmpNtOnAllBroadcastIpiWrapper(ULONG_PTR uUserCtx)
     196{
     197    PRTMPARGS pArgs = (PRTMPARGS)uUserCtx;
     198    /*ASMAtomicIncU32(&pArgs->cHits); - not needed */
    202199    pArgs->pfnWorker(KeGetCurrentProcessorNumber(), pArgs->pvUser1, pArgs->pvUser2);
    203 
    204     /* Dereference the argument structure. */
    205     int32_t cRefs = ASMAtomicDecS32(&pArgs->cRefs);
    206     Assert(cRefs >= 0);
    207     if (cRefs == 0)
    208         ExFreePool(pArgs);
     200    return 0;
    209201}
    210202
    211203
    212204/**
    213  * Internal worker for the RTMpOn* APIs.
     205 * Wrapper between the native KIPI_BROADCAST_WORKER and IPRT's PFNRTMPWORKER for
     206 * the RTMpOnOthers case.
     207 *
     208 * @param   uUserCtx            The user context argument (PRTMPARGS).
     209 */
     210static ULONG_PTR __stdcall rtmpNtOnOthersBroadcastIpiWrapper(ULONG_PTR uUserCtx)
     211{
     212    PRTMPARGS pArgs = (PRTMPARGS)uUserCtx;
     213    RTCPUID idCpu = KeGetCurrentProcessorNumber();
     214    if (pArgs->idCpu != idCpu)
     215    {
     216        /*ASMAtomicIncU32(&pArgs->cHits); - not needed */
     217        pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
     218    }
     219    return 0;
     220}
     221
     222
     223/**
     224 * Wrapper between the native KIPI_BROADCAST_WORKER and IPRT's PFNRTMPWORKER for
     225 * the RTMpOnSpecific case.
     226 *
     227 * @param   uUserCtx            The user context argument (PRTMPARGS).
     228 */
     229static ULONG_PTR __stdcall rtmpNtOnSpecificBroadcastIpiWrapper(ULONG_PTR uUserCtx)
     230{
     231    PRTMPARGS pArgs = (PRTMPARGS)uUserCtx;
     232    RTCPUID idCpu = KeGetCurrentProcessorNumber();
     233    if (pArgs->idCpu == idCpu)
     234    {
     235        ASMAtomicIncU32(&pArgs->cHits);
     236        pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
     237    }
     238    return 0;
     239}
     240
     241
     242/**
     243 * Internal worker for the RTMpOn* APIs using KeIpiGenericCall.
    214244 *
    215245 * @returns IPRT status code.
     
    220250 * @param   idCpu           Used if enmCpuid RT_NT_CPUID_SPECIFIC, otherwise ignored.
    221251 */
    222 static int rtMpCall(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2, RT_NT_CPUID enmCpuid, RTCPUID idCpu)
     252static int rtMpCallUsingBroadcastIpi(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2,
     253                                     PKIPI_BROADCAST_WORKER pfnNativeWrapper, RTCPUID idCpu)
     254{
     255    RTMPARGS Args;
     256    Args.pfnWorker = pfnWorker;
     257    Args.pvUser1   = pvUser1;
     258    Args.pvUser2   = pvUser2;
     259    Args.idCpu     = idCpu;
     260    Args.cRefs     = 0;
     261    Args.cHits     = 0;
     262
     263    AssertPtr(g_pfnrtKeIpiGenericCall);
     264    g_pfnrtKeIpiGenericCall(pfnNativeWrapper, (uintptr_t)&Args);
     265
     266    if (   pfnNativeWrapper != rtmpNtOnSpecificBroadcastIpiWrapper
     267        || Args.cHits > 0)
     268        return VINF_SUCCESS;
     269    return VERR_CPU_OFFLINE;
     270}
     271
     272
     273/**
     274 * Wrapper between the native nt per-cpu callbacks and PFNRTWORKER
     275 *
     276 * @param   Dpc                 DPC object
     277 * @param   DeferredContext     Context argument specified by KeInitializeDpc
     278 * @param   SystemArgument1     Argument specified by KeInsertQueueDpc
     279 * @param   SystemArgument2     Argument specified by KeInsertQueueDpc
     280 */
     281static VOID __stdcall rtmpNtDPCWrapper(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
     282{
     283    PRTMPARGS pArgs = (PRTMPARGS)DeferredContext;
     284    ASMAtomicIncU32(&pArgs->cHits);
     285
     286    pArgs->pfnWorker(KeGetCurrentProcessorNumber(), pArgs->pvUser1, pArgs->pvUser2);
     287
     288    /* Dereference the argument structure. */
     289    int32_t cRefs = ASMAtomicDecS32(&pArgs->cRefs);
     290    Assert(cRefs >= 0);
     291    if (cRefs == 0)
     292        ExFreePool(pArgs);
     293}
     294
     295
     296/**
     297 * Internal worker for the RTMpOn* APIs.
     298 *
     299 * @returns IPRT status code.
     300 * @param   pfnWorker       The callback.
     301 * @param   pvUser1         User argument 1.
     302 * @param   pvUser2         User argument 2.
     303 * @param   enmCpuid        What to do / is idCpu valid.
     304 * @param   idCpu           Used if enmCpuid RT_NT_CPUID_SPECIFIC, otherwise ignored.
     305 */
     306static int rtMpCallUsingDpcs(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2, RT_NT_CPUID enmCpuid, RTCPUID idCpu)
    223307{
    224308    PRTMPARGS pArgs;
     
    331415RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
    332416{
    333     return rtMpCall(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_ALL, 0);
     417    if (g_pfnrtKeIpiGenericCall)
     418        return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnAllBroadcastIpiWrapper, 0);
     419    return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_ALL, 0);
    334420}
    335421
     
    337423RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
    338424{
    339     return rtMpCall(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_OTHERS, 0);
     425    if (g_pfnrtKeIpiGenericCall)
     426        return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnOthersBroadcastIpiWrapper, 0);
     427    return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_OTHERS, 0);
    340428}
    341429
     
    348436              : VERR_CPU_OFFLINE;
    349437
    350     return rtMpCall(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_SPECIFIC, idCpu);
    351 }
    352 
    353 static KDPC aPokeDpcs[MAXIMUM_PROCESSORS] = {0};
    354 static bool fPokeDPCsInitialized = false;
     438    if (g_pfnrtKeIpiGenericCall)
     439        return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnSpecificBroadcastIpiWrapper, 0);
     440    return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_SPECIFIC, idCpu);
     441}
     442
     443
     444
    355445
    356446static VOID rtMpNtPokeCpuDummy(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
     
    364454#ifndef IPRT_TARGET_NT4
    365455
    366 ULONG_PTR rtMpIpiGenericCall(ULONG_PTR Argument)
     456static ULONG_PTR __stdcall rtMpIpiGenericCall(ULONG_PTR Argument)
    367457{
    368458    NOREF(Argument);
     
    371461
    372462
     463int rtMpPokeCpuUsingBroadcastIpi(RTCPUID idCpu)
     464{
     465    g_pfnrtKeIpiGenericCall(rtMpIpiGenericCall, 0);
     466    return VINF_SUCCESS;
     467}
     468
     469# if 0
    373470int rtMpSendIpiVista(RTCPUID idCpu)
    374471{
     472    /* If we start care about Vista, we should investigate a non-broadcast API. */
    375473    g_pfnrtKeIpiGenericCall(rtMpIpiGenericCall, 0);
    376474////    g_pfnrtNtHalRequestIpi(1 << idCpu);
    377475    return VINF_SUCCESS;
    378476}
    379 
    380 
    381 int rtMpSendIpiWin7(RTCPUID idCpu)
    382 {
    383     g_pfnrtKeIpiGenericCall(rtMpIpiGenericCall, 0);
    384 ////    g_pfnrtNtHalSendSoftwareInterrupt(idCpu, DISPATCH_LEVEL);
     477# endif
     478
     479
     480int rtMpPokeCpuUsingHalSendSoftwareInterrupt(RTCPUID idCpu)
     481{
     482    g_pfnrtNtHalSendSoftwareInterrupt(idCpu, DISPATCH_LEVEL);
    385483    return VINF_SUCCESS;
    386484}
     
    389487
    390488
    391 int rtMpSendIpiDummy(RTCPUID idCpu)
    392 {
    393     return VERR_NOT_IMPLEMENTED;
    394 }
    395 
    396 
    397 RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
    398 {
    399     if (!RTMpIsCpuOnline(idCpu))
    400         return !RTMpIsCpuPossible(idCpu)
    401               ? VERR_CPU_NOT_FOUND
    402               : VERR_CPU_OFFLINE;
    403 
    404     int rc = g_pfnrtSendIpi(idCpu);
    405     if (rc == VINF_SUCCESS)
    406         return rc;
    407 
    408     /* Fallback. */
    409     if (!fPokeDPCsInitialized)
    410     {
    411         for (unsigned i = 0; i < RT_ELEMENTS(aPokeDpcs); i++)
     489int rtMpPokeCpuUsingDpc(RTCPUID idCpu)
     490{
     491    /*
     492     * APC fallback.
     493     */
     494    static KDPC s_aPokeDpcs[MAXIMUM_PROCESSORS] = {0};
     495    static bool s_fPokeDPCsInitialized = false;
     496
     497    if (!s_fPokeDPCsInitialized)
     498    {
     499        for (unsigned i = 0; i < RT_ELEMENTS(s_aPokeDpcs); i++)
    412500        {
    413             KeInitializeDpc(&aPokeDpcs[i], rtMpNtPokeCpuDummy, NULL);
    414             KeSetImportanceDpc(&aPokeDpcs[i], HighImportance);
    415             KeSetTargetProcessorDpc(&aPokeDpcs[i], (int)i);
     501            KeInitializeDpc(&s_aPokeDpcs[i], rtMpNtPokeCpuDummy, NULL);
     502            KeSetImportanceDpc(&s_aPokeDpcs[i], HighImportance);
     503            KeSetTargetProcessorDpc(&s_aPokeDpcs[i], (int)i);
    416504        }
    417         fPokeDPCsInitialized = true;
     505        s_fPokeDPCsInitialized = true;
    418506    }
    419507
     
    424512    KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
    425513
    426     KeSetImportanceDpc(&aPokeDpcs[idCpu], HighImportance);
    427     KeSetTargetProcessorDpc(&aPokeDpcs[idCpu], (int)idCpu);
     514    KeSetImportanceDpc(&s_aPokeDpcs[idCpu], HighImportance);
     515    KeSetTargetProcessorDpc(&s_aPokeDpcs[idCpu], (int)idCpu);
    428516
    429517    /* Assuming here that high importance DPCs will be delivered immediately; or at least an IPI will be sent immediately.
    430518     * @note: not true on at least Vista & Windows 7
    431519     */
    432     BOOLEAN bRet = KeInsertQueueDpc(&aPokeDpcs[idCpu], 0, 0);
     520    BOOLEAN bRet = KeInsertQueueDpc(&s_aPokeDpcs[idCpu], 0, 0);
    433521
    434522    KeLowerIrql(oldIrql);
     
    437525
    438526
     527RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
     528{
     529    if (!RTMpIsCpuOnline(idCpu))
     530        return !RTMpIsCpuPossible(idCpu)
     531              ? VERR_CPU_NOT_FOUND
     532              : VERR_CPU_OFFLINE;
     533    /* Calls rtMpSendIpiFallback, rtMpSendIpiWin7AndLater or rtMpSendIpiVista. */
     534    return g_pfnrtMpPokeCpuWorker(idCpu);
     535}
     536
     537
    439538RTDECL(bool) RTMpOnAllIsConcurrentSafe(void)
    440539{
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