VirtualBox

Changeset 54315 in vbox for trunk/src/VBox/HostDrivers


Ignore:
Timestamp:
Feb 19, 2015 9:33:21 PM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
98390
Message:

SUPDrv: Eliminated the need for the GIP master to have a zero TSC delta value. Fixed incorrect RTCPUSET indexing (don't use idCpu!). Documented the tsc delta thred states. Made it transition from terminating to destroyed. Renamed supdrvMeasureTscDeltas to supdrvMeasureInitialTscDeltas and dropped the unused pidxMaster parameter.

Location:
trunk/src/VBox/HostDrivers/Support
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/SUPDrv.c

    r54313 r54315  
    179179                                                  RTCPUID idCpu, uint8_t idApic, uint64_t iTick);
    180180static void                 supdrvGipInitCpu(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS);
    181 static int                  supdrvMeasureTscDeltas(PSUPDRVDEVEXT pDevExt, uint32_t *pidxMaster);
     181static int                  supdrvMeasureInitialTscDeltas(PSUPDRVDEVEXT pDevExt);
    182182static int                  supdrvMeasureTscDeltaOne(PSUPDRVDEVEXT pDevExt, uint32_t idxWorker);
    183183static int                  supdrvIOCtl_ResumeSuspendedKbds(void);
     
    60516051            {
    60526052                pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Measuring;
    6053                 rc = RTSemEventSignal(pDevExt->hTscDeltaEvent);
     6053                rc = RTSemEventSignal(pDevExt->hTscDeltaEvent); /* (Safe on windows as long as spinlock isn't IRQ safe.) */
    60546054                if (RT_FAILURE(rc))
    60556055                    return supdrvTscDeltaThreadButchered(pDevExt, true /* fSpinlockHeld */, "RTSemEventSignal", rc);
     
    60706070                    do
    60716071                    {
    6072                         rc = supdrvMeasureTscDeltas(pDevExt, NULL /* pidxMaster */);
     6072                        rc = supdrvMeasureInitialTscDeltas(pDevExt);
    60736073                        if (   RT_SUCCESS(rc)
    60746074                            || (   RT_FAILURE(rc)
     
    60926092                        PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[iCpu];
    60936093                        if (   pGipCpuWorker->i64TSCDelta == INT64_MAX
    6094                             && RTCpuSetIsMember(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->idCpu))
     6094                            && RTCpuSetIsMember(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet))
    60956095                        {
    60966096                            rc |= supdrvMeasureTscDeltaOne(pDevExt, iCpu);
     
    61086108
    61096109            case kTscDeltaThreadState_Terminating:
     6110                pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Destroyed;
    61106111                RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
    61116112                return VINF_SUCCESS;
     
    61256126 *
    61266127 * @returns VINF_SUCCESS on success, VERR_TIMEOUT if it doesn't respond in time,
    6127  *        other error code on internal error.
     6128 *          other error code on internal error.
    61286129 *
    61296130 * @param   pThis           Pointer to the grant service instance data.
     
    67696770                    do
    67706771                    {
    6771                         rc = supdrvMeasureTscDeltas(pDevExt, NULL /* pidxMaster */);
     6772                        rc = supdrvMeasureInitialTscDeltas(pDevExt);
    67726773                        if (   rc != VERR_TRY_AGAIN
    67736774                            && rc != VERR_CPU_OFFLINE)
     
    68266827                }
    68276828                else
    6828                     OSDBGPRINT(("supdrvGipCreate: supdrvMeasureTscDeltas failed. rc=%Rrc\n", rc));
     6829                    OSDBGPRINT(("supdrvGipCreate: supdrvMeasureInitialTscDeltas failed. rc=%Rrc\n", rc));
    68296830            }
    68306831            else
     
    70027003 * @param   idCpu               The CPU ID.
    70037004 */
    7004 static uint32_t supdrvGipCpuIndexFromCpuId(PSUPGLOBALINFOPAGE pGip, RTCPUID idCpu)
     7005static uint32_t supdrvGipFindOrAllocCpuIndexForCpuId(PSUPGLOBALINFOPAGE pGip, RTCPUID idCpu)
    70057006{
    70067007    uint32_t i, cTries;
     
    70307031
    70317032/**
     7033 * Finds the GIP CPU index corresponding to @a idCpu.
     7034 *
     7035 * @returns GIP CPU array index, UINT32_MAX if not found.
     7036 * @param   pGip                The GIP.
     7037 * @param   idCpu               The CPU ID.
     7038 */
     7039static uint32_t supdrvGipFindCpuIndexForCpuId(PSUPGLOBALINFOPAGE pGip, RTCPUID idCpu)
     7040{
     7041    uint32_t i;
     7042    for (i = 0; i < pGip->cCpus; i++)
     7043        if (pGip->aCPUs[i].idCpu == idCpu)
     7044            return i;
     7045    return UINT32_MAX;
     7046}
     7047
     7048
     7049/**
    70327050 * The calling CPU should be accounted as online, update GIP accordingly.
    70337051 *
    7034  * This is used by supdrvGipMpEvent as well as the supdrvGipCreate.
     7052 * This is used by supdrvGipCreate() as well as supdrvGipMpEvent().
    70357053 *
    70367054 * @param   pDevExt             The device extension.
     
    70727090     */
    70737091    u64NanoTS = RTTimeSystemNanoTS() - pGip->u32UpdateIntervalNS;
    7074     i = supdrvGipCpuIndexFromCpuId(pGip, idCpu);
     7092    i = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu);
    70757093    supdrvGipInitCpu(pDevExt, pGip, &pGip->aCPUs[i], u64NanoTS);
    70767094    idApic = ASMGetApicId();
     
    70917109    if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
    70927110    {
    7093         RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, idCpu);
     7111        RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, iCpuSet);
    70947112#ifdef SUPDRV_USE_TSC_DELTA_THREAD
    70957113        RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
     
    71537171        ASMAtomicWriteS64(&pGip->aCPUs[i].i64TSCDelta, INT64_MAX);
    71547172        /* Remove this CPU from the set of CPUs that we have obtained the TSC deltas. */
    7155         RTCpuSetDel(&pDevExt->TscDeltaObtainedCpuSet, idCpu);
     7173        RTCpuSetDel(&pDevExt->TscDeltaObtainedCpuSet, iCpuSet);
    71567174    }
    71577175
     
    72107228        {
    72117229            /*
    7212              * Find a new GIP master.
     7230             * The GIP master is going offline, find a new one.
    72137231             */
    72147232            bool        fIgnored;
    72157233            unsigned    i;
    7216             int64_t     iTSCDelta;
    7217             uint32_t    idxNewGipMaster;
    72187234            RTCPUID     idNewGipMaster = NIL_RTCPUID;
    72197235            RTCPUSET    OnlineCpus;
     
    72347250            ASMAtomicCmpXchgSize(&pDevExt->idGipMaster, idNewGipMaster, idGipMaster, fIgnored);
    72357251            NOREF(fIgnored);
    7236 
    7237             /*
    7238              * Adjust all the TSC deltas against the new GIP master.
    7239              */
    7240             /** @todo this needs fixing, we cannot dynamically re-adjust the base unless
    7241              *        GIP isn't mapped and no other consumers of TSC-deltas. Basically,
    7242              *        we need to adjust the master's own TSC-delta (can be non-zero)
    7243              *        while computing the deltas. */
    7244             if (pGip)
    7245             {
    7246                 idxNewGipMaster = supdrvGipCpuIndexFromCpuId(pGip, idNewGipMaster);
    7247                 iTSCDelta       = pGip->aCPUs[idxNewGipMaster].i64TSCDelta;
    7248                 Assert(iTSCDelta != INT64_MAX);
    7249                 for (i = 0; i < pGip->cCpus; i++)
    7250                 {
    7251                     PSUPGIPCPU pGipCpu      = &pGip->aCPUs[i];
    7252                     int64_t    iWorkerDelta = pGipCpu->i64TSCDelta;
    7253                     if (iWorkerDelta != INT64_MAX)
    7254                         iWorkerDelta -= iTSCDelta;
    7255                     ASMAtomicWriteS64(&pGipCpu->i64TSCDelta, iWorkerDelta);
    7256                 }
    7257                 Assert(pGip->aCPUs[idxNewGipMaster].i64TSCDelta == 0);
    7258             }
    7259         }
    7260     }
    7261 }
    7262 
    7263 
    7264 /**
    7265  * Callback used by supdrvMeasureTscDeltas() to read the TSC on two CPUs and
    7266  * compute the delta between them.
     7252        }
     7253    }
     7254}
     7255
     7256
     7257/**
     7258 * Callback used by supdrvMeasureInitialTscDeltas() to read the TSC on two CPUs
     7259 * and compute the delta between them.
    72677260 *
    72687261 * @param   idCpu       The CPU we are current scheduled on.
    72697262 * @param   pvUser1     Opaque pointer to the device instance data.
    7270  * @param   pvUser2     Opaque pointer to the worker Cpu Id.
     7263 * @param   pvUser2     Pointer to the SUPGIPCPU entry of the worker CPU.
    72717264 *
    72727265 * @remarks Measuring TSC deltas between the CPUs is tricky because we need to
     
    72977290static DECLCALLBACK(void) supdrvMeasureTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
    72987291{
    7299     PSUPDRVDEVEXT      pDevExt   = (PSUPDRVDEVEXT)pvUser1;
    7300     PSUPGLOBALINFOPAGE pGip      = pDevExt->pGip;
    7301     uint32_t          *pidWorker = (uint32_t *)pvUser2;
    7302     RTCPUID            idMaster  = ASMAtomicUoReadU32(&pDevExt->idTscDeltaInitiator);
    7303     unsigned           idxMaster = supdrvGipCpuIndexFromCpuId(pGip, idMaster);
    7304     unsigned           idxWorker = supdrvGipCpuIndexFromCpuId(pGip, *pidWorker);
    7305     PSUPGIPCPU         pGipCpuMaster = &pGip->aCPUs[idxMaster];
    7306     PSUPGIPCPU         pGipCpuWorker = &pGip->aCPUs[idxWorker];
    7307     int                cTriesLeft = 12;
     7292    PSUPDRVDEVEXT      pDevExt          = (PSUPDRVDEVEXT)pvUser1;
     7293    PSUPGLOBALINFOPAGE pGip             = pDevExt->pGip;
     7294    PSUPGIPCPU         pGipCpuWorker    = (PSUPGIPCPU)pvUser2;
     7295    uint32_t           idWorker         = pGipCpuWorker->idCpu;
     7296    RTCPUID            idMaster         = ASMAtomicUoReadU32(&pDevExt->idTscDeltaInitiator);
     7297    unsigned           idxMaster        = supdrvGipFindCpuIndexForCpuId(pGip, idMaster);
     7298    PSUPGIPCPU         pGipCpuMaster    = &pGip->aCPUs[idxMaster];
     7299    int                cTriesLeft;
    73087300
    73097301    if (   idCpu != idMaster
    7310         && idCpu != *pidWorker)
     7302        && idCpu != idWorker)
    73117303        return;
    73127304
     
    73597351    }
    73607352
     7353    /*
     7354     * ...
     7355     */
    73617356    Assert(pGipCpuWorker->i64TSCDelta == INT64_MAX);
     7357    cTriesLeft = 12;
    73627358    while (cTriesLeft-- > 0)
    73637359    {
     
    73977393                    if (pGipCpuWorker->u64TSCSample != GIP_TSC_DELTA_RSVD)
    73987394                    {
    7399                         int64_t iDelta = pGipCpuWorker->u64TSCSample - pGipCpuMaster->u64TSCSample;
     7395                        int64_t iDelta = pGipCpuWorker->u64TSCSample
     7396                                       - (pGipCpuMaster->u64TSCSample - pGipCpuMaster->i64TSCDelta);
     7397                        /** @todo r=bird: Why isn't this code using absolute values? Guess it mostly works fine because
     7398                         * the detection code is biased thowards positive deltas (see tstSupTscDelta.cpp output) ... */
    74007399                        if (iDelta < pGipCpuWorker->i64TSCDelta)
    74017400                            pGipCpuWorker->i64TSCDelta = iDelta;
     
    74647463            if (idCpu == idMaster)
    74657464            {
    7466                 RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuMaster->idCpu);
    7467                 RTCpuSetAdd(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuMaster->idCpu);
     7465                RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuMaster->iCpuSet);
     7466                RTCpuSetAdd(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuMaster->iCpuSet);
    74687467            }
    74697468            else
    74707469            {
    7471                 RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->idCpu);
    7472                 RTCpuSetAdd(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->idCpu);
     7470                RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
     7471                RTCpuSetAdd(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet);
    74737472            }
    74747473            break;
     
    75297528    Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED);
    75307529
     7530    /*
     7531     * Don't attempt measuring the delta for the GIP master.
     7532     */
    75317533    if (pGipCpuWorker->idCpu == idMaster)
    75327534    {
    7533         ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, 0);
     7535        if (pGipCpuWorker->i64TSCDelta == INT64_MAX) /* This shouldn't happen, but just in case. */
     7536            ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, 0);
    75347537        return VINF_SUCCESS;
    75357538    }
     
    75507553        ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, INT64_MAX);
    75517554        ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP);
    7552         rc = RTMpOnAll(supdrvMeasureTscDeltaCallback, pDevExt, &pGipCpuWorker->idCpu);
     7555        rc = RTMpOnAll(supdrvMeasureTscDeltaCallback, pDevExt, pGipCpuWorker);
    75537556        if (RT_SUCCESS(rc))
    75547557        {
     
    75877590
    75887591/**
    7589  * Measures the TSC deltas between CPUs.
    7590  *
     7592 * Performs the initial measurements of the TSC deltas between CPUs.
     7593 *
     7594 * This is called by supdrvGipCreate or triggered by it if threaded.
     7595 *
     7596 * @returns VBox status code.
    75917597 * @param   pDevExt     Pointer to the device instance data.
    7592  * @param   pidxMaster  Where to store the index of the chosen master TSC if we
    7593  *                      managed to determine the TSC deltas successfully.
    7594  *                      Optional, can be NULL.
    7595  *
    7596  * @returns VBox status code.
     7598 *
    75977599 * @remarks Must be called only after supdrvGipInitOnCpu() as this function uses
    75987600 *          idCpu, GIP's online CPU set which are populated in
    75997601 *          supdrvGipInitOnCpu().
    76007602 */
    7601 static int supdrvMeasureTscDeltas(PSUPDRVDEVEXT pDevExt, uint32_t *pidxMaster)
     7603static int supdrvMeasureInitialTscDeltas(PSUPDRVDEVEXT pDevExt)
    76027604{
    76037605    PSUPGIPCPU pGipCpuMaster;
     
    76077609    int        rc             = VINF_SUCCESS;
    76087610    uint32_t   cMpOnOffEvents = ASMAtomicReadU32(&pDevExt->cMpOnOffEvents);
    7609     uint32_t   cOnlineCpus    = pGip->cOnlineCpus;
    76107611
    76117612    Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED);
     
    76387639    ASMAtomicWriteSize(&pDevExt->idGipMaster, pGipCpuMaster->idCpu);
    76397640
    7640     AssertReturn(cOnlineCpus > 0, VERR_INTERNAL_ERROR_5);
     7641    /*
     7642     * If there is only a single CPU online we have nothing to do.
     7643     */
    76417644    if (pGip->cOnlineCpus <= 1)
    76427645    {
    7643         if (pidxMaster)
    7644             *pidxMaster = idxMaster;
     7646        AssertReturn(pGip->cOnlineCpus > 0, VERR_INTERNAL_ERROR_5);
    76457647        return VINF_SUCCESS;
    76467648    }
    76477649
     7650    /*
     7651     * Loop thru the GIP CPU array and get deltas for each CPU (except the master).
     7652     */
    76487653    for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
    76497654    {
    76507655        PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[iCpu];
    76517656        if (   iCpu != idxMaster
    7652             && RTCpuSetIsMember(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->idCpu))
     7657            && RTCpuSetIsMember(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet))
    76537658        {
    76547659            rc = supdrvMeasureTscDeltaOne(pDevExt, iCpu);
     
    76697674    }
    76707675
    7671     if (   RT_SUCCESS(rc)
    7672         && !pGipCpuMaster->i64TSCDelta
    7673         && pidxMaster)
    7674     {
    7675         *pidxMaster = idxMaster;
    7676     }
    76777676    return rc;
    76787677}
     
    82678266    if (RT_UNLIKELY(iTick == 1))
    82688267    {
    8269         iCpu = supdrvGipCpuIndexFromCpuId(pGip, idCpu);
     8268        iCpu = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu);
    82708269        if (pGip->aCPUs[iCpu].enmState == SUPGIPCPUSTATE_OFFLINE)
    82718270            supdrvGipMpEventOnline(pDevExt, idCpu);
     
    83758374                 *        thread. Check if anyone uses/needs fAsync before implementing this. */
    83768375                RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
    8377                 RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->idCpu);
     8376                RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
    83788377                if (   pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening
    83798378                    || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring)
  • trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h

    r54306 r54315  
    251251    /** Uninitialized/invalid value. */
    252252    kTscDeltaThreadState_Invalid = 0,
    253     /** The thread is being created. */
     253    /** The thread is being created.
     254     * Next state: Listening, Butchered, Terminating  */
    254255    kTscDeltaThreadState_Creating,
    255     /** The thread is listening for events. */
     256    /** The thread is listening for events.
     257     * Previous state: Creating, Measuring
     258     * Next state: WaitAndMeasure, Butchered, Terminated */
    256259    kTscDeltaThreadState_Listening,
    257     /** The thread is sleeping before starting a measurement. */
     260    /** The thread is sleeping before starting a measurement.
     261     * Previous state: Listening, Measuring
     262     * Next state:     Measuring, Butchered, Terminating
     263     * @remarks The thread won't enter this state on its own, it is put into this
     264     *          state by the GIP timer, the CPU online callback and by the
     265     *          SUP_IOCTL_TSC_DELTA_MEASURE code. */
    258266    kTscDeltaThreadState_WaitAndMeasure,
    259     /** The thread is currently servicing a measurement request. */
     267    /** The thread is currently servicing a measurement request.
     268     * Previous state: WaitAndMeasure
     269     * Next state:     Listening, WaitAndMeasure, Terminate */
    260270    kTscDeltaThreadState_Measuring,
    261     /** The thread is terminating. */
     271    /** The thread is terminating.
     272     * @remarks The thread won't enter this state on its own, is put into this state
     273     *          by supdrvTscDeltaTerm. */
    262274    kTscDeltaThreadState_Terminating,
    263     /** The thread is butchered due to an unexpected error. */
     275    /** The thread is butchered due to an unexpected error.
     276     * Previous State: Creating, Listening, WaitAndMeasure  */
    264277    kTscDeltaThreadState_Butchered,
    265     /** The thread is destroyed. */
     278    /** The thread is destroyed (final).
     279     * Previous state: Terminating */
    266280    kTscDeltaThreadState_Destroyed,
    267281    /** The usual 32-bit blowup hack. */
    268282    kTscDeltaThreadState_32BitHack = 0x7fffffff
    269 } SUPDRVTSCDELTATHREADSTATE, *PSUPDRVTSCDELTATHREADSTATE;
    270 #endif
     283} SUPDRVTSCDELTATHREADSTATE;
     284#endif /* SUPDRV_USE_TSC_DELTA_THREAD */
    271285
    272286/**
     
    650664    uint32_t                        u32SystemTimerGranularityGrant;
    651665    /** The CPU id of the GIP master.
    652      * This CPU is responsible for the updating the common GIP data. */
     666     * This CPU is responsible for the updating the common GIP data and it is
     667     * the one used to calculate TSC deltas relative to.
     668     * (The initial master will have a 0 zero value, but it it goes offline the
     669     * new master may have a non-zero value.) */
    653670    RTCPUID volatile                idGipMaster;
    654671
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette