VirtualBox

Changeset 54410 in vbox


Ignore:
Timestamp:
Feb 24, 2015 2:52:10 AM (10 years ago)
Author:
vboxsync
Message:

IPRT/r0drv: Implemented RTMpOnPair for NT (windows).

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/Makefile.kmk

    r54408 r54410  
    20022002        generic/mppresent-generic.cpp \
    20032003        generic/RTMpGetCoreCount-generic.cpp \
    2004         generic/RTMpOnPair-generic.cpp \
    20052004        nt/RTErrConvertFromNtStatus.cpp \
    20062005        r0drv/generic/threadctxhooks-r0drv-generic.cpp \
  • trunk/src/VBox/Runtime/r0drv/mp-r0drv.h

    r53717 r54410  
    5353    void       *pvUser2;
    5454    RTCPUID     idCpu;
     55    RTCPUID     idCpu2;
    5556    uint32_t volatile cHits;
    5657#ifdef RT_OS_WINDOWS
  • trunk/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp

    r53768 r54410  
    4747{
    4848    RT_NT_CPUID_SPECIFIC,
     49    RT_NT_CPUID_PAIR,
    4950    RT_NT_CPUID_OTHERS,
    5051    RT_NT_CPUID_ALL
     
    248249/**
    249250 * Wrapper between the native KIPI_BROADCAST_WORKER and IPRT's PFNRTMPWORKER for
     251 * the RTMpOnPair case.
     252 *
     253 * @param   uUserCtx            The user context argument (PRTMPARGS).
     254 */
     255static ULONG_PTR __stdcall rtmpNtOnPairBroadcastIpiWrapper(ULONG_PTR uUserCtx)
     256{
     257    PRTMPARGS pArgs = (PRTMPARGS)uUserCtx;
     258    RTCPUID idCpu = KeGetCurrentProcessorNumber();
     259    if (   pArgs->idCpu  == idCpu
     260        || pArgs->idCpu2 == idCpu)
     261    {
     262        ASMAtomicIncU32(&pArgs->cHits);
     263        pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
     264    }
     265    return 0;
     266}
     267
     268
     269/**
     270 * Wrapper between the native KIPI_BROADCAST_WORKER and IPRT's PFNRTMPWORKER for
    250271 * the RTMpOnSpecific case.
    251272 *
     
    268289 * Internal worker for the RTMpOn* APIs using KeIpiGenericCall.
    269290 *
    270  * @returns IPRT status code.
    271  * @param   pfnWorker       The callback.
    272  * @param   pvUser1         User argument 1.
    273  * @param   pvUser2         User argument 2.
    274  * @param   enmCpuid        What to do / is idCpu valid.
    275  * @param   idCpu           Used if enmCpuid RT_NT_CPUID_SPECIFIC, otherwise ignored.
     291 * @returns VINF_SUCCESS.
     292 * @param   pfnWorker   The callback.
     293 * @param   pvUser1     User argument 1.
     294 * @param   pvUser2     User argument 2.
     295 * @param   idCpu       First CPU to match, ultimately specific to the
     296 *                      pfnNativeWrapper used.
     297 * @param   idCpu2      Second CPU to match, ultimately specific to the
     298 *                      pfnNativeWrapper used.
     299 * @param   pcHits      Where to return the number of this. Optional.
    276300 */
    277301static int rtMpCallUsingBroadcastIpi(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2,
    278                                      PKIPI_BROADCAST_WORKER pfnNativeWrapper, RTCPUID idCpu)
     302                                     PKIPI_BROADCAST_WORKER pfnNativeWrapper, RTCPUID idCpu, RTCPUID idCpu2,
     303                                     uint32_t *pcHits)
    279304{
    280305    RTMPARGS Args;
     
    283308    Args.pvUser2   = pvUser2;
    284309    Args.idCpu     = idCpu;
     310    Args.idCpu2    = idCpu2;
    285311    Args.cRefs     = 0;
    286312    Args.cHits     = 0;
     
    288314    AssertPtr(g_pfnrtKeIpiGenericCall);
    289315    g_pfnrtKeIpiGenericCall(pfnNativeWrapper, (uintptr_t)&Args);
    290 
    291     if (   pfnNativeWrapper != rtmpNtOnSpecificBroadcastIpiWrapper
    292         || Args.cHits > 0)
    293         return VINF_SUCCESS;
    294     return VERR_CPU_OFFLINE;
     316    if (pcHits)
     317        *pcHits = Args.cHits;
     318    return VINF_SUCCESS;
    295319}
    296320
     
    307331{
    308332    PRTMPARGS pArgs = (PRTMPARGS)DeferredContext;
     333
    309334    ASMAtomicIncU32(&pArgs->cHits);
    310 
    311335    pArgs->pfnWorker(KeGetCurrentProcessorNumber(), pArgs->pvUser1, pArgs->pvUser2);
    312336
     
    323347 *
    324348 * @returns IPRT status code.
    325  * @param   pfnWorker       The callback.
    326  * @param   pvUser1         User argument 1.
    327  * @param   pvUser2         User argument 2.
    328  * @param   enmCpuid        What to do / is idCpu valid.
    329  * @param   idCpu           Used if enmCpuid RT_NT_CPUID_SPECIFIC, otherwise ignored.
    330  */
    331 static int rtMpCallUsingDpcs(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2, RT_NT_CPUID enmCpuid, RTCPUID idCpu)
     349 * @param   pfnWorker   The callback.
     350 * @param   pvUser1     User argument 1.
     351 * @param   pvUser2     User argument 2.
     352 * @param   enmCpuid    What to do / is idCpu valid.
     353 * @param   idCpu       Used if enmCpuid is RT_NT_CPUID_SPECIFIC or
     354 *                      RT_NT_CPUID_PAIR, otherwise ignored.
     355 * @param   idCpu2      Used if enmCpuid is RT_NT_CPUID_PAIR, otherwise ignored.
     356 * @param   pcHits      Where to return the number of this. Optional.
     357 */
     358static int rtMpCallUsingDpcs(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2,
     359                             RT_NT_CPUID enmCpuid, RTCPUID idCpu, RTCPUID idCpu2, uint32_t *pcHits)
    332360{
    333361    PRTMPARGS pArgs;
     
    361389    pArgs->pvUser2   = pvUser2;
    362390    pArgs->idCpu     = NIL_RTCPUID;
     391    pArgs->idCpu2    = NIL_RTCPUID;
    363392    pArgs->cHits     = 0;
    364393    pArgs->cRefs     = 1;
     
    371400        KeSetImportanceDpc(&paExecCpuDpcs[0], HighImportance);
    372401        KeSetTargetProcessorDpc(&paExecCpuDpcs[0], (int)idCpu);
     402        pArgs->idCpu = idCpu;
     403    }
     404    else if (enmCpuid == RT_NT_CPUID_SPECIFIC)
     405    {
     406        KeInitializeDpc(&paExecCpuDpcs[0], rtmpNtDPCWrapper, pArgs);
     407        KeSetImportanceDpc(&paExecCpuDpcs[0], HighImportance);
     408        KeSetTargetProcessorDpc(&paExecCpuDpcs[0], (int)idCpu);
     409        pArgs->idCpu = idCpu;
     410
     411        KeInitializeDpc(&paExecCpuDpcs[1], rtmpNtDPCWrapper, pArgs);
     412        KeSetImportanceDpc(&paExecCpuDpcs[1], HighImportance);
     413        KeSetTargetProcessorDpc(&paExecCpuDpcs[1], (int)idCpu2);
     414        pArgs->idCpu2 = idCpu2;
    373415    }
    374416    else
     
    398440        ASMAtomicIncS32(&pArgs->cRefs);
    399441        BOOLEAN ret = KeInsertQueueDpc(&paExecCpuDpcs[0], 0, 0);
     442        Assert(ret);
     443    }
     444    else if (enmCpuid == RT_NT_CPUID_PAIR)
     445    {
     446        ASMAtomicIncS32(&pArgs->cRefs);
     447        BOOLEAN ret = KeInsertQueueDpc(&paExecCpuDpcs[0], 0, 0);
     448        Assert(ret);
     449
     450        ASMAtomicIncS32(&pArgs->cRefs);
     451        ret = KeInsertQueueDpc(&paExecCpuDpcs[1], 0, 0);
    400452        Assert(ret);
    401453    }
     
    428480    g_pfnrtNtKeFlushQueuedDpcs();
    429481
     482    if (pcHits)
     483        *pcHits = pArgs->cHits;
     484
    430485    /* Dereference the argument structure. */
    431486    int32_t cRefs = ASMAtomicDecS32(&pArgs->cRefs);
     
    441496{
    442497    if (g_pfnrtKeIpiGenericCall)
    443         return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnAllBroadcastIpiWrapper, 0);
    444     return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_ALL, 0);
     498        return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnAllBroadcastIpiWrapper,
     499                                         NIL_RTCPUID, NIL_RTCPUID, NULL);
     500    return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_ALL, NIL_RTCPUID, NIL_RTCPUID, NULL);
    445501}
    446502
     
    449505{
    450506    if (g_pfnrtKeIpiGenericCall)
    451         return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnOthersBroadcastIpiWrapper, 0);
    452     return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_OTHERS, 0);
    453 }
     507        return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnOthersBroadcastIpiWrapper,
     508                                         NIL_RTCPUID, NIL_RTCPUID, NULL);
     509    return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_OTHERS, NIL_RTCPUID, NIL_RTCPUID, NULL);
     510}
     511
     512
     513RTDECL(int) RTMpOnPair(RTCPUID idCpu1, RTCPUID idCpu2, uint32_t fFlags, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
     514{
     515    int rc;
     516    AssertReturn(idCpu1 != idCpu2, VERR_INVALID_PARAMETER);
     517    AssertReturn(!(fFlags & RTMPON_F_VALID_MASK), VERR_INVALID_FLAGS);
     518    if ((fFlags & RTMPON_F_CONCURRENT_EXEC) && !g_pfnrtKeIpiGenericCall)
     519        return VERR_NOT_SUPPORTED;
     520
     521    /*
     522     * Check that both CPUs are online before doing the broadcast call.
     523     */
     524    if (   RTMpIsCpuOnline(idCpu1)
     525        && RTMpIsCpuOnline(idCpu2))
     526    {
     527        /*
     528         * The broadcast IPI isn't quite as bad as it could have been, because
     529         * it looks like windows doesn't synchronize CPUs on the way out, they
     530         * seems to get back to normal work while the pair is still busy.
     531         */
     532        uint32_t cHits = 0;
     533        if (g_pfnrtKeIpiGenericCall)
     534            rc = rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnPairBroadcastIpiWrapper, idCpu1, idCpu2, &cHits);
     535        else
     536            rc = rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_PAIR, idCpu1, idCpu2, &cHits);
     537        if (RT_SUCCESS(rc))
     538        {
     539            Assert(cHits <= 2);
     540            if (cHits == 2)
     541                rc = VINF_SUCCESS;
     542            else if (cHits == 1)
     543                rc = VERR_NOT_ALL_CPUS_SHOWED;
     544            else if (cHits == 0)
     545                rc = VERR_CPU_OFFLINE;
     546            else
     547                rc = VERR_CPU_IPE_1;
     548        }
     549    }
     550    /*
     551     * A CPU must be present to be considered just offline.
     552     */
     553    else if (   RTMpIsCpuPresent(idCpu1)
     554             && RTMpIsCpuPresent(idCpu2))
     555        rc = VERR_CPU_OFFLINE;
     556    else
     557        rc = VERR_CPU_NOT_FOUND;
     558    return rc;
     559}
     560
     561
     562RTDECL(bool) RTMpOnPairIsConcurrentExecSupported(void)
     563{
     564    return RTMpOnAllIsConcurrentSafe();
     565}
     566
    454567
    455568/**
     
    503616     * or if the current IRQL is unsuitable for KeWaitForSingleObject.
    504617     */
     618    int rc;
     619    uint32_t cHits = 0;
    505620    if (   g_pfnrtKeIpiGenericCall
    506621        && (   RTMpGetOnlineCount() <= 2
    507622            || KeGetCurrentIrql()   > APC_LEVEL) )
    508         return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnSpecificBroadcastIpiWrapper, 0);
    509 
    510 #if 0 /** @todo untested code. needs some tuning. */
     623        rc = rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnSpecificBroadcastIpiWrapper,
     624                                       idCpu, NIL_RTCPUID, &cHits);
     625    else
     626        rc = rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_SPECIFIC, idCpu, NIL_RTCPUID, &cHits);
     627    if (RT_SUCCESS(rc))
     628    {
     629        if (cHits == 1)
     630            return VINF_SUCCESS;
     631        rc = cHits == 0 ? VERR_CPU_OFFLINE : VERR_CPU_IPE_1;
     632    }
     633    return rc;
     634
     635#if 0 /** @todo Untested code replacing the rtMpCallUsingDpcs caste. Needs some tuning too, I guess. */
    511636    /*
    512637     * Initialize the argument package and the objects within it.
     
    631756    rtMpNtOnSpecificRelease(pArgs);
    632757    return rc;
    633 
    634 #else
    635     return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_SPECIFIC, idCpu);
    636758#endif
    637759}
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