Changeset 87816 in vbox
- Timestamp:
- Feb 20, 2021 12:54:46 AM (4 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR3/TM.cpp
r87814 r87816 180 180 #endif 181 181 static DECLCALLBACK(void) tmR3TimerCallback(PRTTIMER pTimer, void *pvUser, uint64_t iTick); 182 static void tmR3TimerQueueRun(PVM pVM, PTMTIMERQUEUE pQueue);183 static void tmR3TimerQueueRunVirtualSync(PVM pVM);184 182 static DECLCALLBACK(int) tmR3SetWarpDrive(PUVM pUVM, uint32_t u32Percent); 185 183 #ifndef VBOX_WITHOUT_NS_ACCOUNTING … … 228 226 { 229 227 Assert(pVM->tm.s.aTimerQueues[i].szName[0] != '\0'); 230 pVM->tm.s.aTimerQueues[i].enmClock = (TMCLOCK)i; 231 pVM->tm.s.aTimerQueues[i].u64Expire = INT64_MAX; 232 pVM->tm.s.aTimerQueues[i].idxActive = UINT32_MAX; 233 pVM->tm.s.aTimerQueues[i].idxSchedule = UINT32_MAX; 234 pVM->tm.s.aTimerQueues[i].idxFreeHint = 1; 228 pVM->tm.s.aTimerQueues[i].enmClock = (TMCLOCK)i; 229 pVM->tm.s.aTimerQueues[i].u64Expire = INT64_MAX; 230 pVM->tm.s.aTimerQueues[i].idxActive = UINT32_MAX; 231 pVM->tm.s.aTimerQueues[i].idxSchedule = UINT32_MAX; 232 pVM->tm.s.aTimerQueues[i].idxFreeHint = 1; 233 pVM->tm.s.aTimerQueues[i].fBeingProcessed = false; 234 pVM->tm.s.aTimerQueues[i].fCannotGrow = false; 235 pVM->tm.s.aTimerQueues[i].hThread = NIL_RTTHREAD; 236 pVM->tm.s.aTimerQueues[i].hWorkerEvt = NIL_SUPSEMEVENT; 237 235 238 rc = PDMR3CritSectInit(pVM, &pVM->tm.s.aTimerQueues[i].TimerLock, RT_SRC_POS, 236 239 "TM %s queue timer lock", pVM->tm.s.aTimerQueues[i].szName); … … 2282 2285 2283 2286 /** 2284 * Schedules and runs any pending timers. 2285 * 2286 * This is normally called from a forced action handler in EMT. 2287 * 2288 * @param pVM The cross context VM structure. 2289 * 2290 * @thread EMT (actually EMT0, but we fend off the others) 2291 */ 2292 VMMR3DECL(void) TMR3TimerQueuesDo(PVM pVM) 2293 { 2294 /* 2295 * Only the dedicated timer EMT should do stuff here. 2296 * (fRunningQueues is only used as an indicator.) 2297 */ 2298 Assert(pVM->tm.s.idTimerCpu < pVM->cCpus); 2299 PVMCPU pVCpuDst = pVM->apCpusR3[pVM->tm.s.idTimerCpu]; 2300 if (VMMGetCpu(pVM) != pVCpuDst) 2301 { 2302 Assert(pVM->cCpus > 1); 2303 return; 2304 } 2305 STAM_PROFILE_START(&pVM->tm.s.StatDoQueues, a); 2306 Log2(("TMR3TimerQueuesDo:\n")); 2307 Assert(!pVM->tm.s.fRunningQueues); 2308 ASMAtomicWriteBool(&pVM->tm.s.fRunningQueues, true); 2309 2310 /* 2311 * Process the queues. 2312 */ 2313 AssertCompile(TMCLOCK_MAX == 4); 2314 2315 /* 2316 * TMCLOCK_VIRTUAL_SYNC (see also TMR3VirtualSyncFF) 2317 */ 2318 PTMTIMERQUEUE pQueue = &pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL_SYNC]; 2319 STAM_PROFILE_START(&pQueue->StatDo, s1); 2320 PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED); 2321 PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VERR_IGNORED); 2322 ASMAtomicWriteBool(&pVM->tm.s.fRunningVirtualSyncQueue, true); 2323 VMCPU_FF_CLEAR(pVCpuDst, VMCPU_FF_TIMER); /* Clear the FF once we started working for real. */ 2324 2325 Assert(pQueue->idxSchedule == UINT32_MAX); 2326 tmR3TimerQueueRunVirtualSync(pVM); 2327 if (pVM->tm.s.fVirtualSyncTicking) /** @todo move into tmR3TimerQueueRunVirtualSync - FIXME */ 2328 VM_FF_CLEAR(pVM, VM_FF_TM_VIRTUAL_SYNC); 2329 2330 ASMAtomicWriteBool(&pVM->tm.s.fRunningVirtualSyncQueue, false); 2331 PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock); 2332 PDMCritSectLeave(&pQueue->TimerLock); 2333 STAM_PROFILE_STOP(&pQueue->StatDo, s1); 2334 2335 /* 2336 * TMCLOCK_VIRTUAL 2337 */ 2338 pQueue = &pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL]; 2339 STAM_PROFILE_START(&pQueue->StatDo, s2); 2340 PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED); 2341 if (pQueue->idxSchedule != UINT32_MAX) 2342 tmTimerQueueSchedule(pVM, pQueue, pQueue); 2343 tmR3TimerQueueRun(pVM, pQueue); 2344 PDMCritSectLeave(&pQueue->TimerLock); 2345 STAM_PROFILE_STOP(&pQueue->StatDo, s2); 2346 2347 /* 2348 * TMCLOCK_TSC 2349 */ 2350 Assert(pVM->tm.s.aTimerQueues[TMCLOCK_TSC].idxActive == UINT32_MAX); /* not used */ 2351 2352 /* 2353 * TMCLOCK_REAL 2354 */ 2355 pQueue = &pVM->tm.s.aTimerQueues[TMCLOCK_REAL]; 2356 STAM_PROFILE_START(&pQueue->StatDo, s3); 2357 PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED); 2358 if (pQueue->idxSchedule != UINT32_MAX) 2359 tmTimerQueueSchedule(pVM, pQueue, pQueue); 2360 tmR3TimerQueueRun(pVM, pQueue); 2361 PDMCritSectLeave(&pQueue->TimerLock); 2362 STAM_PROFILE_STOP(&pQueue->StatDo, s3); 2363 2364 #ifdef VBOX_STRICT 2365 /* check that we didn't screw up. */ 2366 tmTimerQueuesSanityChecks(pVM, "TMR3TimerQueuesDo"); 2367 #endif 2368 2369 /* done */ 2370 Log2(("TMR3TimerQueuesDo: returns void\n")); 2371 ASMAtomicWriteBool(&pVM->tm.s.fRunningQueues, false); 2372 STAM_PROFILE_STOP(&pVM->tm.s.StatDoQueues, a); 2373 } 2374 2375 //RT_C_DECLS_BEGIN 2376 //int iomLock(PVM pVM); 2377 //void iomUnlock(PVM pVM); 2378 //RT_C_DECLS_END 2379 2380 2381 /** 2382 * Schedules and runs any pending times in the specified queue. 2383 * 2384 * This is normally called from a forced action handler in EMT. 2287 * Worker for tmR3TimerQueueDoOne that runs pending timers on the specified 2288 * non-empty timer queue. 2385 2289 * 2386 2290 * @param pVM The cross context VM structure. 2387 2291 * @param pQueue The queue to run. 2388 */ 2389 static void tmR3TimerQueueRun(PVM pVM, PTMTIMERQUEUE pQueue) 2390 { 2391 VM_ASSERT_EMT(pVM); 2292 * @param pNext The head timer. Caller already check that this is 2293 * not NULL. 2294 */ 2295 static void tmR3TimerQueueRun(PVM pVM, PTMTIMERQUEUE pQueue, PTMTIMER pTimer) 2296 { 2297 VM_ASSERT_EMT(pVM); /** @todo relax this */ 2392 2298 2393 2299 /* … … 2399 2305 * N.B. A generic unlink must be applied since other threads 2400 2306 * are allowed to mess with any active timer at any time. 2307 * 2401 2308 * However, we only allow EMT to handle EXPIRED_PENDING 2402 2309 * timers, thus enabling the timer handler function to 2403 2310 * arm the timer again. 2404 2311 */ 2405 PTMTIMER pNext = tmTimerQueueGetHead(pQueue, pQueue); 2406 if (!pNext) 2407 return; 2312 /** @todo the above 'however' is outdated. */ 2408 2313 const uint64_t u64Now = tmClock(pVM, pQueue->enmClock); 2409 while (pNext && pNext->u64Expire <= u64Now) 2410 { 2411 PTMTIMER pTimer = pNext; 2412 pNext = tmTimerGetNext(pQueue, pTimer); 2314 while (pTimer->u64Expire <= u64Now) 2315 { 2316 PTMTIMER const pNext = tmTimerGetNext(pQueue, pTimer); 2413 2317 PPDMCRITSECT pCritSect = pTimer->pCritSect; 2414 2318 if (pCritSect) … … 2461 2365 if (pCritSect) 2462 2366 PDMCritSectLeave(pCritSect); 2367 2368 /* Advance? */ 2369 pTimer = pNext; 2370 if (!pTimer) 2371 break; 2463 2372 } /* run loop */ 2373 } 2374 2375 2376 /** 2377 * Service one regular timer queue. 2378 * 2379 * @param pVM The cross context VM structure. 2380 * @param pQueue The queue. 2381 */ 2382 static void tmR3TimerQueueDoOne(PVM pVM, PTMTIMERQUEUE pQueue) 2383 { 2384 Assert(pQueue->enmClock != TMCLOCK_VIRTUAL_SYNC); 2385 2386 /* 2387 * Only one thread should be "doing" the queue. 2388 */ 2389 if (ASMAtomicCmpXchgBool(&pQueue->fBeingProcessed, true, false)) 2390 { 2391 STAM_PROFILE_START(&pQueue->StatDo, s); 2392 PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED); 2393 2394 if (pQueue->idxSchedule != UINT32_MAX) 2395 tmTimerQueueSchedule(pVM, pQueue, pQueue); 2396 2397 PTMTIMER pHead = tmTimerQueueGetHead(pQueue, pQueue); 2398 if (pHead) 2399 tmR3TimerQueueRun(pVM, pQueue, pHead); 2400 2401 PDMCritSectLeave(&pQueue->TimerLock); 2402 STAM_PROFILE_STOP(&pQueue->StatDo, s); 2403 ASMAtomicWriteBool(&pQueue->fBeingProcessed, false); 2404 } 2464 2405 } 2465 2406 … … 2611 2552 } 2612 2553 2613 Log2(("tmR3TimerQueueRun : %p:{.enmState=%s, .enmClock=%d, .enmType=%d, u64Expire=%llx (now=%llx) .szName='%s'}\n",2554 Log2(("tmR3TimerQueueRunVirtualSync: %p:{.enmState=%s, .enmClock=%d, .enmType=%d, u64Expire=%llx (now=%llx) .szName='%s'}\n", 2614 2555 pTimer, tmTimerState(pTimer->enmState), pQueue->enmClock, pTimer->enmType, pTimer->u64Expire, u64Now, pTimer->szName)); 2615 2556 … … 2649 2590 pTimer->uHzHint = 0; 2650 2591 } 2651 Log2(("tmR3TimerQueueRun : new state %s\n", tmTimerState(pTimer->enmState)));2592 Log2(("tmR3TimerQueueRunVirtualSync: new state %s\n", tmTimerState(pTimer->enmState))); 2652 2593 2653 2594 /* Leave the associated lock. */ … … 2808 2749 else 2809 2750 { 2751 /** @todo Optimize for SMP */ 2810 2752 STAM_PROFILE_START(&pVM->tm.s.StatVirtualSyncFF, a); 2811 2753 PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VERR_IGNORED); … … 2843 2785 } 2844 2786 } 2787 2788 2789 /** 2790 * Service the special virtual sync timer queue. 2791 * 2792 * @param pVM The cross context VM structure. 2793 * @param pQueue The queue. 2794 */ 2795 static void tmR3TimerQueueDoVirtualSync(PVM pVM, PVMCPU pVCpuDst) 2796 { 2797 PTMTIMERQUEUE pQueue = &pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL_SYNC]; 2798 if (ASMAtomicCmpXchgBool(&pQueue->fBeingProcessed, true, false)) 2799 { 2800 STAM_PROFILE_START(&pQueue->StatDo, s1); 2801 PDMCritSectEnter(&pQueue->TimerLock, VERR_IGNORED); 2802 PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VERR_IGNORED); 2803 ASMAtomicWriteBool(&pVM->tm.s.fRunningVirtualSyncQueue, true); 2804 VMCPU_FF_CLEAR(pVCpuDst, VMCPU_FF_TIMER); /* Clear the FF once we started working for real. */ 2805 2806 Assert(pQueue->idxSchedule == UINT32_MAX); 2807 tmR3TimerQueueRunVirtualSync(pVM); 2808 if (pVM->tm.s.fVirtualSyncTicking) /** @todo move into tmR3TimerQueueRunVirtualSync - FIXME */ 2809 VM_FF_CLEAR(pVM, VM_FF_TM_VIRTUAL_SYNC); 2810 2811 ASMAtomicWriteBool(&pVM->tm.s.fRunningVirtualSyncQueue, false); 2812 PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock); 2813 PDMCritSectLeave(&pQueue->TimerLock); 2814 STAM_PROFILE_STOP(&pQueue->StatDo, s1); 2815 ASMAtomicWriteBool(&pQueue->fBeingProcessed, false); 2816 } 2817 } 2818 2819 2820 /** 2821 * Schedules and runs any pending timers. 2822 * 2823 * This is normally called from a forced action handler in EMT. 2824 * 2825 * @param pVM The cross context VM structure. 2826 * 2827 * @thread EMT (actually EMT0, but we fend off the others) 2828 */ 2829 VMMR3DECL(void) TMR3TimerQueuesDo(PVM pVM) 2830 { 2831 /* 2832 * Only the dedicated timer EMT should do stuff here. 2833 * (fRunningQueues is only used as an indicator.) 2834 */ 2835 Assert(pVM->tm.s.idTimerCpu < pVM->cCpus); 2836 PVMCPU pVCpuDst = pVM->apCpusR3[pVM->tm.s.idTimerCpu]; 2837 if (VMMGetCpu(pVM) != pVCpuDst) 2838 { 2839 Assert(pVM->cCpus > 1); 2840 return; 2841 } 2842 STAM_PROFILE_START(&pVM->tm.s.StatDoQueues, a); 2843 Log2(("TMR3TimerQueuesDo:\n")); 2844 Assert(!pVM->tm.s.fRunningQueues); 2845 ASMAtomicWriteBool(&pVM->tm.s.fRunningQueues, true); 2846 2847 /* 2848 * Process the queues. 2849 */ 2850 AssertCompile(TMCLOCK_MAX == 4); 2851 2852 /* 2853 * TMCLOCK_VIRTUAL_SYNC (see also TMR3VirtualSyncFF) 2854 */ 2855 tmR3TimerQueueDoVirtualSync(pVM, pVCpuDst); 2856 2857 /* 2858 * TMCLOCK_VIRTUAL 2859 */ 2860 tmR3TimerQueueDoOne(pVM, &pVM->tm.s.aTimerQueues[TMCLOCK_VIRTUAL]); 2861 2862 /* 2863 * TMCLOCK_TSC 2864 */ 2865 Assert(pVM->tm.s.aTimerQueues[TMCLOCK_TSC].idxActive == UINT32_MAX); /* not used */ 2866 2867 /* 2868 * TMCLOCK_REAL 2869 */ 2870 tmR3TimerQueueDoOne(pVM, &pVM->tm.s.aTimerQueues[TMCLOCK_REAL]); 2871 2872 #ifdef VBOX_STRICT 2873 /* check that we didn't screw up. */ 2874 tmTimerQueuesSanityChecks(pVM, "TMR3TimerQueuesDo"); 2875 #endif 2876 2877 /* done */ 2878 Log2(("TMR3TimerQueuesDo: returns void\n")); 2879 ASMAtomicWriteBool(&pVM->tm.s.fRunningQueues, false); 2880 STAM_PROFILE_STOP(&pVM->tm.s.StatDoQueues, a); 2881 } 2882 2845 2883 2846 2884 -
trunk/src/VBox/VMM/include/TMInternal.h
r87815 r87816 292 292 /** The queue name. */ 293 293 char szName[16]; 294 /** Set when a thread is doing scheduling and callback. */ 295 bool volatile fBeingProcessed; 294 296 /** Set if we've disabled growing. */ 295 297 bool fCannotGrow; 296 298 /** Align on 64-byte boundrary. */ 297 bool afAlignment1[ 3];299 bool afAlignment1[2]; 298 300 /** The current max timer Hz hint. */ 299 301 uint32_t volatile uMaxHzHint; … … 303 305 /** Time spent doing scheduling and timer callbacks. */ 304 306 STAMPROFILE StatDo; 305 uint64_t u64Alignment2[4]; 307 /** The thread servicing this queue, NIL if none. */ 308 R3PTRTYPE(RTTHREAD) hThread; 309 /** The handle to the event semaphore the worker thread sleeps on. */ 310 SUPSEMEVENT hWorkerEvt; 311 /** Absolute sleep deadline for the worker (enmClock time). */ 312 uint64_t volatile tsWorkerWakeup; 313 uint64_t u64Alignment2; 306 314 307 315 /** Lock serializing the active timer list and associated work. */ … … 593 601 594 602 /** Lock serializing access to the VirtualSync clock and the associated 595 * timer queue. */ 603 * timer queue. 604 * @todo Consider merging this with the TMTIMERQUEUE::TimerLock for the 605 * virtual sync queue. */ 596 606 PDMCRITSECT VirtualSyncLock; 597 607
Note:
See TracChangeset
for help on using the changeset viewer.