VirtualBox

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


Ignore:
Timestamp:
Dec 11, 2021 1:38:33 AM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
148821
Message:

IPRT/timer-r0drv-nt.cpp,mp-r0drv-nt.cpp: Work around rtMpNtSetTargetProcessorDpc failure on systems with sparse CPU ID assignments (like on testboxmem1). For timers, if the function fails for an offline CPU, just defer the DPC setup.

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

Legend:

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

    r92871 r92873  
    13501350 *
    13511351 * @returns IPRT status code (errors are asserted).
     1352 * @retval  VERR_CPU_NOT_FOUND if impossible CPU. Not asserted.
    13521353 * @param   pDpc                The DPC.
    13531354 * @param   idCpu               The ID of the new target CPU.
     1355 * @note    Callable at any IRQL.
    13541356 */
    13551357DECLHIDDEN(int) rtMpNtSetTargetProcessorDpc(KDPC *pDpc, RTCPUID idCpu)
     
    13611363        PROCESSOR_NUMBER ProcNum;
    13621364        NTSTATUS rcNt = g_pfnrtKeGetProcessorNumberFromIndex(RTMpCpuIdToSetIndex(idCpu), &ProcNum);
    1363         AssertLogRelMsgReturn(NT_SUCCESS(rcNt), ("KeGetProcessorNumberFromIndex(%u) -> %#x\n", idCpu, rcNt),
    1364                               RTErrConvertFromNtStatus(rcNt));
    1365 
    1366         rcNt = g_pfnrtKeSetTargetProcessorDpcEx(pDpc, &ProcNum);
    1367         AssertLogRelMsgReturn(NT_SUCCESS(rcNt),
    1368                               ("KeSetTargetProcessorDpcEx(,%u(%u/%u)) -> %#x\n", idCpu, ProcNum.Group, ProcNum.Number, rcNt),
    1369                               RTErrConvertFromNtStatus(rcNt));
     1365        if (NT_SUCCESS(rcNt))
     1366        {
     1367            rcNt = g_pfnrtKeSetTargetProcessorDpcEx(pDpc, &ProcNum);
     1368            AssertLogRelMsgReturn(NT_SUCCESS(rcNt),
     1369                                  ("KeSetTargetProcessorDpcEx(,%u(%u/%u)) -> %#x\n", idCpu, ProcNum.Group, ProcNum.Number, rcNt),
     1370                                  RTErrConvertFromNtStatus(rcNt));
     1371        }
     1372        else if (rcNt == STATUS_INVALID_PARAMETER)
     1373            return VERR_CPU_NOT_FOUND;
     1374        else
     1375            AssertLogRelMsgReturn(NT_SUCCESS(rcNt), ("KeGetProcessorNumberFromIndex(%u) -> %#x\n", idCpu, rcNt),
     1376                                  RTErrConvertFromNtStatus(rcNt));
     1377
    13701378    }
    13711379    else if (g_pfnrtKeSetTargetProcessorDpc)
     
    19361944                g_pfnrtKeSetImportanceDpc(&s_aPokeDpcs[i], HighImportance);
    19371945            int rc = rtMpNtSetTargetProcessorDpc(&s_aPokeDpcs[i], idCpu);
    1938             if (RT_FAILURE(rc))
     1946            if (RT_FAILURE(rc) && rc != VERR_CPU_NOT_FOUND)
    19391947                return rc;
    19401948        }
  • trunk/src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp

    r92872 r92873  
    7474    /** The NT DPC object. */
    7575    KDPC                    NtDpc;
     76    /** Whether we failed to set the target CPU for the DPC and that this needs
     77     * to be done at RTTimerStart (simple timers) or during timer callback (omni). */
     78    bool                    fDpcNeedTargetCpuSet;
    7679} RTTIMERNTSUBTIMER;
    7780/** Pointer to a NT sub-timer structure. */
     
    426429
    427430/**
     431 * Called when we have an impcomplete DPC object.
     432 *
     433 * @returns KeInsertQueueDpc return value.
     434 * @param   pSubTimer       The sub-timer to queue an DPC for.
     435 * @param   iCpu            The CPU set index corresponding to that sub-timer.
     436 */
     437DECL_NO_INLINE(static, BOOLEAN) rtTimerNtOmniQueueDpcSlow(PRTTIMERNTSUBTIMER pSubTimer, int iCpu)
     438{
     439    int rc = rtMpNtSetTargetProcessorDpc(&pSubTimer->NtDpc, RTMpCpuIdFromSetIndex(iCpu));
     440    if (RT_SUCCESS(rc))
     441    {
     442        pSubTimer->fDpcNeedTargetCpuSet = false;
     443        return KeInsertQueueDpc(&pSubTimer->NtDpc, 0, 0);
     444    }
     445    return FALSE;
     446}
     447
     448
     449/**
     450 * Wrapper around KeInsertQueueDpc that makes sure the target CPU has been set.
     451 *
     452 * This is for handling deferred rtMpNtSetTargetProcessorDpc failures during
     453 * creation.  These errors happens for offline CPUs which probably never every
     454 * will come online, as very few systems do CPU hotplugging.
     455 *
     456 * @returns KeInsertQueueDpc return value.
     457 * @param   pSubTimer       The sub-timer to queue an DPC for.
     458 * @param   iCpu            The CPU set index corresponding to that sub-timer.
     459 */
     460DECLINLINE(BOOLEAN) rtTimerNtOmniQueueDpc(PRTTIMERNTSUBTIMER pSubTimer, int iCpu)
     461{
     462    if (RT_LIKELY(!pSubTimer->fDpcNeedTargetCpuSet))
     463        return KeInsertQueueDpc(&pSubTimer->NtDpc, 0, 0);
     464    return rtTimerNtOmniQueueDpcSlow(pSubTimer, iCpu);
     465}
     466
     467
     468/**
    428469 * Common timer callback worker for omni-timers.
    429470 *
     
    457498                if (   RTCpuSetIsMemberByIndex(&OnlineSet, iCpu)
    458499                    && iCpuSelf != iCpu)
    459                     KeInsertQueueDpc(&pTimer->aSubTimers[iCpu].NtDpc, 0, 0);
     500                    rtTimerNtOmniQueueDpc(&pTimer->aSubTimers[iCpu], iCpu);
    460501
    461502            pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
     
    475516                if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
    476517                    cCpus++;
    477             ASMAtomicAddS32(&pTimer->cOmniSuspendCountDown, cCpus);
     518            ASMAtomicAddS32(&pTimer->cOmniSuspendCountDown, cCpus); /** @todo this is bogus bogus bogus. The counter is only used here. */
    478519
    479520            for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
    480521                if (   RTCpuSetIsMemberByIndex(&OnlineSet, iCpu)
    481522                    && iCpuSelf != iCpu)
    482                     if (!KeInsertQueueDpc(&pTimer->aSubTimers[iCpu].NtDpc, 0, 0))
     523                    if (!rtTimerNtOmniQueueDpc(&pTimer->aSubTimers[iCpu], iCpu))
    483524                        ASMAtomicDecS32(&pTimer->cOmniSuspendCountDown); /* already queued and counted. */
    484525
     
    584625        KeReleaseSpinLock(&pTimer->Spinlock, bSavedIrql);
    585626        return VERR_CPU_OFFLINE;
     627    }
     628
     629    /*
     630     * Lazy set the DPC target CPU if needed.
     631     */
     632    if (   !pTimer->fSpecificCpu
     633        || !pTimer->aSubTimers[0].fDpcNeedTargetCpuSet)
     634    { /* likely */ }
     635    else
     636    {
     637        int rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[0].NtDpc, pTimer->idCpu);
     638        if (RT_FAILURE(rc))
     639        {
     640            KeReleaseSpinLock(&pTimer->Spinlock, bSavedIrql);
     641            return rc;
     642        }
    586643    }
    587644
     
    902959    if (RT_SUCCESS(rc))
    903960    {
     961        RTCPUSET OnlineSet;
     962        RTMpGetOnlineSet(&OnlineSet);
     963
    904964        if (pTimer->fOmniTimer)
    905965        {
     
    915975            pTimer->iMasterTick = 0;
    916976            pTimer->idCpu       = NIL_RTCPUID;
    917             for (unsigned iCpu = 0; iCpu < cSubTimers && RT_SUCCESS(rc); iCpu++)
     977            for (unsigned iCpu = 0; iCpu < cSubTimers; iCpu++)
    918978            {
    919979                pTimer->aSubTimers[iCpu].iTick   = 0;
    920980                pTimer->aSubTimers[iCpu].pParent = pTimer;
    921981
    922                 if (    pTimer->idCpu == NIL_RTCPUID
    923                     &&  RTMpIsCpuOnline(RTMpCpuIdFromSetIndex(iCpu)))
     982                if (   pTimer->idCpu == NIL_RTCPUID
     983                    && RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
    924984                {
    925985                    pTimer->idCpu = RTMpCpuIdFromSetIndex(iCpu);
     
    935995                if (g_pfnrtKeSetImportanceDpc)
    936996                    g_pfnrtKeSetImportanceDpc(&pTimer->aSubTimers[iCpu].NtDpc, HighImportance);
    937                 rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[iCpu].NtDpc, iCpu);
     997
     998                /* This does not necessarily work for offline CPUs that could potentially be onlined
     999                   at runtime, so postpone it. (See troubles on testboxmem1 after r148799.) */
     1000                int rc2 = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[iCpu].NtDpc, iCpu);
     1001                if (RT_SUCCESS(rc2))
     1002                    pTimer->aSubTimers[0].fDpcNeedTargetCpuSet = false;
     1003                else if (!RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
     1004                    pTimer->aSubTimers[0].fDpcNeedTargetCpuSet = true;
     1005                else
     1006                {
     1007                    rc = rc2;
     1008                    break;
     1009                }
    9381010            }
    9391011            Assert(pTimer->idCpu != NIL_RTCPUID);
     
    9531025                g_pfnrtKeSetImportanceDpc(&pTimer->aSubTimers[0].NtDpc, HighImportance);
    9541026            if (pTimer->fSpecificCpu)
    955                 rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[0].NtDpc, fFlags & RTTIMER_FLAGS_CPU_MASK);
     1027            {
     1028                /* This does not necessarily work for offline CPUs that could potentially be onlined
     1029                   at runtime, so postpone it. (See troubles on testboxmem1 after r148799.) */
     1030                int rc2 = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[0].NtDpc, pTimer->idCpu);
     1031                if (RT_SUCCESS(rc2))
     1032                    pTimer->aSubTimers[0].fDpcNeedTargetCpuSet = false;
     1033                else if (!RTCpuSetIsMember(&OnlineSet, pTimer->idCpu))
     1034                    pTimer->aSubTimers[0].fDpcNeedTargetCpuSet = true;
     1035                else
     1036                    rc = rc2;
     1037            }
    9561038        }
    9571039        if (RT_SUCCESS(rc))
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