Changeset 54357 in vbox
- Timestamp:
- Feb 22, 2015 7:14:39 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPDrvGip.cpp
r54355 r54357 2550 2550 uint64_t au64CacheLinePaddingBefore[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)]; 2551 2551 /** The synchronization variable, holds values GIP_TSC_DELTA_SYNC_*. */ 2552 volatile uint32_t u Var1;2552 volatile uint32_t uSyncVar; 2553 2553 /** Unused. */ 2554 volatile uint32_t uVar2; 2555 2556 /** Start RDTSC value. This does not need to be in its own cache line, it's 2557 * just put here to save stack space. */ 2554 volatile uint32_t u32Padding; 2555 2556 /** Padding to make sure the uVar1 is in its own cache line. */ 2557 uint64_t au64CacheLinePaddingAfter[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t) - 1]; 2558 2559 /** Start RDTSC value. Put here mainly to save stack space. */ 2558 2560 uint64_t uTscStart; 2559 /** Max number of ticks we can allow to elapse in the RTMpOn callback.2560 * This is estimated from the CPU frequency... */2561 uint64_t cMaxTicks;2562 2563 /** Padding to make sure the uVar1 is in its own cache line. */2564 uint64_t au64CacheLinePaddingAfter[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t) - 2];2565 2561 } SUPTSCDELTASYNC2; 2566 2562 AssertCompileSize(SUPTSCDELTASYNC2, GIP_TSC_DELTA_CACHE_LINE_SIZE * 2 + sizeof(uint64_t)); … … 2575 2571 { 2576 2572 /** The device extension. */ 2577 PSUPDRVDEVEXT pDevExt;2573 PSUPDRVDEVEXT pDevExt; 2578 2574 /** Pointer to the GIP CPU array entry for the worker. */ 2579 PSUPGIPCPU pWorker;2575 PSUPGIPCPU pWorker; 2580 2576 /** Pointer to the GIP CPU array entry for the master. */ 2581 PSUPGIPCPU pMaster;2577 PSUPGIPCPU pMaster; 2582 2578 /** Pointer to the master's synchronization struct (on stack). */ 2583 PSUPTSCDELTASYNC2 2579 PSUPTSCDELTASYNC2 volatile pSyncMaster; 2584 2580 /** Pointer to the worker's synchronization struct (on stack). */ 2585 PSUPTSCDELTASYNC2 pSyncWorker; 2581 PSUPTSCDELTASYNC2 volatile pSyncWorker; 2582 /** The maximum number of ticks to spend in supdrvMeasureTscDeltaCallback. 2583 * (This is what we need a rough TSC frequency for.) */ 2584 uint64_t cMaxTscTicks; 2585 /** Used to abort synchronization setup. */ 2586 bool volatile fAbortSetup; 2586 2587 2587 2588 #if 0 … … 2611 2612 * @{ 2612 2613 */ 2613 #define TSCDELTA_MASTER_SYNC_BEFORE(a_p TscDeltaSync) \2614 #define TSCDELTA_MASTER_SYNC_BEFORE(a_pSync1, a_pMySync, a_pOtherSync) \ 2614 2615 do {\ 2615 ASMAtomicWriteU32(&(a_p TscDeltaSync)->u, GIP_TSC_DELTA_SYNC_START); \2616 ASMAtomicWriteU32(&(a_pSync1)->u, GIP_TSC_DELTA_SYNC_START); \ 2616 2617 \ 2617 2618 /* Disable interrupts only in the master for as short a period \ … … 2619 2620 uFlags = ASMIntDisableFlags(); \ 2620 2621 \ 2621 while (ASMAtomicReadU32(&(a_p TscDeltaSync)->u) == GIP_TSC_DELTA_SYNC_START) \2622 while (ASMAtomicReadU32(&(a_pSync1)->u) == GIP_TSC_DELTA_SYNC_START) \ 2622 2623 { /* nothing */ } \ 2623 2624 } while (0) 2624 #define TSCDELTA_MASTER_SYNC_AFTER(a_p TscDeltaSync) \2625 #define TSCDELTA_MASTER_SYNC_AFTER(a_pSync1, a_pMySync, a_pOtherSync) \ 2625 2626 do {\ 2626 2627 /* Sync up with worker. */ \ 2627 2628 ASMSetFlags(uFlags); \ 2628 2629 \ 2629 while (ASMAtomicReadU32(&(a_p TscDeltaSync)->u) != GIP_TSC_DELTA_SYNC_WORKER_DONE) \2630 while (ASMAtomicReadU32(&(a_pSync1)->u) != GIP_TSC_DELTA_SYNC_WORKER_DONE) \ 2630 2631 { /* nothing */ } \ 2631 2632 } while (0) 2632 #define TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(a_p TscDeltaSync) \2633 #define TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(a_pSync1, a_pMySync, a_pOtherSync) \ 2633 2634 do {\ 2634 ASMAtomicWriteU32(&(a_p TscDeltaSync)->u, GIP_TSC_DELTA_SYNC_STOP); \2635 ASMAtomicWriteU32(&(a_pSync1)->u, GIP_TSC_DELTA_SYNC_STOP); \ 2635 2636 } while (0) 2636 2637 2637 #define TSCDELTA_OTHER_SYNC_BEFORE(a_p TscDeltaSync, a_MidSyncExpr) \2638 #define TSCDELTA_OTHER_SYNC_BEFORE(a_pSync1, a_pMySync, a_pOtherSync, a_MidSyncExpr) \ 2638 2639 do { \ 2639 while (ASMAtomicReadU32(&(a_p TscDeltaSync)->u) != GIP_TSC_DELTA_SYNC_START) \2640 while (ASMAtomicReadU32(&(a_pSync1)->u) != GIP_TSC_DELTA_SYNC_START) \ 2640 2641 { /* nothing */ } \ 2641 2642 a_MidSyncExpr; \ 2642 ASMAtomicWriteU32(&(a_p TscDeltaSync)->u, GIP_TSC_DELTA_SYNC_WORKER_READY); \2643 ASMAtomicWriteU32(&(a_pSync1)->u, GIP_TSC_DELTA_SYNC_WORKER_READY); \ 2643 2644 } while (0) 2644 #define TSCDELTA_OTHER_SYNC_AFTER(a_p TscDeltaSync) \2645 #define TSCDELTA_OTHER_SYNC_AFTER(a_pSync1, a_pMySync, a_pOtherSync) \ 2645 2646 do { \ 2646 2647 /* Tell master we're done collecting our data. */ \ 2647 ASMAtomicWriteU32(&(a_p TscDeltaSync)->u, GIP_TSC_DELTA_SYNC_WORKER_DONE); \2648 ASMAtomicWriteU32(&(a_pSync1)->u, GIP_TSC_DELTA_SYNC_WORKER_DONE); \ 2648 2649 \ 2649 2650 /* Wait for the master to process the data. */ \ 2650 while (ASMAtomicReadU32(&(a_p TscDeltaSync)->u) == GIP_TSC_DELTA_SYNC_WORKER_DONE) \2651 while (ASMAtomicReadU32(&(a_pSync1)->u) == GIP_TSC_DELTA_SYNC_WORKER_DONE) \ 2651 2652 ASMNopPause(); \ 2652 2653 } while (0) … … 2682 2683 * 2683 2684 * @param pArgs The argument/state data. 2684 * @param pSync 2685 * @param pSync1 The synchronization structure 2685 2686 * (pDevExt->pTscDeltaSync). 2686 2687 * @param fIsMaster Set if master, clear if worker. 2687 2688 * @param iTry The attempt number. 2688 2689 */ 2689 static void supdrvTscDeltaMethod1Loop(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC pSync, bool fIsMaster, uint32_t iTry) 2690 static void supdrvTscDeltaMethod1Loop(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC pSync1, 2691 PSUPTSCDELTASYNC2 pMySync, PSUPTSCDELTASYNC2 pOtherSync, bool fIsMaster, uint32_t iTry) 2690 2692 { 2691 2693 PSUPGIPCPU pGipCpuWorker = pArgs->pWorker; … … 2706 2708 ("%#llx idMaster=%#x idWorker=%#x (idGipMaster=%#x)\n", 2707 2709 pGipCpuMaster->u64TSCSample, pGipCpuMaster->idCpu, pGipCpuWorker->idCpu, pArgs->pDevExt->idGipMaster)); 2708 TSCDELTA_MASTER_SYNC_BEFORE(pSync );2710 TSCDELTA_MASTER_SYNC_BEFORE(pSync1, pMySync, pOtherSync); 2709 2711 2710 2712 do … … 2714 2716 } while (pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD); 2715 2717 2716 TSCDELTA_MASTER_SYNC_AFTER(pSync );2718 TSCDELTA_MASTER_SYNC_AFTER(pSync1, pMySync, pOtherSync); 2717 2719 2718 2720 /* Process the data. */ … … 2732 2734 /* Reset our TSC sample and tell the worker to move on. */ 2733 2735 ASMAtomicWriteU64(&pGipCpuMaster->u64TSCSample, GIP_TSC_DELTA_RSVD); 2734 TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(pSync );2736 TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(pSync1, pMySync, pOtherSync); 2735 2737 } 2736 2738 else … … 2744 2746 2745 2747 ASMAtomicReadU64(&pGipCpuMaster->u64TSCSample); /* Warm the cache line. */ 2746 TSCDELTA_OTHER_SYNC_BEFORE(pSync , Assert(pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD));2748 TSCDELTA_OTHER_SYNC_BEFORE(pSync1, pMySync, pOtherSync, Assert(pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD)); 2747 2749 2748 2750 /* … … 2779 2781 } 2780 2782 2781 TSCDELTA_OTHER_SYNC_AFTER(pSync );2783 TSCDELTA_OTHER_SYNC_AFTER(pSync1, pMySync, pOtherSync); 2782 2784 } 2783 2785 } … … 2948 2950 * 2949 2951 * @param pArgs The argument/state data. 2950 * @param pSync The synchronization structure2952 * @param pSync1 The synchronization structure 2951 2953 * (pDevExt->pTscDeltaSync). 2952 2954 * @param fIsMaster Set if master, clear if worker. 2953 2955 * @param iTry The attempt number. 2954 2956 */ 2955 static void supdrvTscDeltaMethod2Loop(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC pSync, bool fIsMaster, uint32_t iTry) 2957 static void supdrvTscDeltaMethod2Loop(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC pSync1, 2958 PSUPTSCDELTASYNC2 pMySync, PSUPTSCDELTASYNC2 pOtherSync, bool fIsMaster, uint32_t iTry) 2956 2959 { 2957 2960 unsigned iLoop; … … 3000 3003 * Sync up with the worker and collect data. 3001 3004 */ 3002 TSCDELTA_MASTER_SYNC_BEFORE(pSync );3005 TSCDELTA_MASTER_SYNC_BEFORE(pSync1, pMySync, pOtherSync); 3003 3006 supdrvTscDeltaMethod2CollectData(pArgs->M2.pMasterData, &pArgs->M2.pWorkerData->iCurSeqNo, pArgs->M2.fLagMaster); 3004 TSCDELTA_MASTER_SYNC_AFTER(pSync );3007 TSCDELTA_MASTER_SYNC_AFTER(pSync1, pMySync, pOtherSync); 3005 3008 3006 3009 /* … … 3012 3015 supdrvTscDeltaMethod2ProcessDataOnMaster(pArgs, iLoop); 3013 3016 3014 TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(pSync );3017 TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(pSync1, pMySync, pOtherSync); 3015 3018 } 3016 3019 else … … 3019 3022 * The worker. 3020 3023 */ 3021 TSCDELTA_OTHER_SYNC_BEFORE(pSync , (void)0);3024 TSCDELTA_OTHER_SYNC_BEFORE(pSync1, pMySync, pOtherSync, (void)0); 3022 3025 supdrvTscDeltaMethod2CollectData(pArgs->M2.pWorkerData, &pArgs->M2.pMasterData->iCurSeqNo, pArgs->M2.fLagWorker); 3023 TSCDELTA_OTHER_SYNC_AFTER(pSync );3026 TSCDELTA_OTHER_SYNC_AFTER(pSync1, pMySync, pOtherSync); 3024 3027 } 3025 3028 … … 3068 3071 3069 3072 /** Prestart wait. */ 3070 #define GIP_TSC_DELTA_SYNC2_PRESTART_WAIT UINT32_C(0xffe) 3071 3072 /** Start measurement of TSC delta. */ 3073 #define GIP_TSC_DELTA_SYNC2_START UINT32_C(1) 3074 /** Worker thread is ready for reading the TSC. */ 3075 #define GIP_TSC_DELTA_SYNC2_WORKER_READY UINT32_C(2) 3076 /** Worker thread is done updating TSC delta info. */ 3077 #define GIP_TSC_DELTA_SYNC2_WORKER_DONE UINT32_C(3) 3078 /** When IPRT is isn't concurrent safe: Master is ready and will wait for worker 3079 * with a timeout. */ 3080 #define GIP_TSC_DELTA_SYNC2_PRESTART_MASTER UINT32_C(4) 3081 3082 3083 /** 3084 * Callback used by supdrvMeasureInitialTscDeltas() to read the TSC on two CPUs 3073 #define GIP_TSC_DELTA_SYNC2_PRESTART_WAIT UINT32_C(0x0ffe) 3074 /** Prestart aborted. */ 3075 #define GIP_TSC_DELTA_SYNC2_PRESTART_ABORT UINT32_C(0x0fff) 3076 /** Start testing. */ 3077 #define GIP_TSC_DELTA_SYNC2_START UINT32_C(0x1000) 3078 3079 3080 /** The other party won't touch the sync struct ever again. */ 3081 #define GIP_TSC_DELTA_SYNC2_FINAL UINT32_C(0x1fff) 3082 3083 3084 3085 static int supdrvMeasureTscDeltaCallbackAbortSyncSetup(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC2 pMySync, 3086 bool fIsMaster, bool fTimeout) 3087 { 3088 PSUPTSCDELTASYNC2 volatile *ppMySync = fIsMaster ? &pArgs->pSyncMaster : &pArgs->pSyncWorker; 3089 PSUPTSCDELTASYNC2 volatile *ppOtherSync = fIsMaster ? &pArgs->pSyncWorker : &pArgs->pSyncMaster; 3090 #if defined(DEBUG_bird) && defined(RT_OS_WINDOWS) 3091 uint32_t iTry = 0; 3092 #endif 3093 3094 /* 3095 * Clear our sync pointer and make sure the abort flag is set. 3096 */ 3097 ASMAtomicWriteNullPtr(ppMySync); 3098 ASMAtomicWriteBool(&pArgs->fAbortSetup, true); 3099 3100 /* 3101 * Make sure the other party is out of there and won't be touching our 3102 * sync state again (would cause stack corruption). 3103 */ 3104 while (ASMAtomicReadPtrT(ppOtherSync, PSUPTSCDELTASYNC2) != NULL) 3105 { 3106 ASMNopPause(); 3107 ASMNopPause(); 3108 ASMNopPause(); 3109 #if defined(DEBUG_bird) && defined(RT_OS_WINDOWS) 3110 if (++iTry == 0) __debugbreak(); 3111 #endif 3112 } 3113 3114 return 0; 3115 } 3116 3117 3118 /** 3119 * This is used by supdrvMeasureInitialTscDeltas() to read the TSC on two CPUs 3085 3120 * and compute the delta between them. 3086 3121 * 3122 * To reduce code size a good when timeout handling was added, a dummy return 3123 * value had to be added (saves 1-3 lines per timeout case), thus this 3124 * 'Unwrapped' function and the dummy 0 return value. 3125 * 3126 * @returns 0 (dummy, ignored) 3087 3127 * @param idCpu The CPU we are current scheduled on. 3088 * @param pvUser1 Pointer to a parameter package (SUPDRVGIPTSCDELTARGS). 3089 * @param pvUser2 Unused. 3128 * @param pArgs Pointer to a parameter package. 3090 3129 * 3091 3130 * @remarks Measuring TSC deltas between the CPUs is tricky because we need to … … 3095 3134 * doing this on x86 CPUs. 3096 3135 */ 3097 static DECLCALLBACK(void) supdrvMeasureTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2) 3098 { 3099 PSUPDRVGIPTSCDELTARGS pArgs = (PSUPDRVGIPTSCDELTARGS)pvUser1; 3100 PSUPDRVDEVEXT pDevExt = pArgs->pDevExt; 3101 PSUPTSCDELTASYNC pSync = pDevExt->pTscDeltaSync; 3102 PSUPGIPCPU pGipCpuWorker = pArgs->pWorker; 3103 PSUPGIPCPU pGipCpuMaster = pArgs->pMaster; 3104 bool const fIsMaster = idCpu == pGipCpuMaster->idCpu; 3105 uint32_t iTry; 3106 #if 0 3107 PSUPTSCDELTASYNC2 pOtherSync; 3108 SUPTSCDELTASYNC2 MySync; 3109 #endif 3136 static int supdrvMeasureTscDeltaCallbackUnwrapped(RTCPUID idCpu, PSUPDRVGIPTSCDELTARGS pArgs) 3137 { 3138 PSUPDRVDEVEXT pDevExt = pArgs->pDevExt; 3139 PSUPTSCDELTASYNC pSync1 = pDevExt->pTscDeltaSync; 3140 PSUPGIPCPU pGipCpuWorker = pArgs->pWorker; 3141 PSUPGIPCPU pGipCpuMaster = pArgs->pMaster; 3142 bool const fIsMaster = idCpu == pGipCpuMaster->idCpu; 3143 uint32_t iTry; 3144 PSUPTSCDELTASYNC2 volatile *ppMySync = fIsMaster ? &pArgs->pSyncMaster : &pArgs->pSyncWorker; 3145 PSUPTSCDELTASYNC2 volatile *ppOtherSync = fIsMaster ? &pArgs->pSyncWorker : &pArgs->pSyncMaster; 3146 SUPTSCDELTASYNC2 MySync; 3147 PSUPTSCDELTASYNC2 pOtherSync; 3110 3148 3111 3149 /* A bit of paranoia first. */ 3112 3150 if (!pGipCpuMaster || !pGipCpuWorker) 3113 return ;3151 return 0; 3114 3152 3115 3153 /* … … 3118 3156 if ( !fIsMaster 3119 3157 && idCpu != pGipCpuWorker->idCpu) 3120 return; 3121 3122 #if 0 3158 return 0; 3159 3123 3160 /* 3124 3161 * Set up my synchronization stuff and wait for the other party to show up. 3125 * We don't wait forever since the other party may have gone fishing after 3126 * we checked it out in supdrvMeasureTscDeltaOne, and then there is of course 3127 * windows and it's BSOD if we waste too much time here. 3128 */ 3162 * 3163 * We don't wait forever since the other party may be off fishing (offline, 3164 * spinning with ints disables, whatever), we must play nice to the rest of 3165 * the system as this context generally isn't one in which we will get 3166 * preempted and we may hold up a number of lower priority interrupts. 3167 */ 3168 ASMAtomicWriteU32(&MySync.uSyncVar, GIP_TSC_DELTA_SYNC2_PRESTART_WAIT); 3169 ASMAtomicWritePtr(ppMySync, &MySync); 3170 MySync.uTscStart = ASMReadTSC(); 3171 3172 /* Look for the partner, might not be here yet... Special abort considerations. */ 3173 iTry = 0; 3174 while ((pOtherSync = ASMAtomicReadPtrT(ppOtherSync, PSUPTSCDELTASYNC2)) == NULL) 3175 { 3176 ASMNopPause(); 3177 if ( ASMAtomicReadBool(&pArgs->fAbortSetup) 3178 || !RTMpIsCpuOnline(fIsMaster ? pGipCpuWorker->idCpu : pGipCpuWorker->idCpu) ) 3179 return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/); 3180 if ( (iTry++ & 0xff) == 0 3181 && ASMReadTSC() - MySync.uTscStart > pArgs->cMaxTscTicks) 3182 return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, true /*fTimeout*/); 3183 #if defined(DEBUG_bird) && defined(RT_OS_WINDOWS) 3184 if (iTry == 0) __debugbreak(); 3185 #endif 3186 ASMNopPause(); 3187 } 3188 3189 /* I found my partner, waiting to be found... Special abort considerations. */ 3129 3190 if (fIsMaster) 3130 { 3131 MySync.uVar1 = GIP_TSC_DELTA_SYNC2_PRESTART_WAIT; 3132 ASMSerializeInstruction(); ASMCompilerBarrier(); 3133 ASMAtomicWritePtr(&pArgs->pSyncMaster, &MySync); 3134 } 3135 else 3136 { 3137 MySync.uVar1 = GIP_TSC_DELTA_SYNC2_PRESTART_WAIT; 3138 ASMSerializeInstruction(); ASMCompilerBarrier(); 3139 ASMAtomicWritePtr(&pArgs->pSyncWorker, &MySync); 3140 } 3141 3142 MySync.uTscStart = ASMReadTSC(); 3143 MySync.cMaxTicks = u64CpuHz 3144 3145 while ((pOtherSync = ASMAtomicReadPtr((void * volatile *)(fIsMaster ? &pArgs->pSyncWorker : &pArgs->pSyncMaster))) != NULL) 3146 { 3147 uint32_t cInner = 10240; 3148 while ( cInner-- > 0 3149 && ASMAtomicUoReadU32(MySync.uVar1) == GIP_TSC_DELTA_SYNC2_PRESTART_WAIT) 3150 ASMNopPause(); 3151 3152 } 3191 if (!ASMAtomicCmpXchgU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_START, GIP_TSC_DELTA_SYNC2_PRESTART_WAIT)) /* parnaoia */ 3192 return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/); 3193 3194 iTry = 0; 3195 while (ASMAtomicReadU32(&MySync.uSyncVar) == GIP_TSC_DELTA_SYNC2_PRESTART_WAIT) 3196 { 3197 ASMNopPause(); 3198 if (ASMAtomicReadBool(&pArgs->fAbortSetup)) 3199 return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/); 3200 if ( (iTry++ & 0xff) == 0 3201 && ASMReadTSC() - MySync.uTscStart > pArgs->cMaxTscTicks) 3202 { 3203 if ( fIsMaster 3204 && !ASMAtomicCmpXchgU32(&MySync.uSyncVar, GIP_TSC_DELTA_SYNC2_PRESTART_ABORT, GIP_TSC_DELTA_SYNC2_PRESTART_WAIT)) 3205 break; /* race #1: slave has moved on, handle timeout in loop instead. */ 3206 return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, true /*fTimeout*/); 3207 } 3208 #if defined(DEBUG_bird) && defined(RT_OS_WINDOWS) 3209 if (iTry == 0) __debugbreak(); 3153 3210 #endif 3154 3155 3156 /* If the IPRT API isn't concurrent safe, the master and worker wait for each other 3157 with a timeout to avoid deadlocking the entire system. */ 3158 if (!RTMpOnAllIsConcurrentSafe()) 3159 { 3160 /** @todo This was introduced for Windows, but since Windows doesn't use this 3161 * code path any longer (as DPC timeouts BSOD regardless of interrupts, 3162 * see @bugref{6710} comment 81), eventually phase it out. */ 3163 uint64_t uTscNow; 3164 uint64_t uTscStart; 3165 uint64_t const cWaitTicks = 130000; /* Arbitrary value, can be tweaked later. */ 3166 3167 ASMSerializeInstruction(); 3168 uTscStart = ASMReadTSC(); 3169 if (fIsMaster) 3170 { 3171 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_PRESTART_MASTER); 3172 while (ASMAtomicReadU32(&pDevExt->pTscDeltaSync->u) != GIP_TSC_DELTA_SYNC_PRESTART_WORKER) 3173 { 3174 ASMSerializeInstruction(); 3175 uTscNow = ASMReadTSC(); 3176 if (uTscNow - uTscStart > cWaitTicks) 3177 { 3178 /* Set the worker delta to indicate failure, not the master. */ 3179 ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, INT64_MAX); 3180 return; 3181 } 3182 3183 ASMNopPause(); 3184 } 3185 } 3186 else 3187 { 3188 while (ASMAtomicReadU32(&pDevExt->pTscDeltaSync->u) != GIP_TSC_DELTA_SYNC_PRESTART_MASTER) 3189 { 3190 ASMSerializeInstruction(); 3191 uTscNow = ASMReadTSC(); 3192 if (uTscNow - uTscStart > cWaitTicks) 3193 { 3194 ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, INT64_MAX); 3195 return; 3196 } 3197 3198 ASMNopPause(); 3199 } 3200 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_PRESTART_WORKER); 3201 } 3202 } 3211 } 3212 3213 if (!fIsMaster) 3214 if (!ASMAtomicCmpXchgU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_START, GIP_TSC_DELTA_SYNC2_PRESTART_WAIT)) /* race #1 */ 3215 return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/); 3203 3216 3204 3217 /* … … 3208 3221 for (iTry = 0; iTry < 12; iTry++) 3209 3222 { 3223 if (ASMAtomicReadU32(&MySync.uSyncVar) != GIP_TSC_DELTA_SYNC2_START) 3224 break; 3225 3210 3226 /* 3211 3227 * Do the measurements. 3212 3228 */ 3213 3229 #ifdef GIP_TSC_DELTA_METHOD_1 3214 supdrvTscDeltaMethod1Loop(pArgs, pSync , fIsMaster, iTry);3230 supdrvTscDeltaMethod1Loop(pArgs, pSync1, &MySync, pOtherSync, fIsMaster, iTry); 3215 3231 #elif defined(GIP_TSC_DELTA_METHOD_2) 3216 supdrvTscDeltaMethod2Loop(pArgs, pSync , fIsMaster, iTry);3232 supdrvTscDeltaMethod2Loop(pArgs, pSync1, &MySync, pOtherSync, fIsMaster, iTry); 3217 3233 #else 3218 3234 # error "huh??" 3219 3235 #endif 3236 if (ASMAtomicReadU32(&MySync.uSyncVar) != GIP_TSC_DELTA_SYNC2_START) 3237 break; 3220 3238 3221 3239 /* … … 3237 3255 } 3238 3256 } 3239 } 3240 3241 3242 /** 3243 * Clears TSC delta related variables. 3244 * 3245 * Clears all TSC samples as well as the delta synchronization variable on the 3246 * all the per-CPU structs. Optionally also clears the per-cpu deltas too. 3247 * 3248 * @param pDevExt Pointer to the device instance data. 3249 * @param fClearDeltas Whether the deltas are also to be cleared. 3250 */ 3251 DECLINLINE(void) supdrvClearTscSamples(PSUPDRVDEVEXT pDevExt, bool fClearDeltas) 3252 { 3253 unsigned iCpu; 3254 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 3255 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 3256 { 3257 PSUPGIPCPU pGipCpu = &pGip->aCPUs[iCpu]; 3258 ASMAtomicWriteU64(&pGipCpu->u64TSCSample, GIP_TSC_DELTA_RSVD); 3259 if (fClearDeltas) 3260 ASMAtomicWriteS64(&pGipCpu->i64TSCDelta, INT64_MAX); 3261 } 3262 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP); 3257 3258 /* 3259 * End the synchroniziation dance. We tell the other that we're done, 3260 * then wait for the same kind of reply. 3261 */ 3262 ASMAtomicWriteU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_FINAL); 3263 ASMAtomicWriteNullPtr(ppMySync); 3264 iTry = 0; 3265 while (ASMAtomicReadU32(&MySync.uSyncVar) != GIP_TSC_DELTA_SYNC2_FINAL) 3266 { 3267 iTry++; 3268 if ( iTry == 0 3269 && !RTMpIsCpuOnline(fIsMaster ? pGipCpuWorker->idCpu : pGipCpuWorker->idCpu)) 3270 break; /* this really shouldn't happen. */ 3271 #if defined(DEBUG_bird) && defined(RT_OS_WINDOWS) 3272 if (iTry == 0) __debugbreak(); 3273 #endif 3274 ASMNopPause(); 3275 } 3276 3277 return 0; 3278 } 3279 3280 /** 3281 * Callback used by supdrvMeasureInitialTscDeltas() to read the TSC on two CPUs 3282 * and compute the delta between them. 3283 * 3284 * @param idCpu The CPU we are current scheduled on. 3285 * @param pvUser1 Pointer to a parameter package (SUPDRVGIPTSCDELTARGS). 3286 * @param pvUser2 Unused. 3287 */ 3288 static DECLCALLBACK(void) supdrvMeasureTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2) 3289 { 3290 supdrvMeasureTscDeltaCallbackUnwrapped(idCpu, (PSUPDRVGIPTSCDELTARGS)pvUser1); 3263 3291 } 3264 3292 … … 3348 3376 if (RTCpuSetIsMemberByIndex(&pGip->OnlineCpuSet, pGipCpuWorker->iCpuSet)) 3349 3377 { 3378 /** @todo we need to check that the master is online... 3379 * The old supdrvMeasureTscDeltaCallback code would spin forever. */ 3350 3380 /* 3351 3381 * Initialize data package for the RTMpOnAll callback. … … 3353 3383 SUPDRVGIPTSCDELTARGS Args; 3354 3384 RT_ZERO(Args); 3355 Args.pWorker = pGipCpuWorker; 3356 Args.pMaster = pGipCpuMaster; 3357 Args.pDevExt = pDevExt; 3358 Args.pSyncMaster = NULL; 3359 Args.pSyncWorker = NULL; 3385 Args.pWorker = pGipCpuWorker; 3386 Args.pMaster = pGipCpuMaster; 3387 Args.pDevExt = pDevExt; 3388 Args.pSyncMaster = NULL; 3389 Args.pSyncWorker = NULL; 3390 #if 0 /* later */ 3391 Args.cMaxTscTicks = ASMAtomicReadU64(&pGip->u64CpuHz) / 2048; /* 488 us */ 3392 #else 3393 Args.cMaxTscTicks = ASMAtomicReadU64(&pGip->u64CpuHz) / 1024; /* 976 us */ 3394 #endif 3395 3360 3396 #ifdef GIP_TSC_DELTA_METHOD_1 3361 3397 rc = supdrvTscDeltaMethod1Init(&Args); … … 3420 3456 3421 3457 /** 3458 * Clears TSC delta related variables. 3459 * 3460 * Clears all TSC samples as well as the delta synchronization variable on the 3461 * all the per-CPU structs. Optionally also clears the per-cpu deltas too. 3462 * 3463 * @param pDevExt Pointer to the device instance data. 3464 * @param fClearDeltas Whether the deltas are also to be cleared. 3465 */ 3466 static void supdrvClearTscSamples(PSUPDRVDEVEXT pDevExt, bool fClearDeltas) 3467 { 3468 unsigned iCpu; 3469 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 3470 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 3471 { 3472 PSUPGIPCPU pGipCpu = &pGip->aCPUs[iCpu]; 3473 ASMAtomicWriteU64(&pGipCpu->u64TSCSample, GIP_TSC_DELTA_RSVD); 3474 if (fClearDeltas) 3475 ASMAtomicWriteS64(&pGipCpu->i64TSCDelta, INT64_MAX); 3476 } 3477 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP); 3478 } 3479 3480 3481 /** 3422 3482 * Performs the initial measurements of the TSC deltas between CPUs. 3423 3483 * … … 3944 4004 cTries = 256; 3945 4005 3946 if (cMsWaitRetry > 1000) 4006 if (cMsWaitRetry == 0) 4007 cMsWaitRetry = 2; 4008 else if (cMsWaitRetry > 1000) 3947 4009 cMsWaitRetry = 1000; 3948 4010 … … 4045 4107 cTries--; 4046 4108 4047 if (cMsWaitRetry) 4048 { 4049 rc = RTThreadSleep(cMsWaitRetry); 4050 if (rc == VERR_INTERRUPTED) 4051 break; 4052 } 4109 /* Always delay between retries (be nice to the rest of the system 4110 and avoid the BSOD hounds). */ 4111 rc = RTThreadSleep(cMsWaitRetry); 4112 if (rc == VERR_INTERRUPTED) 4113 break; 4053 4114 } 4054 4115 … … 4172 4233 rc = supdrvMeasureTscDeltaOne(pDevExt, iGipCpu); 4173 4234 Assert(pGip->aCPUs[iGipCpu].i64TSCDelta != INT64_MAX || RT_FAILURE_NP(rc)); 4235 /** @todo should probably delay on failure... dpc watchdogs */ 4174 4236 } 4175 4237 else
Note:
See TracChangeset
for help on using the changeset viewer.