VirtualBox

Changeset 54395 in vbox


Ignore:
Timestamp:
Feb 23, 2015 5:34:01 PM (10 years ago)
Author:
vboxsync
Message:

IPRT, HostDriver, VMMR0: MP notifications fixes for TSC-delta measurements, scheduling of notification callback taken care by the API consumer instead of IPRT.

Location:
trunk/src/VBox
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/SUPDrvGip.cpp

    r54392 r54395  
    109109#define GIP_TSC_DELTA_SYNC_PRESTART_WORKER  5
    110110/** The TSC-refinement interval in seconds. */
    111 #define GIP_TSC_REFINE_PREIOD_IN_SECS       5
     111#define GIP_TSC_REFINE_PERIOD_IN_SECS       5
    112112/** The TSC-delta threshold for the SUPGIPUSETSCDELTA_PRACTICALLY_ZERO rating */
    113113#define GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO    32
     
    142142static DECLCALLBACK(void)   supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
    143143static void                 supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS, uint64_t uCpuHz);
     144static int                  supdrvMeasureInitialTscDeltas(PSUPDRVDEVEXT pDevExt);
     145static int                  supdrvMeasureTscDeltaOne(PSUPDRVDEVEXT pDevExt, uint32_t idxWorker);
    144146#ifdef SUPDRV_USE_TSC_DELTA_THREAD
    145147static int                  supdrvTscDeltaThreadInit(PSUPDRVDEVEXT pDevExt);
    146148static void                 supdrvTscDeltaTerm(PSUPDRVDEVEXT pDevExt);
    147 static int                  supdrvTscDeltaThreadWaitForOnlineCpus(PSUPDRVDEVEXT pDevExt);
     149static void                 supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt);
    148150#endif
    149151
     
    197199 * @note    Don't you dare change the delta calculation.  If you really do, make
    198200 *          sure you update all places where it's used (IPRT, SUPLibAll.cpp,
    199  *          SUPDrv.c, supdrvGipMpEvent, and more).
     201 *          SUPDrv.c, supdrvGipMpEvent(), and more).
    200202 */
    201203DECLINLINE(int) supdrvTscDeltaApply(PSUPGLOBALINFOPAGE pGip, uint64_t *puTsc, uint16_t idApic, bool *pfDeltaApplied)
     
    769771
    770772/**
    771  * Used by supdrvInitRefineInvariantTscFreqTimer and supdrvGipInitMeasureTscFreq
    772  * to update the TSC frequency related GIP variables.
     773 * Used by supdrvInitRefineInvariantTscFreqTimer() and
     774 * supdrvGipInitMeasureTscFreq() to update the TSC frequency related GIP
     775 * variables.
    773776 *
    774777 * @param   pGip                The GIP.
     
    807810 *
    808811 * This is started during driver init and fires once
    809  * GIP_TSC_REFINE_PREIOD_IN_SECS seconds later.
     812 * GIP_TSC_REFINE_PERIOD_IN_SECS seconds later.
    810813 *
    811814 * @param   pTimer      The timer.
     
    834837     *         an interrupt handler with higher priority than the clock
    835838     *         interrupt, or spinning for ages in timer handlers is frowned
    836      *         upon, this look must be disabled!
     839     *         upon, this code must be disabled!
    837840     *
    838841     * Darwin, FreeBSD, Linux, Solaris, Windows 8.1+:
     
    863866    /*
    864867     * If the above measurement was taken on a different CPU than the one we
    865      * started the rprocess on, cTscTicksElapsed will need to be adjusted with
     868     * started the process on, cTscTicksElapsed will need to be adjusted with
    866869     * the TSC deltas of both the CPUs.
    867870     *
     
    896899         * calculations.
    897900         */
    898         else if (cNsElapsed <= GIP_TSC_REFINE_PREIOD_IN_SECS * 5 * RT_NS_1SEC_64)
     901        else if (cNsElapsed <= GIP_TSC_REFINE_PERIOD_IN_SECS * 5 * RT_NS_1SEC_64)
    899902        {
    900903            int rc = RTTimerStart(pTimer, RT_NS_1SEC);
     
    905908        {
    906909            SUPR0Printf("vboxdrv: Failed to refine invariant TSC frequency because deltas are unavailable after %u (%u) seconds\n",
    907                         (uint32_t)(cNsElapsed / RT_NS_1SEC), GIP_TSC_REFINE_PREIOD_IN_SECS);
     910                        (uint32_t)(cNsElapsed / RT_NS_1SEC), GIP_TSC_REFINE_PERIOD_IN_SECS);
    908911            SUPR0Printf("vboxdrv: start: %u, %u, %#llx  stop: %u, %u, %#llx\n",
    909912                        iStartCpuSet, iStartGipCpu, iStartTscDelta, iStopCpuSet, iStopGipCpu, iStopTscDelta);
     
    927930         * Reschedule the timer if we haven't yet reached the defined refinement period.
    928931         */
    929         if (cNsElapsed < GIP_TSC_REFINE_PREIOD_IN_SECS * RT_NS_1SEC_64)
     932        if (cNsElapsed < GIP_TSC_REFINE_PERIOD_IN_SECS * RT_NS_1SEC_64)
    930933        {
    931934            int rc = RTTimerStart(pTimer, RT_NS_1SEC);
     
    980983     * first VMs before we're done.  On most systems we will be loading the
    981984     * support driver during boot and VMs won't be started for a while yet,
    982      * it is really only a problem during development (especiall with
     985     * it is really only a problem during development (especially with
    983986     * on-demand driver starting on windows).
    984987     *
    985      * To avoid wasting time doing a long supdrvGipInitMeasureTscFreq call
    986      * to calculate the frequencey during driver loading, the timer is set
     988     * To avoid wasting time doing a long supdrvGipInitMeasureTscFreq() call
     989     * to calculate the frequency during driver loading, the timer is set
    987990     * to fire after 200 ms the first time. It will then reschedule itself
    988      * to fire every second until GIP_TSC_REFINE_PREIOD_IN_SECS has been
     991     * to fire every second until GIP_TSC_REFINE_PERIOD_IN_SECS has been
    989992     * reached or it notices that there is a user land client with GIP
    990993     * mapped (we want a stable frequency for all VMs).
     
    12921295
    12931296    AssertPtrReturnVoid(pGip);
     1297    Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    12941298    AssertRelease(idCpu == RTMpCpuId());
    12951299    Assert(pGip->cPossibleCpus == RTMpGetCount());
     
    13331337    ASMAtomicWriteU16(&pGip->aiCpuFromCpuSetIdx[iCpuSet], i);
    13341338
     1339    /* Add this CPU to this set of CPUs we need to calculate the TSC-delta for. */
     1340    RTCpuSetAddByIndex(&pDevExt->TscDeltaCpuSet, RTMpCpuIdToSetIndex(idCpu));
     1341
    13351342    /* Update the Mp online/offline counter. */
    13361343    ASMAtomicIncU32(&pDevExt->cMpOnOffEvents);
    13371344
    1338     /* Add this CPU to the set of CPUs for which we need to calculate their TSC-deltas. */
    1339     if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
    1340     {
    1341         RTCpuSetAddByIndex(&pDevExt->TscDeltaCpuSet, iCpuSet);
    1342 #ifdef SUPDRV_USE_TSC_DELTA_THREAD
    1343         RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
    1344         if (   pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening
    1345             || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring)
    1346         {
    1347             pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_WaitAndMeasure;
    1348         }
    1349         RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
    1350 #endif
    1351     }
    1352 
    1353     /* commit it */
     1345    /* Commit it. */
    13541346    ASMAtomicWriteSize(&pGip->aCPUs[i].enmState, SUPGIPCPUSTATE_ONLINE);
    13551347
    13561348    RTSpinlockRelease(pDevExt->hGipSpinlock);
     1349}
     1350
     1351
     1352/**
     1353 * RTMpOnSpecific callback wrapper for supdrvGipMpEventOnlineOrInitOnCpu().
     1354 *
     1355 * @param   idCpu     The CPU ID we are running on.
     1356 * @param   pvUser1    Opaque pointer to the device instance data.
     1357 * @param   pvUser2    Not used.
     1358 */
     1359static DECLCALLBACK(void) supdrvGipMpEventOnlineCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
     1360{
     1361    PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser1;
     1362    NOREF(pvUser2);
     1363    supdrvGipMpEventOnlineOrInitOnCpu(pDevExt, idCpu);
    13571364}
    13581365
     
    13961403    }
    13971404
    1398     /* commit it */
     1405    /* Commit it. */
    13991406    ASMAtomicWriteSize(&pGip->aCPUs[i].enmState, SUPGIPCPUSTATE_OFFLINE);
    14001407
     
    14121419 * @param   idCpu       The cpu it applies to.
    14131420 * @param   pvUser      Pointer to the device extension.
    1414  *
    1415  * @remarks This function -must- fire on the newly online'd CPU for the
    1416  *          RTMPEVENT_ONLINE case and can fire on any CPU for the
    1417  *          RTMPEVENT_OFFLINE case.
    14181421 */
    14191422static DECLCALLBACK(void) supdrvGipMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser)
     
    14221425    PSUPGLOBALINFOPAGE  pGip    = pDevExt->pGip;
    14231426
    1424     AssertRelease(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    1425 
    1426     /*
    1427      * Update the GIP CPU data.
    1428      */
    14291427    if (pGip)
    14301428    {
     1429        RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
    14311430        switch (enmEvent)
    14321431        {
    14331432            case RTMPEVENT_ONLINE:
    1434                 AssertRelease(idCpu == RTMpCpuId());
    1435                 supdrvGipMpEventOnlineOrInitOnCpu(pDevExt, idCpu);
     1433            {
     1434                RTThreadPreemptDisable(&PreemptState);
     1435                if (idCpu == RTMpCpuId())
     1436                {
     1437                    supdrvGipMpEventOnlineOrInitOnCpu(pDevExt, idCpu);
     1438                    RTThreadPreemptRestore(&PreemptState);
     1439                }
     1440                else
     1441                {
     1442                    RTThreadPreemptRestore(&PreemptState);
     1443                    RTMpOnSpecific(idCpu, supdrvGipMpEventOnlineCallback, pDevExt, NULL /* pvUser2 */);
     1444                }
     1445
     1446                /*
     1447                 * Recompute TSC-delta for the newly online'd CPU.
     1448                 */
     1449                if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
     1450                {
     1451#ifdef SUPDRV_USE_TSC_DELTA_THREAD
     1452                    supdrvTscDeltaThreadStartMeasurement(pDevExt);
     1453#else
     1454                    uint32_t iCpu = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu);
     1455                    supdrvMeasureTscDeltaOne(pDevExt, iCpu);
     1456#endif
     1457                }
    14361458                break;
     1459            }
     1460
    14371461            case RTMPEVENT_OFFLINE:
    14381462                supdrvGipMpEventOffline(pDevExt, idCpu);
     
    16891713    ASMAtomicWriteU16(&pCpu->idApic,    UINT16_MAX);
    16901714
    1691     /* 
     1715    /*
    16921716     * The first time we're called, we don't have a CPU frequency handy,
    16931717     * so pretend it's a 4 GHz CPU.  On CPUs that are online, we'll get
     
    18731897     * If we're in any of the other two modes, neither which require MP init,
    18741898     * notifications or deltas for the job, do the full measurement now so
    1875      * that supdrvGipInitOnCpu can populate the TSC interval and history
     1899     * that supdrvGipInitOnCpu() can populate the TSC interval and history
    18761900     * array with more reasonable values.
    18771901     */
    18781902    if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
    18791903    {
    1880         rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, true /*fRough*/); /* cannot fail */
     1904        rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, true /* fRough */); /* cannot fail */
    18811905        supdrvGipInitStartTimerForRefiningInvariantTscFreq(pDevExt, pGip);
    18821906    }
    18831907    else
    1884         rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, false /*fRough*/);
     1908        rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, false /* fRough */);
    18851909    if (RT_SUCCESS(rc))
    18861910    {
     
    19101934                {
    19111935#ifdef SUPDRV_USE_TSC_DELTA_THREAD
    1912                     if (pDevExt->hTscDeltaThread != NIL_RTTHREAD)
    1913                         RTThreadUserSignal(pDevExt->hTscDeltaThread);
     1936                    supdrvTscDeltaThreadStartMeasurement(pDevExt);
    19141937#else
    19151938                    uint16_t iCpu;
     
    24322455
    24332456    ASMSetFlags(uFlags);
    2434 
    2435 #ifdef SUPDRV_USE_TSC_DELTA_THREAD
    2436     if (   pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED
    2437         && !RTCpuSetIsEmpty(&pDevExt->TscDeltaCpuSet))
    2438     {
    2439         RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
    2440         if (   pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening
    2441             || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring)
    2442             pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_WaitAndMeasure;
    2443         RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
    2444         /** @todo Do the actual poking using -- RTThreadUserSignal() */
    2445     }
    2446 #endif
    24472457}
    24482458
     
    25772587
    25782588/**
    2579  * Argument package/state passed by supdrvMeasureTscDeltaOne to the RTMpOn
     2589 * Argument package/state passed by supdrvMeasureTscDeltaOne() to the RTMpOn
    25802590 * callback worker.
    25812591 */
     
    31573167 * The idea here is that we have the two CPUs execute the exact same code
    31583168 * collecting a largish set of TSC samples.  The code has one data dependency on
    3159  * the other CPU which intention it is to synchronize the execution as well as
    3160  * help cross references the two sets of TSC samples (the sequence numbers).
     3169 * the other CPU with the intention to synchronize the execution as well
     3170 * as help cross references the two sets of TSC samples (the sequence numbers).
    31613171 *
    31623172 * The @a fLag parameter is used to modify the execution a tiny bit on one or
     
    38113821         */
    38123822        PSUPDRVGIPTSCDELTARGS pArgs = (PSUPDRVGIPTSCDELTARGS)RTMemAllocZ(sizeof(*pArgs));
    3813         if (pArgs)
     3823        if (RT_LIKELY(pArgs))
    38143824        {
    38153825            pArgs->pWorker      = pGipCpuWorker;
     
    41064116                RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
    41074117                pDevExt->cMsTscDeltaTimeout = 1;
    4108                 RTThreadSleep(10);
     4118                RTThreadSleep(1);
    41094119                /* fall thru */
    41104120            }
     
    42564266
    42574267/**
    4258  * Waits for TSC-delta measurements to be completed for all online CPUs.
    4259  *
    4260  * @returns VBox status code.
    4261  * @param   pDevExt         Pointer to the device instance data.
    4262  */
    4263 static int supdrvTscDeltaThreadWaitForOnlineCpus(PSUPDRVDEVEXT pDevExt)
    4264 {
    4265     int cTriesLeft = 5;
    4266     int cMsTotalWait;
    4267     int cMsWaited = 0;
    4268     int cMsWaitGranularity = 1;
    4269 
    4270     PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
    4271     AssertReturn(pGip, VERR_INVALID_POINTER);
    4272 
    4273     if (RT_UNLIKELY(pDevExt->hTscDeltaThread == NIL_RTTHREAD))
    4274         return VERR_THREAD_NOT_WAITABLE;
    4275 
    4276     cMsTotalWait = RT_MIN(pGip->cPresentCpus + 10, 200);
    4277     while (cTriesLeft-- > 0)
    4278     {
    4279         if (RTCpuSetIsEqual(&pDevExt->TscDeltaObtainedCpuSet, &pGip->OnlineCpuSet))
    4280             return VINF_SUCCESS;
    4281         RTThreadSleep(cMsWaitGranularity);
    4282         cMsWaited += cMsWaitGranularity;
    4283         if (cMsWaited >= cMsTotalWait)
    4284             break;
    4285     }
    4286 
    4287     return VERR_TIMEOUT;
     4268 * Signals the TSC-delta thread to start measuring TSC-deltas.
     4269 *
     4270 * @param   pDevExt     Pointer to the device instance data.
     4271 */
     4272static void supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt)
     4273{
     4274    if (RT_LIKELY(pDevExt->hTscDeltaThread != NIL_RTTHREAD))
     4275    {
     4276        RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
     4277        if (   pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening
     4278            || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring)
     4279        {
     4280            pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_WaitAndMeasure;
     4281        }
     4282        RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
     4283        RTThreadUserSignal(pDevExt->hTscDeltaThread);
     4284    }
    42884285}
    42894286
     
    44574454        return VERR_INVALID_FLAGS;
    44584455
     4456    /*
     4457     * The request is a noop if the TSC delta isn't being used.
     4458     */
     4459    if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ZERO_CLAIMED)
     4460        return VINF_SUCCESS;
     4461
    44594462    if (cTries == 0)
    44604463        cTries = 12;
     
    44664469    else if (cMsWaitRetry > 1000)
    44674470        cMsWaitRetry = 1000;
    4468 
    4469     /*
    4470      * The request is a noop if the TSC delta isn't being used.
    4471      */
    4472     if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ZERO_CLAIMED)
    4473         return VINF_SUCCESS;
    44744471
    44754472#ifdef SUPDRV_USE_TSC_DELTA_THREAD
     
    44974494            rc = VINF_SUCCESS;
    44984495        }
    4499         else
     4496        else if (pDevExt->enmTscDeltaThreadState != kTscDeltaThreadState_WaitAndMeasure)
    45004497            rc = VERR_THREAD_IS_DEAD;
    45014498        RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
     
    46134610
    46144611    return SUPR0TscDeltaMeasureBySetIndex(pSession, iCpuSet, fFlags, cMsWaitRetry,
    4615                                           cTries == 0 ? 5*RT_MS_1SEC : cMsWaitRetry * cTries /*cMsWaitThread*/,
     4612                                          cTries == 0 ? 5 * RT_MS_1SEC : cMsWaitRetry * cTries /*cMsWaitThread*/,
    46164613                                          cTries);
    46174614}
     
    46914688                rc = supdrvMeasureTscDeltaOne(pDevExt, iGipCpu);
    46924689                Assert(pGip->aCPUs[iGipCpu].i64TSCDelta != INT64_MAX || RT_FAILURE_NP(rc));
    4693                 /** @todo should probably delay on failure... dpc watchdogs   */
     4690                /** @todo should probably delay on failure... dpc watchdogs */
    46944691            }
    46954692            else
  • trunk/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c

    r44529 r54395  
    55
    66/*
    7  * Copyright (C) 2008-2011 Oracle Corporation
     7 * Copyright (C) 2008-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3232#include "internal/iprt.h"
    3333
    34 #include <iprt/mp.h>
    3534#include <iprt/asm-amd64-x86.h>
    3635#include <iprt/err.h>
     
    7069
    7170/**
    72  * Notification wrapper that updates CPU states and invokes our notification
    73  * callbacks.
    74  *
    75  * @param idCpu             The CPU Id.
    76  * @param pvUser1           Pointer to the notifier_block (unused).
    77  * @param pvUser2           The notification event.
    78  * @remarks This can be invoked in interrupt context.
    79  */
    80 static DECLCALLBACK(void) rtMpNotificationLinuxOnCurrentCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
    81 {
    82     unsigned long ulNativeEvent = *(unsigned long *)pvUser2;
    83     NOREF(pvUser1);
    84 
    85     AssertRelease(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    86     AssertReleaseMsg(idCpu == RTMpCpuId(),  /* ASSUMES iCpu == RTCPUID */
    87                      ("idCpu=%u RTMpCpuId=%d ApicId=%d\n", idCpu, RTMpCpuId(), ASMGetApicId() ));
    88 
    89     switch (ulNativeEvent)
    90     {
    91 # ifdef CPU_DOWN_FAILED
    92         case CPU_DOWN_FAILED:
    93 #  if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_FAILED_FROZEN)
    94         case CPU_DOWN_FAILED_FROZEN:
    95 #  endif
    96 # endif
    97         case CPU_ONLINE:
    98 # if defined(CPU_TASKS_FROZEN) && defined(CPU_ONLINE_FROZEN)
    99         case CPU_ONLINE_FROZEN:
    100 # endif
    101             rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE, idCpu);
    102             break;
    103 
    104 # ifdef CPU_DOWN_PREPARE
    105         case CPU_DOWN_PREPARE:
    106 #  if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_PREPARE_FROZEN)
    107         case CPU_DOWN_PREPARE_FROZEN:
    108 #  endif
    109             rtMpNotificationDoCallbacks(RTMPEVENT_OFFLINE, idCpu);
    110             break;
    111 # endif
    112     }
    113 }
    114 
    115 
    116 /**
    11771 * The native callback.
    11872 *
     
    12175 * @param   ulNativeEvent   The native event.
    12276 * @param   pvCpu           The cpu id cast into a pointer value.
     77 *
    12378 * @remarks This can fire with preemption enabled and on any CPU.
    12479 */
    12580static int rtMpNotificationLinuxCallback(struct notifier_block *pNotifierBlock, unsigned long ulNativeEvent, void *pvCpu)
    12681{
    127     int rc;
    12882    bool fProcessEvent = false;
    12983    RTCPUID idCpu      = (uintptr_t)pvCpu;
     
    188142        return NOTIFY_DONE;
    189143
    190     /*
    191      * Reschedule the callbacks to fire on the specific CPU with preemption disabled.
    192      */
    193     rc = RTMpOnSpecific(idCpu, rtMpNotificationLinuxOnCurrentCpu, pNotifierBlock, &ulNativeEvent);
    194     Assert(RT_SUCCESS(rc)); NOREF(rc);
     144    switch (ulNativeEvent)
     145    {
     146# ifdef CPU_DOWN_FAILED
     147        case CPU_DOWN_FAILED:
     148#  if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_FAILED_FROZEN)
     149        case CPU_DOWN_FAILED_FROZEN:
     150#  endif
     151# endif
     152        case CPU_ONLINE:
     153# if defined(CPU_TASKS_FROZEN) && defined(CPU_ONLINE_FROZEN)
     154        case CPU_ONLINE_FROZEN:
     155# endif
     156            rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE, idCpu);
     157            break;
     158
     159# ifdef CPU_DOWN_PREPARE
     160        case CPU_DOWN_PREPARE:
     161#  if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_PREPARE_FROZEN)
     162        case CPU_DOWN_PREPARE_FROZEN:
     163#  endif
     164            rtMpNotificationDoCallbacks(RTMPEVENT_OFFLINE, idCpu);
     165            break;
     166# endif
     167    }
     168
    195169    return NOTIFY_DONE;
    196170}
  • trunk/src/VBox/Runtime/r0drv/solaris/mpnotification-r0drv-solaris.c

    r54294 r54395  
    55
    66/*
    7  * Copyright (C) 2008-2012 Oracle Corporation
     7 * Copyright (C) 2008-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    6464
    6565/**
    66  * PFNRTMPWORKER worker for executing Mp events on the target CPU.
    67  *
    68  * @param    idCpu          The current CPU Id.
    69  * @param    pvArg          Opaque pointer to event type (online/offline).
    70  * @param    pvIgnored1     Ignored.
    71  */
    72 static void rtMpNotificationSolOnCurrentCpu(RTCPUID idCpu, void *pvArg, void *pvIgnored1)
    73 {
    74     NOREF(pvIgnored1);
    75     NOREF(idCpu);
    76 
    77     PRTMPARGS pArgs = (PRTMPARGS)pvArg;
    78     AssertRelease(pArgs && pArgs->idCpu == RTMpCpuId());
    79     Assert(pArgs->pvUser1);
    80     Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    81 
    82     RTMPEVENT enmMpEvent = *(RTMPEVENT *)pArgs->pvUser1;
    83     rtMpNotificationDoCallbacks(enmMpEvent, pArgs->idCpu);
    84 }
    85 
    86 
    87 /**
    8866 * Solaris callback function for Mp event notification.
    8967 *
     68 * @returns Solaris error code.
    9069 * @param    CpuState   The current event/state of the CPU.
    91  * @param    iCpu       Which CPU is this event fore.
     70 * @param    iCpu       Which CPU is this event for.
    9271 * @param    pvArg      Ignored.
    9372 *
    9473 * @remarks This function assumes index == RTCPUID.
    95  * @returns Solaris error code.
     74 *          We may -not- be firing on the CPU going online/offline and called
     75 *          with preemption enabled.
    9676 */
    9777static int rtMpNotificationCpuEvent(cpu_setup_t CpuState, int iCpu, void *pvArg)
    9878{
    9979    RTMPEVENT enmMpEvent;
    100 
    101     RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
    102     RTThreadPreemptDisable(&PreemptState);
    10380
    10481    /*
     
    11996        return 0;
    12097
    121     /*
    122      * Since we don't absolutely need to do CPU bound code in any of the CPU offline
    123      * notification hooks, run it on the current CPU. Scheduling a callback to execute
    124      * on the CPU going offline at this point is too late and will not work reliably.
    125      */
    126     bool fRunningOnTargetCpu = iCpu == RTMpCpuId();
    127     if (   fRunningOnTargetCpu == true
    128         || enmMpEvent == RTMPEVENT_OFFLINE)
    129     {
    130         rtMpNotificationDoCallbacks(enmMpEvent, iCpu);
    131     }
    132     else
    133     {
    134         /** @todo We should probably be using thread_affinity_set() here, see
    135          *        cpu_online() code. */
    136         /*
    137          * We're not on the target CPU, schedule (synchronous) the event notification callback
    138          * to run on the target CPU i.e. the CPU that was online'd.
    139          */
    140         RTMPARGS Args;
    141         RT_ZERO(Args);
    142         Args.pvUser1 = &enmMpEvent;
    143         Args.pvUser2 = NULL;
    144         Args.idCpu   = iCpu;
    145         RTMpOnSpecific(iCpu, rtMpNotificationSolOnCurrentCpu, &Args, NULL /* pvIgnored1 */);
    146     }
    147 
    148     RTThreadPreemptRestore(&PreemptState);
    149 
     98    rtMpNotificationDoCallbacks(enmMpEvent, iCpu);
    15099    NOREF(pvArg);
    151100    return 0;
  • trunk/src/VBox/VMM/VMMR0/HMR0.cpp

    r54332 r54395  
    994994 *
    995995 * @returns VBox status code.
    996  * @param   idCpu       The identifier for the CPU the function is called on.
     996 * @param   idCpu       The identifier for the CPU this function is called on.
    997997 *
    998998 * @remarks Must be called with preemption disabled.
     
    10071007    Assert(idCpu < RT_ELEMENTS(g_HvmR0.aCpuInfo));
    10081008    Assert(!pCpu->fConfigured || pCpu->hMemObj != NIL_RTR0MEMOBJ);
     1009    AssertRelease(idCpu == RTMpCpuId());
    10091010
    10101011    if (pCpu->hMemObj == NIL_RTR0MEMOBJ)
     
    10121013
    10131014    int rc;
    1014     if (   pCpu->fConfigured
    1015         && idCpu == RTMpCpuId())    /* We may not be firing on the CPU being disabled/going offline. */
     1015    if (pCpu->fConfigured)
    10161016    {
    10171017        void    *pvCpuPage     = RTR0MemObjAddress(pCpu->hMemObj);
     
    10431043    AssertReturnVoid(g_HvmR0.fGlobalInit);
    10441044    hmR0FirstRcSetStatus(pFirstRc, hmR0DisableCpu(idCpu));
     1045}
     1046
     1047
     1048/**
     1049 * Worker function passed to RTMpOnSpecific() that is to be called on the target
     1050 * CPU.
     1051 *
     1052 * @param   idCpu       The identifier for the CPU the function is called on.
     1053 * @param   pvUser1     Null, not used.
     1054 * @param   pvUser2     Null, not used.
     1055 */
     1056static DECLCALLBACK(void) hmR0DisableCpuOnSpecificCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
     1057{
     1058    NOREF(pvUser1);
     1059    NOREF(pvUser2);
     1060    hmR0DisableCpu(idCpu);
    10451061}
    10461062
     
    10611077     * CPU comes online, the initialization is done lazily in HMR0Enter().
    10621078     */
    1063     Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    10641079    switch (enmEvent)
    10651080    {
    10661081        case RTMPEVENT_OFFLINE:
    10671082        {
    1068             int rc = hmR0DisableCpu(idCpu);
    1069             AssertRC(rc);
     1083            RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
     1084            RTThreadPreemptDisable(&PreemptState);
     1085            if (idCpu == RTMpCpuId())
     1086            {
     1087                int rc = hmR0DisableCpu(idCpu);
     1088                AssertRC(rc);
     1089                RTThreadPreemptRestore(&PreemptState);
     1090            }
     1091            else
     1092            {
     1093                RTThreadPreemptRestore(&PreemptState);
     1094                RTMpOnSpecific(idCpu, hmR0DisableCpuOnSpecificCallback, NULL /* pvUser1 */, NULL /* pvUser2 */);
     1095            }
    10701096            break;
    10711097        }
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