Changeset 37517 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Jun 16, 2011 7:24:00 PM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 72345
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 1 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/TMAll.cpp
r37452 r37517 5 5 6 6 /* 7 * Copyright (C) 2006-20 07Oracle Corporation7 * Copyright (C) 2006-2011 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 23 23 #include <VBox/vmm/tm.h> 24 24 #include <VBox/vmm/mm.h> 25 #include <VBox/vmm/dbgftrace.h> 25 26 #ifdef IN_RING3 26 27 # include <VBox/vmm/rem.h> … … 40 41 # include <iprt/thread.h> 41 42 #endif 43 44 #include "TMInline.h" 42 45 43 46 … … 373 376 * and stuff. 374 377 */ 375 DECLINLINE(void) tmTimerLink (PTMTIMERQUEUE pQueue, PTMTIMER pTimer)378 DECLINLINE(void) tmTimerLinkSchedule(PTMTIMERQUEUE pQueue, PTMTIMER pTimer) 376 379 { 377 380 Assert(!pTimer->offScheduleNext); … … 402 405 if (tmTimerTry(pTimer, enmStateNew, enmStateOld)) 403 406 { 404 tmTimerLink (&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF(paTimerQueues)[pTimer->enmClock], pTimer);407 tmTimerLinkSchedule(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF(paTimerQueues)[pTimer->enmClock], pTimer); 405 408 return true; 406 409 } … … 408 411 } 409 412 413 414 /** 415 * Links a timer into the active list of a timer queue. 416 * 417 * @param pQueue The queue. 418 * @param pTimer The timer. 419 * @param u64Expire The timer expiration time. 420 * 421 * @remarks Called while owning the relevant queue lock. 422 */ 423 DECL_FORCE_INLINE(void) tmTimerQueueLinkActive(PTMTIMERQUEUE pQueue, PTMTIMER pTimer, uint64_t u64Expire) 424 { 425 Assert(!pTimer->offNext); 426 Assert(!pTimer->offPrev); 427 Assert(pTimer->enmState == TMTIMERSTATE_ACTIVE || pTimer->enmClock != TMCLOCK_VIRTUAL_SYNC); /* (active is not a stable state) */ 428 429 PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue); 430 if (pCur) 431 { 432 for (;; pCur = TMTIMER_GET_NEXT(pCur)) 433 { 434 if (pCur->u64Expire > u64Expire) 435 { 436 const PTMTIMER pPrev = TMTIMER_GET_PREV(pCur); 437 TMTIMER_SET_NEXT(pTimer, pCur); 438 TMTIMER_SET_PREV(pTimer, pPrev); 439 if (pPrev) 440 TMTIMER_SET_NEXT(pPrev, pTimer); 441 else 442 { 443 TMTIMER_SET_HEAD(pQueue, pTimer); 444 ASMAtomicWriteU64(&pQueue->u64Expire, u64Expire); 445 DBGFTRACE_U64_TAG2(pTimer->CTX_SUFF(pVM), u64Expire, "tmTimerQueueLinkActive head", R3STRING(pTimer->pszDesc)); 446 } 447 TMTIMER_SET_PREV(pCur, pTimer); 448 return; 449 } 450 if (!pCur->offNext) 451 { 452 TMTIMER_SET_NEXT(pCur, pTimer); 453 TMTIMER_SET_PREV(pTimer, pCur); 454 DBGFTRACE_U64_TAG2(pTimer->CTX_SUFF(pVM), u64Expire, "tmTimerQueueLinkActive tail", R3STRING(pTimer->pszDesc)); 455 return; 456 } 457 } 458 } 459 else 460 { 461 TMTIMER_SET_HEAD(pQueue, pTimer); 462 ASMAtomicWriteU64(&pQueue->u64Expire, u64Expire); 463 DBGFTRACE_U64_TAG2(pTimer->CTX_SUFF(pVM), u64Expire, "tmTimerQueueLinkActive empty", R3STRING(pTimer->pszDesc)); 464 } 465 } 466 467 468 469 /** 470 * Schedules the given timer on the given queue. 471 * 472 * @param pQueue The timer queue. 473 * @param pTimer The timer that needs scheduling. 474 * 475 * @remarks Called while owning the lock. 476 */ 477 DECLINLINE(void) tmTimerQueueScheduleOne(PTMTIMERQUEUE pQueue, PTMTIMER pTimer) 478 { 479 Assert(pQueue->enmClock != TMCLOCK_VIRTUAL_SYNC); 480 481 /* 482 * Processing. 483 */ 484 unsigned cRetries = 2; 485 do 486 { 487 TMTIMERSTATE enmState = pTimer->enmState; 488 switch (enmState) 489 { 490 /* 491 * Reschedule timer (in the active list). 492 */ 493 case TMTIMERSTATE_PENDING_RESCHEDULE: 494 if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_SCHEDULE, TMTIMERSTATE_PENDING_RESCHEDULE))) 495 break; /* retry */ 496 tmTimerQueueUnlinkActive(pQueue, pTimer); 497 /* fall thru */ 498 499 /* 500 * Schedule timer (insert into the active list). 501 */ 502 case TMTIMERSTATE_PENDING_SCHEDULE: 503 Assert(!pTimer->offNext); Assert(!pTimer->offPrev); 504 if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_ACTIVE, TMTIMERSTATE_PENDING_SCHEDULE))) 505 break; /* retry */ 506 tmTimerQueueLinkActive(pQueue, pTimer, pTimer->u64Expire); 507 return; 508 509 /* 510 * Stop the timer in active list. 511 */ 512 case TMTIMERSTATE_PENDING_STOP: 513 if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_STOP_SCHEDULE, TMTIMERSTATE_PENDING_STOP))) 514 break; /* retry */ 515 tmTimerQueueUnlinkActive(pQueue, pTimer); 516 /* fall thru */ 517 518 /* 519 * Stop the timer (not on the active list). 520 */ 521 case TMTIMERSTATE_PENDING_STOP_SCHEDULE: 522 Assert(!pTimer->offNext); Assert(!pTimer->offPrev); 523 if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_STOPPED, TMTIMERSTATE_PENDING_STOP_SCHEDULE))) 524 break; 525 return; 526 527 /* 528 * The timer is pending destruction by TMR3TimerDestroy, our caller. 529 * Nothing to do here. 530 */ 531 case TMTIMERSTATE_DESTROY: 532 break; 533 534 /* 535 * Postpone these until they get into the right state. 536 */ 537 case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE: 538 case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE: 539 tmTimerLinkSchedule(pQueue, pTimer); 540 STAM_COUNTER_INC(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatPostponed)); 541 return; 542 543 /* 544 * None of these can be in the schedule. 545 */ 546 case TMTIMERSTATE_FREE: 547 case TMTIMERSTATE_STOPPED: 548 case TMTIMERSTATE_ACTIVE: 549 case TMTIMERSTATE_EXPIRED_GET_UNLINK: 550 case TMTIMERSTATE_EXPIRED_DELIVER: 551 default: 552 AssertMsgFailed(("Timer (%p) in the scheduling list has an invalid state %s (%d)!", 553 pTimer, tmTimerState(pTimer->enmState), pTimer->enmState)); 554 return; 555 } 556 } while (cRetries-- > 0); 557 } 558 559 560 /** 561 * Schedules the specified timer queue. 562 * 563 * @param pVM The VM to run the timers for. 564 * @param pQueue The queue to schedule. 565 * 566 * @remarks Called while owning the lock. 567 */ 568 void tmTimerQueueSchedule(PVM pVM, PTMTIMERQUEUE pQueue) 569 { 570 TM_ASSERT_LOCK(pVM); 571 572 /* 573 * Dequeue the scheduling list and iterate it. 574 */ 575 int32_t offNext = ASMAtomicXchgS32(&pQueue->offSchedule, 0); 576 Log2(("tmTimerQueueSchedule: pQueue=%p:{.enmClock=%d, offNext=%RI32, .u64Expired=%'RU64}\n", pQueue, pQueue->enmClock, offNext, pQueue->u64Expire)); 577 if (!offNext) 578 return; 579 PTMTIMER pNext = (PTMTIMER)((intptr_t)pQueue + offNext); 580 while (pNext) 581 { 582 /* 583 * Unlink the head timer and find the next one. 584 */ 585 PTMTIMER pTimer = pNext; 586 pNext = pNext->offScheduleNext ? (PTMTIMER)((intptr_t)pNext + pNext->offScheduleNext) : NULL; 587 pTimer->offScheduleNext = 0; 588 589 /* 590 * Do the scheduling. 591 */ 592 Log2(("tmTimerQueueSchedule: %p:{.enmState=%s, .enmClock=%d, .enmType=%d, .pszDesc=%s}\n", 593 pTimer, tmTimerState(pTimer->enmState), pTimer->enmClock, pTimer->enmType, R3STRING(pTimer->pszDesc))); 594 tmTimerQueueScheduleOne(pQueue, pTimer); 595 Log2(("tmTimerQueueSchedule: %p: new %s\n", pTimer, tmTimerState(pTimer->enmState))); 596 } /* foreach timer in current schedule batch. */ 597 Log2(("tmTimerQueueSchedule: u64Expired=%'RU64\n", pQueue->u64Expire)); 598 } 599 600 601 #ifdef VBOX_STRICT 602 /** 603 * Checks that the timer queues are sane. 604 * 605 * @param pVM VM handle. 606 * 607 * @remarks Called while owning the lock. 608 */ 609 void tmTimerQueuesSanityChecks(PVM pVM, const char *pszWhere) 610 { 611 TM_ASSERT_LOCK(pVM); 612 613 /* 614 * Check the linking of the active lists. 615 */ 616 bool fHaveVirtualSyncLock = false; 617 for (int i = 0; i < TMCLOCK_MAX; i++) 618 { 619 PTMTIMERQUEUE pQueue = &pVM->tm.s.CTX_SUFF(paTimerQueues)[i]; 620 Assert((int)pQueue->enmClock == i); 621 if (pQueue->enmClock == TMCLOCK_VIRTUAL_SYNC) 622 { 623 if (PDMCritSectTryEnter(&pVM->tm.s.VirtualSyncLock) != VINF_SUCCESS) 624 continue; 625 fHaveVirtualSyncLock = true; 626 } 627 PTMTIMER pPrev = NULL; 628 for (PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue); pCur; pPrev = pCur, pCur = TMTIMER_GET_NEXT(pCur)) 629 { 630 AssertMsg((int)pCur->enmClock == i, ("%s: %d != %d\n", pszWhere, pCur->enmClock, i)); 631 AssertMsg(TMTIMER_GET_PREV(pCur) == pPrev, ("%s: %p != %p\n", pszWhere, TMTIMER_GET_PREV(pCur), pPrev)); 632 TMTIMERSTATE enmState = pCur->enmState; 633 switch (enmState) 634 { 635 case TMTIMERSTATE_ACTIVE: 636 AssertMsg( !pCur->offScheduleNext 637 || pCur->enmState != TMTIMERSTATE_ACTIVE, 638 ("%s: %RI32\n", pszWhere, pCur->offScheduleNext)); 639 break; 640 case TMTIMERSTATE_PENDING_STOP: 641 case TMTIMERSTATE_PENDING_RESCHEDULE: 642 case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE: 643 break; 644 default: 645 AssertMsgFailed(("%s: Invalid state enmState=%d %s\n", pszWhere, enmState, tmTimerState(enmState))); 646 break; 647 } 648 } 649 } 650 651 652 # ifdef IN_RING3 653 /* 654 * Do the big list and check that active timers all are in the active lists. 655 */ 656 PTMTIMERR3 pPrev = NULL; 657 for (PTMTIMERR3 pCur = pVM->tm.s.pCreated; pCur; pPrev = pCur, pCur = pCur->pBigNext) 658 { 659 Assert(pCur->pBigPrev == pPrev); 660 Assert((unsigned)pCur->enmClock < (unsigned)TMCLOCK_MAX); 661 662 TMTIMERSTATE enmState = pCur->enmState; 663 switch (enmState) 664 { 665 case TMTIMERSTATE_ACTIVE: 666 case TMTIMERSTATE_PENDING_STOP: 667 case TMTIMERSTATE_PENDING_RESCHEDULE: 668 case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE: 669 if (fHaveVirtualSyncLock || pCur->enmClock != TMCLOCK_VIRTUAL_SYNC) 670 { 671 PTMTIMERR3 pCurAct = TMTIMER_GET_HEAD(&pVM->tm.s.CTX_SUFF(paTimerQueues)[pCur->enmClock]); 672 Assert(pCur->offPrev || pCur == pCurAct); 673 while (pCurAct && pCurAct != pCur) 674 pCurAct = TMTIMER_GET_NEXT(pCurAct); 675 Assert(pCurAct == pCur); 676 } 677 break; 678 679 case TMTIMERSTATE_PENDING_SCHEDULE: 680 case TMTIMERSTATE_PENDING_STOP_SCHEDULE: 681 case TMTIMERSTATE_STOPPED: 682 case TMTIMERSTATE_EXPIRED_DELIVER: 683 if (fHaveVirtualSyncLock || pCur->enmClock != TMCLOCK_VIRTUAL_SYNC) 684 { 685 Assert(!pCur->offNext); 686 Assert(!pCur->offPrev); 687 for (PTMTIMERR3 pCurAct = TMTIMER_GET_HEAD(&pVM->tm.s.CTX_SUFF(paTimerQueues)[pCur->enmClock]); 688 pCurAct; 689 pCurAct = TMTIMER_GET_NEXT(pCurAct)) 690 { 691 Assert(pCurAct != pCur); 692 Assert(TMTIMER_GET_NEXT(pCurAct) != pCur); 693 Assert(TMTIMER_GET_PREV(pCurAct) != pCur); 694 } 695 } 696 break; 697 698 /* ignore */ 699 case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE: 700 break; 701 702 /* shouldn't get here! */ 703 case TMTIMERSTATE_EXPIRED_GET_UNLINK: 704 case TMTIMERSTATE_DESTROY: 705 default: 706 AssertMsgFailed(("Invalid state enmState=%d %s\n", enmState, tmTimerState(enmState))); 707 break; 708 } 709 } 710 # endif /* IN_RING3 */ 711 712 if (fHaveVirtualSyncLock) 713 PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock); 714 } 715 #endif /* !VBOX_STRICT */ 410 716 411 717 #ifdef VBOX_HIGH_RES_TIMERS_HACK … … 854 1160 855 1161 /** 856 * Links a timer into the active list of a timer queue.857 *858 * The caller must have taken the TM semaphore before calling this function.859 *860 * @param pQueue The queue.861 * @param pTimer The timer.862 * @param u64Expire The timer expiration time.863 */864 DECL_FORCE_INLINE(void) tmTimerActiveLink(PTMTIMERQUEUE pQueue, PTMTIMER pTimer, uint64_t u64Expire)865 {866 PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue);867 if (pCur)868 {869 for (;; pCur = TMTIMER_GET_NEXT(pCur))870 {871 if (pCur->u64Expire > u64Expire)872 {873 const PTMTIMER pPrev = TMTIMER_GET_PREV(pCur);874 TMTIMER_SET_NEXT(pTimer, pCur);875 TMTIMER_SET_PREV(pTimer, pPrev);876 if (pPrev)877 TMTIMER_SET_NEXT(pPrev, pTimer);878 else879 {880 TMTIMER_SET_HEAD(pQueue, pTimer);881 pQueue->u64Expire = u64Expire;882 }883 TMTIMER_SET_PREV(pCur, pTimer);884 return;885 }886 if (!pCur->offNext)887 {888 TMTIMER_SET_NEXT(pCur, pTimer);889 TMTIMER_SET_PREV(pTimer, pCur);890 return;891 }892 }893 }894 else895 {896 TMTIMER_SET_HEAD(pQueue, pTimer);897 pQueue->u64Expire = u64Expire;898 }899 }900 901 902 /**903 1162 * Optimized TMTimerSet code path for starting an inactive timer. 904 1163 * … … 915 1174 Assert(pTimer->enmState == TMTIMERSTATE_ACTIVE); 916 1175 1176 TMCLOCK const enmClock = pTimer->enmClock; 1177 917 1178 /* 918 1179 * Calculate and set the expiration time. 919 1180 */ 920 pTimer->u64Expire = u64Expire; 1181 if (enmClock == TMCLOCK_VIRTUAL_SYNC) 1182 { 1183 uint64_t u64Last = ASMAtomicReadU64(&pVM->tm.s.u64VirtualSync); 1184 AssertMsgStmt(u64Expire >= u64Last, 1185 ("exp=%#llx last=%#llx\n", u64Expire, u64Last), 1186 u64Expire = u64Last); 1187 } 1188 ASMAtomicWriteU64(&pTimer->u64Expire, u64Expire); 921 1189 Log2(("tmTimerSetOptimizedStart: %p:{.pszDesc='%s', .u64Expire=%'RU64}\n", pTimer, R3STRING(pTimer->pszDesc), u64Expire)); 922 1190 … … 924 1192 * Link the timer into the active list. 925 1193 */ 926 TMCLOCK const enmClock = pTimer->enmClock; 927 tmTimerActiveLink(&pVM->tm.s.CTX_SUFF(paTimerQueues)[enmClock], pTimer, u64Expire); 1194 tmTimerQueueLinkActive(&pVM->tm.s.CTX_SUFF(paTimerQueues)[enmClock], pTimer, u64Expire); 928 1195 929 1196 STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetOpt); … … 933 1200 934 1201 935 1202 /** 1203 * TMTimerSet for the virtual sync timer queue. 1204 * 1205 * This employs a greatly simplified state machine by always acquiring the 1206 * queue lock and bypassing the scheduling list. 1207 * 1208 * @returns VBox status code 1209 * @param pVM The VM handle. 1210 * @param pTimer The timer handle. 1211 * @param u64Expire The expiration time. 1212 */ 1213 static int tmTimerVirtualSyncSet(PVM pVM, PTMTIMER pTimer, uint64_t u64Expire) 1214 { 1215 STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatTimerSetVs), a); 1216 VM_ASSERT_EMT(pVM); 1217 int rc = PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VINF_SUCCESS); 1218 AssertRCReturn(rc, rc); 1219 1220 PTMTIMERQUEUE pQueue = &pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC]; 1221 TMTIMERSTATE enmState = pTimer->enmState; 1222 switch (enmState) 1223 { 1224 case TMTIMERSTATE_EXPIRED_DELIVER: 1225 case TMTIMERSTATE_STOPPED: 1226 if (enmState == TMTIMERSTATE_EXPIRED_DELIVER) 1227 STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetVsStExpDeliver); 1228 else 1229 STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetVsStStopped); 1230 1231 AssertMsg(u64Expire >= pVM->tm.s.u64VirtualSync, 1232 ("%'RU64 < %'RU64 %s\n", u64Expire, pVM->tm.s.u64VirtualSync, R3STRING(pTimer->pszDesc))); 1233 pTimer->u64Expire = u64Expire; 1234 TM_SET_STATE(pTimer, TMTIMERSTATE_ACTIVE); 1235 tmTimerQueueLinkActive(pQueue, pTimer, u64Expire); 1236 rc = VINF_SUCCESS; 1237 break; 1238 1239 case TMTIMERSTATE_ACTIVE: 1240 STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetVsStActive); 1241 tmTimerQueueUnlinkActive(pQueue, pTimer); 1242 pTimer->u64Expire = u64Expire; 1243 tmTimerQueueLinkActive(pQueue, pTimer, u64Expire); 1244 rc = VINF_SUCCESS; 1245 break; 1246 1247 case TMTIMERSTATE_PENDING_RESCHEDULE: 1248 case TMTIMERSTATE_PENDING_STOP: 1249 case TMTIMERSTATE_PENDING_SCHEDULE: 1250 case TMTIMERSTATE_PENDING_STOP_SCHEDULE: 1251 case TMTIMERSTATE_EXPIRED_GET_UNLINK: 1252 case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE: 1253 case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE: 1254 case TMTIMERSTATE_DESTROY: 1255 case TMTIMERSTATE_FREE: 1256 AssertLogRelMsgFailed(("Invalid timer state %s: %s\n", tmTimerState(enmState), R3STRING(pTimer->pszDesc))); 1257 rc = VERR_TM_INVALID_STATE; 1258 break; 1259 1260 default: 1261 AssertMsgFailed(("Unknown timer state %d: %s\n", enmState, R3STRING(pTimer->pszDesc))); 1262 rc = VERR_TM_UNKNOWN_STATE; 1263 break; 1264 } 1265 1266 STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerSetVs), a); 1267 PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock); 1268 return rc; 1269 } 936 1270 937 1271 … … 946 1280 { 947 1281 PVM pVM = pTimer->CTX_SUFF(pVM); 1282 1283 /* Treat virtual sync timers specially. */ 1284 if (pTimer->enmClock == TMCLOCK_VIRTUAL_SYNC) 1285 return tmTimerVirtualSyncSet(pVM, pTimer, u64Expire); 1286 948 1287 STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatTimerSet), a); 949 1288 TMTIMER_ASSERT_CRITSECT(pTimer); 950 1289 1290 DBGFTRACE_U64_TAG2(pVM, u64Expire, "TMTimerSet", R3STRING(pTimer->pszDesc)); 1291 951 1292 #ifdef VBOX_WITH_STATISTICS 952 /* Gather optimization info. */ 1293 /* 1294 * Gather optimization info. 1295 */ 953 1296 STAM_COUNTER_INC(&pVM->tm.s.StatTimerSet); 954 1297 TMTIMERSTATE enmOrgState = pTimer->enmState; … … 982 1325 { 983 1326 tmTimerSetOptimizedStart(pVM, pTimer, u64Expire); 984 STAM_PROFILE_STOP(&p Timer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);1327 STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerSet), a); 985 1328 return VINF_SUCCESS; 986 1329 } … … 1010 1353 Assert(!pTimer->offPrev); 1011 1354 Assert(!pTimer->offNext); 1012 AssertMsg( pTimer->enmClock != TMCLOCK_VIRTUAL_SYNC1013 || pVM->tm.s.fVirtualSyncTicking1014 || u64Expire >= pVM->tm.s.u64VirtualSync,1015 ("%'RU64 < %'RU64 %s\n", u64Expire, pVM->tm.s.u64VirtualSync, R3STRING(pTimer->pszDesc)));1016 1355 pTimer->u64Expire = u64Expire; 1017 1356 TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_SCHEDULE); … … 1149 1488 * Link the timer into the active list. 1150 1489 */ 1151 tmTimerActiveLink(&pVM->tm.s.CTX_SUFF(paTimerQueues)[enmClock], pTimer, u64Expire); 1490 DBGFTRACE_U64_TAG2(pVM, u64Expire, "tmTimerSetRelativeOptimizedStart", R3STRING(pTimer->pszDesc)); 1491 tmTimerQueueLinkActive(&pVM->tm.s.CTX_SUFF(paTimerQueues)[enmClock], pTimer, u64Expire); 1152 1492 1153 1493 STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeOpt); 1154 1494 tmTimerUnlock(pVM); 1155 1495 return VINF_SUCCESS; 1496 } 1497 1498 1499 /** 1500 * TMTimerSetRelative for the virtual sync timer queue. 1501 * 1502 * This employs a greatly simplified state machine by always acquiring the 1503 * queue lock and bypassing the scheduling list. 1504 * 1505 * @returns VBox status code 1506 * @param pVM The VM handle. 1507 * @param cTicksToNext Clock ticks until the next time expiration. 1508 * @param pu64Now Where to return the current time stamp used. 1509 * Optional. 1510 */ 1511 static int tmTimerVirtualSyncSetRelative(PVM pVM, PTMTIMER pTimer, uint64_t cTicksToNext, uint64_t *pu64Now) 1512 { 1513 STAM_PROFILE_START(pVM->tm.s.CTX_SUFF_Z(StatTimerSetRelativeVs), a); 1514 VM_ASSERT_EMT(pVM); 1515 int rc = PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VINF_SUCCESS); 1516 AssertRCReturn(rc, rc); 1517 1518 /* Calculate the expiration tick. */ 1519 uint64_t u64Expire = TMVirtualSyncGetNoCheck(pVM); 1520 if (pu64Now) 1521 *pu64Now = u64Expire; 1522 u64Expire += cTicksToNext; 1523 1524 /* Update the timer. */ 1525 PTMTIMERQUEUE pQueue = &pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC]; 1526 TMTIMERSTATE enmState = pTimer->enmState; 1527 switch (enmState) 1528 { 1529 case TMTIMERSTATE_EXPIRED_DELIVER: 1530 case TMTIMERSTATE_STOPPED: 1531 if (enmState == TMTIMERSTATE_EXPIRED_DELIVER) 1532 STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeVsStExpDeliver); 1533 else 1534 STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeVsStStopped); 1535 pTimer->u64Expire = u64Expire; 1536 TM_SET_STATE(pTimer, TMTIMERSTATE_ACTIVE); 1537 tmTimerQueueLinkActive(pQueue, pTimer, u64Expire); 1538 rc = VINF_SUCCESS; 1539 break; 1540 1541 case TMTIMERSTATE_ACTIVE: 1542 STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeVsStActive); 1543 tmTimerQueueUnlinkActive(pQueue, pTimer); 1544 pTimer->u64Expire = u64Expire; 1545 tmTimerQueueLinkActive(pQueue, pTimer, u64Expire); 1546 rc = VINF_SUCCESS; 1547 break; 1548 1549 case TMTIMERSTATE_PENDING_RESCHEDULE: 1550 case TMTIMERSTATE_PENDING_STOP: 1551 case TMTIMERSTATE_PENDING_SCHEDULE: 1552 case TMTIMERSTATE_PENDING_STOP_SCHEDULE: 1553 case TMTIMERSTATE_EXPIRED_GET_UNLINK: 1554 case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE: 1555 case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE: 1556 case TMTIMERSTATE_DESTROY: 1557 case TMTIMERSTATE_FREE: 1558 AssertLogRelMsgFailed(("Invalid timer state %s: %s\n", tmTimerState(enmState), R3STRING(pTimer->pszDesc))); 1559 rc = VERR_TM_INVALID_STATE; 1560 break; 1561 1562 default: 1563 AssertMsgFailed(("Unknown timer state %d: %s\n", enmState, R3STRING(pTimer->pszDesc))); 1564 rc = VERR_TM_UNKNOWN_STATE; 1565 break; 1566 } 1567 1568 STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerSetRelativeVs), a); 1569 PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock); 1570 return rc; 1156 1571 } 1157 1572 … … 1168 1583 VMMDECL(int) TMTimerSetRelative(PTMTIMER pTimer, uint64_t cTicksToNext, uint64_t *pu64Now) 1169 1584 { 1170 STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a); 1585 PVM pVM = pTimer->CTX_SUFF(pVM); 1586 1587 /* Treat virtual sync timers specially. */ 1588 if (pTimer->enmClock == TMCLOCK_VIRTUAL_SYNC) 1589 return tmTimerVirtualSyncSetRelative(pVM, pTimer, cTicksToNext, pu64Now); 1590 1591 STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a); 1171 1592 TMTIMER_ASSERT_CRITSECT(pTimer); 1172 PVM pVM = pTimer->CTX_SUFF(pVM); 1173 int rc;1593 1594 DBGFTRACE_U64_TAG2(pVM, cTicksToNext, "TMTimerSetRelative", R3STRING(pTimer->pszDesc)); 1174 1595 1175 1596 #ifdef VBOX_WITH_STATISTICS 1176 /* Gather optimization info. */ 1597 /* 1598 * Gather optimization info. 1599 */ 1177 1600 STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelative); 1178 1601 TMTIMERSTATE enmOrgState = pTimer->enmState; … … 1225 1648 * Unoptimized path. 1226 1649 */ 1650 int rc; 1227 1651 TMCLOCK const enmClock = pTimer->enmClock; 1228 bool fOwnVirtSyncLock;1229 fOwnVirtSyncLock = !fOwnTMLock1230 && enmClock == TMCLOCK_VIRTUAL_SYNC1231 && RT_SUCCESS(tmVirtualSyncTryLock(pVM));1232 1652 for (int cRetries = 1000; ; cRetries--) 1233 1653 { … … 1358 1778 */ 1359 1779 if (!fOwnTMLock) 1360 {1361 1780 fOwnTMLock = RT_SUCCESS_NP(tmTimerTryLock(pVM)); 1362 if ( !fOwnTMLock1363 && enmClock == TMCLOCK_VIRTUAL_SYNC1364 && !fOwnVirtSyncLock)1365 fOwnVirtSyncLock = RT_SUCCESS_NP(tmVirtualSyncTryLock(pVM));1366 }1367 1781 1368 1782 } /* for (;;) */ … … 1371 1785 * Clean up and return. 1372 1786 */ 1373 if (fOwnVirtSyncLock)1374 tmVirtualSyncUnlock(pVM);1375 1787 if (fOwnTMLock) 1376 1788 tmTimerUnlock(pVM); 1377 1378 if ( !fOwnTMLock1379 && !fOwnVirtSyncLock1380 && enmClock == TMCLOCK_VIRTUAL_SYNC)1381 STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeRacyVirtSync);1382 1789 1383 1790 STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a); … … 1518 1925 1519 1926 /** 1927 * TMTimerStop for the virtual sync timer queue. 1928 * 1929 * This employs a greatly simplified state machine by always acquiring the 1930 * queue lock and bypassing the scheduling list. 1931 * 1932 * @returns VBox status code 1933 * @param pVM The VM handle. 1934 * @param pTimer The timer handle. 1935 */ 1936 static int tmTimerVirtualSyncStop(PVM pVM, PTMTIMER pTimer) 1937 { 1938 STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatTimerStopVs), a); 1939 VM_ASSERT_EMT(pVM); 1940 int rc = PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VINF_SUCCESS); 1941 AssertRCReturn(rc, rc); 1942 1943 /* Reset the HZ hint. */ 1944 if (pTimer->uHzHint) 1945 { 1946 if (pTimer->uHzHint >= pVM->tm.s.uMaxHzHint) 1947 ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, true); 1948 pTimer->uHzHint = 0; 1949 } 1950 1951 /* Update the timer state. */ 1952 PTMTIMERQUEUE pQueue = &pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC]; 1953 TMTIMERSTATE enmState = pTimer->enmState; 1954 switch (enmState) 1955 { 1956 case TMTIMERSTATE_ACTIVE: 1957 tmTimerQueueUnlinkActive(pQueue, pTimer); 1958 TM_SET_STATE(pTimer, TMTIMERSTATE_STOPPED); 1959 rc = VINF_SUCCESS; 1960 break; 1961 1962 case TMTIMERSTATE_EXPIRED_DELIVER: 1963 TM_SET_STATE(pTimer, TMTIMERSTATE_STOPPED); 1964 rc = VINF_SUCCESS; 1965 break; 1966 1967 case TMTIMERSTATE_STOPPED: 1968 rc = VINF_SUCCESS; 1969 break; 1970 1971 case TMTIMERSTATE_PENDING_RESCHEDULE: 1972 case TMTIMERSTATE_PENDING_STOP: 1973 case TMTIMERSTATE_PENDING_SCHEDULE: 1974 case TMTIMERSTATE_PENDING_STOP_SCHEDULE: 1975 case TMTIMERSTATE_EXPIRED_GET_UNLINK: 1976 case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE: 1977 case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE: 1978 case TMTIMERSTATE_DESTROY: 1979 case TMTIMERSTATE_FREE: 1980 AssertLogRelMsgFailed(("Invalid timer state %s: %s\n", tmTimerState(enmState), R3STRING(pTimer->pszDesc))); 1981 rc = VERR_TM_INVALID_STATE; 1982 break; 1983 1984 default: 1985 AssertMsgFailed(("Unknown timer state %d: %s\n", enmState, R3STRING(pTimer->pszDesc))); 1986 rc = VERR_TM_UNKNOWN_STATE; 1987 break; 1988 } 1989 1990 STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerStopVs), a); 1991 PDMCritSectLeave(&pVM->tm.s.VirtualSyncLock); 1992 return rc; 1993 } 1994 1995 1996 /** 1520 1997 * Stop the timer. 1521 1998 * Use TMR3TimerArm() to "un-stop" the timer. … … 1526 2003 VMMDECL(int) TMTimerStop(PTMTIMER pTimer) 1527 2004 { 1528 STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a); 2005 PVM pVM = pTimer->CTX_SUFF(pVM); 2006 2007 /* Treat virtual sync timers specially. */ 2008 if (pTimer->enmClock == TMCLOCK_VIRTUAL_SYNC) 2009 return tmTimerVirtualSyncStop(pVM, pTimer); 2010 2011 STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatTimerStop), a); 1529 2012 TMTIMER_ASSERT_CRITSECT(pTimer); 1530 2013 1531 /* Reset the HZ hint. */ 2014 /* 2015 * Reset the HZ hint. 2016 */ 1532 2017 if (pTimer->uHzHint) 1533 2018 { 1534 PVM pVM = pTimer->CTX_SUFF(pVM);1535 2019 if (pTimer->uHzHint >= pVM->tm.s.uMaxHzHint) 1536 2020 ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, true); … … 1557 2041 case TMTIMERSTATE_PENDING_STOP: 1558 2042 case TMTIMERSTATE_PENDING_STOP_SCHEDULE: 1559 STAM_PROFILE_STOP(&p Timer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);2043 STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerStop), a); 1560 2044 return VINF_SUCCESS; 1561 2045 … … 1564 2048 { 1565 2049 tmSchedule(pTimer); 1566 STAM_PROFILE_STOP(&p Timer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);2050 STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerStop), a); 1567 2051 return VINF_SUCCESS; 1568 2052 } … … 1572 2056 { 1573 2057 tmSchedule(pTimer); 1574 STAM_PROFILE_STOP(&p Timer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);2058 STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerStop), a); 1575 2059 return VINF_SUCCESS; 1576 2060 } … … 1581 2065 { 1582 2066 tmSchedule(pTimer); 1583 STAM_PROFILE_STOP(&p Timer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);2067 STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerStop), a); 1584 2068 return VINF_SUCCESS; 1585 2069 } … … 1611 2095 1612 2096 AssertMsgFailed(("Failed waiting for stable state. state=%d (%s)\n", pTimer->enmState, R3STRING(pTimer->pszDesc))); 1613 STAM_PROFILE_STOP(&p Timer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);2097 STAM_PROFILE_STOP(&pVM->tm.s.CTX_SUFF_Z(StatTimerStop), a); 1614 2098 return VERR_INTERNAL_ERROR; 1615 2099 } … … 1625 2109 VMMDECL(uint64_t) TMTimerGet(PTMTIMER pTimer) 1626 2110 { 2111 PVM pVM = pTimer->CTX_SUFF(pVM); 2112 1627 2113 uint64_t u64; 1628 PVM pVM = pTimer->CTX_SUFF(pVM);1629 1630 2114 switch (pTimer->enmClock) 1631 2115 { … … 1641 2125 default: 1642 2126 AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock)); 1643 return ~(uint64_t)0;2127 return UINT64_MAX; 1644 2128 } 1645 2129 //Log2(("TMTimerGet: returns %'RU64 (pTimer=%p:{.enmState=%s, .pszDesc='%s'})\n", … … 1801 2285 * @returns timer clock ticks. 1802 2286 * @param pTimer Timer handle as returned by one of the create functions. 1803 * @param u64NanoTSThe nanosecond value ticks to convert.2287 * @param cNanoSecs The nanosecond value ticks to convert. 1804 2288 * @remark There could be rounding and overflow errors here. 1805 2289 */ 1806 VMMDECL(uint64_t) TMTimerFromNano(PTMTIMER pTimer, uint64_t u64NanoTS)2290 VMMDECL(uint64_t) TMTimerFromNano(PTMTIMER pTimer, uint64_t cNanoSecs) 1807 2291 { 1808 2292 switch (pTimer->enmClock) … … 1811 2295 case TMCLOCK_VIRTUAL_SYNC: 1812 2296 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000); 1813 return u64NanoTS;2297 return cNanoSecs; 1814 2298 1815 2299 case TMCLOCK_REAL: 1816 2300 AssertCompile(TMCLOCK_FREQ_REAL == 1000); 1817 return u64NanoTS/ 1000000;2301 return cNanoSecs / 1000000; 1818 2302 1819 2303 default: … … 1829 2313 * @returns timer clock ticks. 1830 2314 * @param pTimer Timer handle as returned by one of the create functions. 1831 * @param u64MicroTSThe microsecond value ticks to convert.2315 * @param cMicroSecs The microsecond value ticks to convert. 1832 2316 * @remark There could be rounding and overflow errors here. 1833 2317 */ 1834 VMMDECL(uint64_t) TMTimerFromMicro(PTMTIMER pTimer, uint64_t u64MicroTS)2318 VMMDECL(uint64_t) TMTimerFromMicro(PTMTIMER pTimer, uint64_t cMicroSecs) 1835 2319 { 1836 2320 switch (pTimer->enmClock) … … 1839 2323 case TMCLOCK_VIRTUAL_SYNC: 1840 2324 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000); 1841 return u64MicroTS* 1000;2325 return cMicroSecs * 1000; 1842 2326 1843 2327 case TMCLOCK_REAL: 1844 2328 AssertCompile(TMCLOCK_FREQ_REAL == 1000); 1845 return u64MicroTS/ 1000;2329 return cMicroSecs / 1000; 1846 2330 1847 2331 default: … … 1857 2341 * @returns timer clock ticks. 1858 2342 * @param pTimer Timer handle as returned by one of the create functions. 1859 * @param u64MilliTSThe millisecond value ticks to convert.2343 * @param cMilliSecs The millisecond value ticks to convert. 1860 2344 * @remark There could be rounding and overflow errors here. 1861 2345 */ 1862 VMMDECL(uint64_t) TMTimerFromMilli(PTMTIMER pTimer, uint64_t u64MilliTS)2346 VMMDECL(uint64_t) TMTimerFromMilli(PTMTIMER pTimer, uint64_t cMilliSecs) 1863 2347 { 1864 2348 switch (pTimer->enmClock) … … 1867 2351 case TMCLOCK_VIRTUAL_SYNC: 1868 2352 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000); 1869 return u64MilliTS* 1000000;2353 return cMilliSecs * 1000000; 1870 2354 1871 2355 case TMCLOCK_REAL: 1872 2356 AssertCompile(TMCLOCK_FREQ_REAL == 1000); 1873 return u64MilliTS;2357 return cMilliSecs; 1874 2358 1875 2359 default: … … 1951 2435 VMMDECL(bool) TMTimerIsActive(PTMTIMER pTimer) 1952 2436 { 1953 TMTIMERSTATE 2437 TMTIMERSTATE enmState = pTimer->enmState; 1954 2438 switch (enmState) 1955 2439 { … … 1985 2469 return false; 1986 2470 } 2471 } 2472 2473 2474 /** 2475 * Gets the current warp drive percent. 2476 * 2477 * @returns The warp drive percent. 2478 * @param pVM The VM handle. 2479 */ 2480 VMMDECL(uint32_t) TMGetWarpDrive(PVM pVM) 2481 { 2482 return pVM->tm.s.u32VirtualWarpDrivePercentage; 1987 2483 } 1988 2484 … … 2019 2515 #undef CASE 2020 2516 } 2021 }2022 2023 2024 /**2025 * Schedules the given timer on the given queue.2026 *2027 * @param pQueue The timer queue.2028 * @param pTimer The timer that needs scheduling.2029 *2030 * @remarks Called while owning the lock.2031 */2032 DECLINLINE(void) tmTimerQueueScheduleOne(PTMTIMERQUEUE pQueue, PTMTIMER pTimer)2033 {2034 /*2035 * Processing.2036 */2037 unsigned cRetries = 2;2038 do2039 {2040 TMTIMERSTATE enmState = pTimer->enmState;2041 switch (enmState)2042 {2043 /*2044 * Reschedule timer (in the active list).2045 */2046 case TMTIMERSTATE_PENDING_RESCHEDULE:2047 {2048 if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_SCHEDULE, TMTIMERSTATE_PENDING_RESCHEDULE)))2049 break; /* retry */2050 2051 const PTMTIMER pPrev = TMTIMER_GET_PREV(pTimer);2052 const PTMTIMER pNext = TMTIMER_GET_NEXT(pTimer);2053 if (pPrev)2054 TMTIMER_SET_NEXT(pPrev, pNext);2055 else2056 {2057 TMTIMER_SET_HEAD(pQueue, pNext);2058 pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX;2059 }2060 if (pNext)2061 TMTIMER_SET_PREV(pNext, pPrev);2062 pTimer->offNext = 0;2063 pTimer->offPrev = 0;2064 /* fall thru */2065 }2066 2067 /*2068 * Schedule timer (insert into the active list).2069 */2070 case TMTIMERSTATE_PENDING_SCHEDULE:2071 {2072 Assert(!pTimer->offNext); Assert(!pTimer->offPrev);2073 if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_ACTIVE, TMTIMERSTATE_PENDING_SCHEDULE)))2074 break; /* retry */2075 2076 PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue);2077 if (pCur)2078 {2079 const uint64_t u64Expire = pTimer->u64Expire;2080 for (;; pCur = TMTIMER_GET_NEXT(pCur))2081 {2082 if (pCur->u64Expire > u64Expire)2083 {2084 const PTMTIMER pPrev = TMTIMER_GET_PREV(pCur);2085 TMTIMER_SET_NEXT(pTimer, pCur);2086 TMTIMER_SET_PREV(pTimer, pPrev);2087 if (pPrev)2088 TMTIMER_SET_NEXT(pPrev, pTimer);2089 else2090 {2091 TMTIMER_SET_HEAD(pQueue, pTimer);2092 pQueue->u64Expire = u64Expire;2093 }2094 TMTIMER_SET_PREV(pCur, pTimer);2095 return;2096 }2097 if (!pCur->offNext)2098 {2099 TMTIMER_SET_NEXT(pCur, pTimer);2100 TMTIMER_SET_PREV(pTimer, pCur);2101 return;2102 }2103 }2104 }2105 else2106 {2107 TMTIMER_SET_HEAD(pQueue, pTimer);2108 pQueue->u64Expire = pTimer->u64Expire;2109 }2110 return;2111 }2112 2113 /*2114 * Stop the timer in active list.2115 */2116 case TMTIMERSTATE_PENDING_STOP:2117 {2118 if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_STOP_SCHEDULE, TMTIMERSTATE_PENDING_STOP)))2119 break; /* retry */2120 2121 const PTMTIMER pPrev = TMTIMER_GET_PREV(pTimer);2122 const PTMTIMER pNext = TMTIMER_GET_NEXT(pTimer);2123 if (pPrev)2124 TMTIMER_SET_NEXT(pPrev, pNext);2125 else2126 {2127 TMTIMER_SET_HEAD(pQueue, pNext);2128 pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX;2129 }2130 if (pNext)2131 TMTIMER_SET_PREV(pNext, pPrev);2132 pTimer->offNext = 0;2133 pTimer->offPrev = 0;2134 /* fall thru */2135 }2136 2137 /*2138 * Stop the timer (not on the active list).2139 */2140 case TMTIMERSTATE_PENDING_STOP_SCHEDULE:2141 Assert(!pTimer->offNext); Assert(!pTimer->offPrev);2142 if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_STOPPED, TMTIMERSTATE_PENDING_STOP_SCHEDULE)))2143 break;2144 return;2145 2146 /*2147 * The timer is pending destruction by TMR3TimerDestroy, our caller.2148 * Nothing to do here.2149 */2150 case TMTIMERSTATE_DESTROY:2151 break;2152 2153 /*2154 * Postpone these until they get into the right state.2155 */2156 case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:2157 case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:2158 tmTimerLink(pQueue, pTimer);2159 STAM_COUNTER_INC(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatPostponed));2160 return;2161 2162 /*2163 * None of these can be in the schedule.2164 */2165 case TMTIMERSTATE_FREE:2166 case TMTIMERSTATE_STOPPED:2167 case TMTIMERSTATE_ACTIVE:2168 case TMTIMERSTATE_EXPIRED_GET_UNLINK:2169 case TMTIMERSTATE_EXPIRED_DELIVER:2170 default:2171 AssertMsgFailed(("Timer (%p) in the scheduling list has an invalid state %s (%d)!",2172 pTimer, tmTimerState(pTimer->enmState), pTimer->enmState));2173 return;2174 }2175 } while (cRetries-- > 0);2176 }2177 2178 2179 /**2180 * Schedules the specified timer queue.2181 *2182 * @param pVM The VM to run the timers for.2183 * @param pQueue The queue to schedule.2184 *2185 * @remarks Called while owning the lock.2186 */2187 void tmTimerQueueSchedule(PVM pVM, PTMTIMERQUEUE pQueue)2188 {2189 TM_ASSERT_LOCK(pVM);2190 2191 /*2192 * Dequeue the scheduling list and iterate it.2193 */2194 int32_t offNext = ASMAtomicXchgS32(&pQueue->offSchedule, 0);2195 Log2(("tmTimerQueueSchedule: pQueue=%p:{.enmClock=%d, offNext=%RI32, .u64Expired=%'RU64}\n", pQueue, pQueue->enmClock, offNext, pQueue->u64Expire));2196 if (!offNext)2197 return;2198 PTMTIMER pNext = (PTMTIMER)((intptr_t)pQueue + offNext);2199 while (pNext)2200 {2201 /*2202 * Unlink the head timer and find the next one.2203 */2204 PTMTIMER pTimer = pNext;2205 pNext = pNext->offScheduleNext ? (PTMTIMER)((intptr_t)pNext + pNext->offScheduleNext) : NULL;2206 pTimer->offScheduleNext = 0;2207 2208 /*2209 * Do the scheduling.2210 */2211 Log2(("tmTimerQueueSchedule: %p:{.enmState=%s, .enmClock=%d, .enmType=%d, .pszDesc=%s}\n",2212 pTimer, tmTimerState(pTimer->enmState), pTimer->enmClock, pTimer->enmType, R3STRING(pTimer->pszDesc)));2213 tmTimerQueueScheduleOne(pQueue, pTimer);2214 Log2(("tmTimerQueueSchedule: %p: new %s\n", pTimer, tmTimerState(pTimer->enmState)));2215 } /* foreach timer in current schedule batch. */2216 Log2(("tmTimerQueueSchedule: u64Expired=%'RU64\n", pQueue->u64Expire));2217 }2218 2219 2220 #ifdef VBOX_STRICT2221 /**2222 * Checks that the timer queues are sane.2223 *2224 * @param pVM VM handle.2225 *2226 * @remarks Called while owning the lock.2227 */2228 void tmTimerQueuesSanityChecks(PVM pVM, const char *pszWhere)2229 {2230 TM_ASSERT_LOCK(pVM);2231 2232 /*2233 * Check the linking of the active lists.2234 */2235 for (int i = 0; i < TMCLOCK_MAX; i++)2236 {2237 PTMTIMERQUEUE pQueue = &pVM->tm.s.CTX_SUFF(paTimerQueues)[i];2238 Assert((int)pQueue->enmClock == i);2239 PTMTIMER pPrev = NULL;2240 for (PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue); pCur; pPrev = pCur, pCur = TMTIMER_GET_NEXT(pCur))2241 {2242 AssertMsg((int)pCur->enmClock == i, ("%s: %d != %d\n", pszWhere, pCur->enmClock, i));2243 AssertMsg(TMTIMER_GET_PREV(pCur) == pPrev, ("%s: %p != %p\n", pszWhere, TMTIMER_GET_PREV(pCur), pPrev));2244 TMTIMERSTATE enmState = pCur->enmState;2245 switch (enmState)2246 {2247 case TMTIMERSTATE_ACTIVE:2248 AssertMsg( !pCur->offScheduleNext2249 || pCur->enmState != TMTIMERSTATE_ACTIVE,2250 ("%s: %RI32\n", pszWhere, pCur->offScheduleNext));2251 break;2252 case TMTIMERSTATE_PENDING_STOP:2253 case TMTIMERSTATE_PENDING_RESCHEDULE:2254 case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:2255 break;2256 default:2257 AssertMsgFailed(("%s: Invalid state enmState=%d %s\n", pszWhere, enmState, tmTimerState(enmState)));2258 break;2259 }2260 }2261 }2262 2263 2264 # ifdef IN_RING32265 /*2266 * Do the big list and check that active timers all are in the active lists.2267 */2268 PTMTIMERR3 pPrev = NULL;2269 for (PTMTIMERR3 pCur = pVM->tm.s.pCreated; pCur; pPrev = pCur, pCur = pCur->pBigNext)2270 {2271 Assert(pCur->pBigPrev == pPrev);2272 Assert((unsigned)pCur->enmClock < (unsigned)TMCLOCK_MAX);2273 2274 TMTIMERSTATE enmState = pCur->enmState;2275 switch (enmState)2276 {2277 case TMTIMERSTATE_ACTIVE:2278 case TMTIMERSTATE_PENDING_STOP:2279 case TMTIMERSTATE_PENDING_RESCHEDULE:2280 case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:2281 {2282 PTMTIMERR3 pCurAct = TMTIMER_GET_HEAD(&pVM->tm.s.CTX_SUFF(paTimerQueues)[pCur->enmClock]);2283 Assert(pCur->offPrev || pCur == pCurAct);2284 while (pCurAct && pCurAct != pCur)2285 pCurAct = TMTIMER_GET_NEXT(pCurAct);2286 Assert(pCurAct == pCur);2287 break;2288 }2289 2290 case TMTIMERSTATE_PENDING_SCHEDULE:2291 case TMTIMERSTATE_PENDING_STOP_SCHEDULE:2292 case TMTIMERSTATE_STOPPED:2293 case TMTIMERSTATE_EXPIRED_DELIVER:2294 {2295 Assert(!pCur->offNext);2296 Assert(!pCur->offPrev);2297 for (PTMTIMERR3 pCurAct = TMTIMER_GET_HEAD(&pVM->tm.s.CTX_SUFF(paTimerQueues)[pCur->enmClock]);2298 pCurAct;2299 pCurAct = TMTIMER_GET_NEXT(pCurAct))2300 {2301 Assert(pCurAct != pCur);2302 Assert(TMTIMER_GET_NEXT(pCurAct) != pCur);2303 Assert(TMTIMER_GET_PREV(pCurAct) != pCur);2304 }2305 break;2306 }2307 2308 /* ignore */2309 case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:2310 break;2311 2312 /* shouldn't get here! */2313 case TMTIMERSTATE_EXPIRED_GET_UNLINK:2314 case TMTIMERSTATE_DESTROY:2315 default:2316 AssertMsgFailed(("Invalid state enmState=%d %s\n", enmState, tmTimerState(enmState)));2317 break;2318 }2319 }2320 # endif /* IN_RING3 */2321 }2322 #endif /* !VBOX_STRICT */2323 2324 2325 /**2326 * Gets the current warp drive percent.2327 *2328 * @returns The warp drive percent.2329 * @param pVM The VM handle.2330 */2331 VMMDECL(uint32_t) TMGetWarpDrive(PVM pVM)2332 {2333 return pVM->tm.s.u32VirtualWarpDrivePercentage;2334 2517 } 2335 2518 -
trunk/src/VBox/VMM/VMMAll/TMAllVirtual.cpp
r37439 r37517 462 462 */ 463 463 u64 -= off; 464 465 uint64_t u64Last = ASMAtomicUoReadU64(&pVM->tm.s.u64VirtualSync); 466 if (u64Last > u64) 467 { 468 u64 = u64Last + 1; 469 STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetAdjLast); 470 } 471 464 472 uint64_t u64Expire = ASMAtomicReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire); 465 473 if (u64 < u64Expire) 466 474 { 475 ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSync, u64); 467 476 if (fUpdateOff) 468 477 ASMAtomicWriteU64(&pVM->tm.s.offVirtualSync, off); … … 551 560 */ 552 561 u64 -= off; 562 563 uint64_t u64Last = ASMAtomicUoReadU64(&pVM->tm.s.u64VirtualSync); 564 if (u64Last > u64) 565 { 566 u64 = u64Last + 1; 567 STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetAdjLast); 568 } 569 553 570 uint64_t u64Expire = ASMAtomicReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire); 554 571 if (u64 < u64Expire) 555 572 { 573 ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSync, u64); 556 574 tmVirtualSyncUnlock(pVM); 557 575 if (pcNsToDeadline) … … 632 650 } 633 651 } 652 653 /* 654 * If we can get the lock, get it. The result is much more reliable. 655 * 656 * Note! This is where all clock source devices branch off because they 657 * will be owning the lock already. The 'else' is taken by code 658 * which is less picky or hasn't been adjusted yet 659 */ 660 if (tmVirtualSyncTryLock(pVM) == VINF_SUCCESS) 661 return tmVirtualSyncGetLocked(pVM, u64, pcNsToDeadline); 634 662 635 663 /* … … 773 801 */ 774 802 u64 -= off; 803 /** @todo u64VirtualSyncLast */ 775 804 uint64_t u64Expire = ASMAtomicReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire); 776 805 if (u64 >= u64Expire) -
trunk/src/VBox/VMM/VMMR3/TM.cpp
r37466 r37517 127 127 #include <VBox/vmm/ssm.h> 128 128 #include <VBox/vmm/dbgf.h> 129 #include <VBox/vmm/dbgftrace.h> 129 130 #include <VBox/vmm/rem.h> 130 131 #include <VBox/vmm/pdmapi.h> … … 147 148 #include <iprt/string.h> 148 149 #include <iprt/env.h> 150 151 #include "TMInline.h" 149 152 150 153 … … 617 620 STAM_REG(pVM, &pVM->tm.s.StatScheduleSetFF, STAMTYPE_COUNTER, "/TM/ScheduleSetFF", STAMUNIT_OCCURENCES, "The number of times the timer FF was set instead of doing scheduling."); 618 621 619 STAM_REG(pVM, &pVM->tm.s.StatTimerSet, STAMTYPE_COUNTER, "/TM/TimerSet", STAMUNIT_OCCURENCES, "Calls ");622 STAM_REG(pVM, &pVM->tm.s.StatTimerSet, STAMTYPE_COUNTER, "/TM/TimerSet", STAMUNIT_OCCURENCES, "Calls, except virtual sync timers"); 620 623 STAM_REG(pVM, &pVM->tm.s.StatTimerSetOpt, STAMTYPE_COUNTER, "/TM/TimerSet/Opt", STAMUNIT_OCCURENCES, "Optimized path taken."); 621 624 STAM_REG(pVM, &pVM->tm.s.StatTimerSetR3, STAMTYPE_PROFILE, "/TM/TimerSet/R3", STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSet calls made in ring-3."); … … 630 633 STAM_REG(pVM, &pVM->tm.s.StatTimerSetStStopped, STAMTYPE_COUNTER, "/TM/TimerSet/StStopped", STAMUNIT_OCCURENCES, "STOPPED"); 631 634 632 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelative, STAMTYPE_COUNTER, "/TM/TimerSetRelative", STAMUNIT_OCCURENCES, "Calls"); 635 STAM_REG(pVM, &pVM->tm.s.StatTimerSetVs, STAMTYPE_COUNTER, "/TM/TimerSetVs", STAMUNIT_OCCURENCES, "TMTimerSet calls on virtual sync timers"); 636 STAM_REG(pVM, &pVM->tm.s.StatTimerSetVsR3, STAMTYPE_PROFILE, "/TM/TimerSetVs/R3", STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSet calls made in ring-3 on virtual sync timers."); 637 STAM_REG(pVM, &pVM->tm.s.StatTimerSetVsRZ, STAMTYPE_PROFILE, "/TM/TimerSetVs/RZ", STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSet calls made in ring-0 / RC on virtual sync timers."); 638 STAM_REG(pVM, &pVM->tm.s.StatTimerSetVsStActive, STAMTYPE_COUNTER, "/TM/TimerSetVs/StActive", STAMUNIT_OCCURENCES, "ACTIVE"); 639 STAM_REG(pVM, &pVM->tm.s.StatTimerSetVsStExpDeliver, STAMTYPE_COUNTER, "/TM/TimerSetVs/StExpDeliver", STAMUNIT_OCCURENCES, "EXPIRED_DELIVER"); 640 STAM_REG(pVM, &pVM->tm.s.StatTimerSetVsStStopped, STAMTYPE_COUNTER, "/TM/TimerSetVs/StStopped", STAMUNIT_OCCURENCES, "STOPPED"); 641 642 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelative, STAMTYPE_COUNTER, "/TM/TimerSetRelative", STAMUNIT_OCCURENCES, "Calls, except virtual sync timers"); 633 643 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeOpt, STAMTYPE_COUNTER, "/TM/TimerSetRelative/Opt", STAMUNIT_OCCURENCES, "Optimized path taken."); 634 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeR3, STAMTYPE_PROFILE, "/TM/TimerSetRelative/R3", STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetRelative calls made in ring-3."); 635 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeRZ, STAMTYPE_PROFILE, "/TM/TimerSetRelative/RZ", STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetReltaive calls made in ring-0 / RC."); 636 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeRacyVirtSync, STAMTYPE_COUNTER, "/TM/TimerSetRelative/RacyVirtSync", STAMUNIT_OCCURENCES, "Potentially racy virtual sync timer update."); 644 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeR3, STAMTYPE_PROFILE, "/TM/TimerSetRelative/R3", STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetRelative calls made in ring-3 (sans virtual sync)."); 645 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeRZ, STAMTYPE_PROFILE, "/TM/TimerSetRelative/RZ", STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetReltaive calls made in ring-0 / RC (sans virtual sync)."); 637 646 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStActive, STAMTYPE_COUNTER, "/TM/TimerSetRelative/StActive", STAMUNIT_OCCURENCES, "ACTIVE"); 638 647 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStExpDeliver, STAMTYPE_COUNTER, "/TM/TimerSetRelative/StExpDeliver", STAMUNIT_OCCURENCES, "EXPIRED_DELIVER"); … … 644 653 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStStopped, STAMTYPE_COUNTER, "/TM/TimerSetRelative/StStopped", STAMUNIT_OCCURENCES, "STOPPED"); 645 654 655 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeVs, STAMTYPE_COUNTER, "/TM/TimerSetRelativeVs", STAMUNIT_OCCURENCES, "TMTimerSetRelative calls on virtual sync timers"); 656 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeVsR3, STAMTYPE_PROFILE, "/TM/TimerSetRelativeVs/R3", STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetRelative calls made in ring-3 on virtual sync timers."); 657 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeVsRZ, STAMTYPE_PROFILE, "/TM/TimerSetRelativeVs/RZ", STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetReltaive calls made in ring-0 / RC on virtual sync timers."); 658 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeVsStActive, STAMTYPE_COUNTER, "/TM/TimerSetRelativeVs/StActive", STAMUNIT_OCCURENCES, "ACTIVE"); 659 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeVsStExpDeliver, STAMTYPE_COUNTER, "/TM/TimerSetRelativeVs/StExpDeliver", STAMUNIT_OCCURENCES, "EXPIRED_DELIVER"); 660 STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeVsStStopped, STAMTYPE_COUNTER, "/TM/TimerSetRelativeVs/StStopped", STAMUNIT_OCCURENCES, "STOPPED"); 661 646 662 STAM_REG(pVM, &pVM->tm.s.StatTimerStopR3, STAMTYPE_PROFILE, "/TM/TimerStopR3", STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerStop calls made in ring-3."); 647 663 STAM_REG(pVM, &pVM->tm.s.StatTimerStopRZ, STAMTYPE_PROFILE, "/TM/TimerStopRZ", STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerStop calls made in ring-0 / RC."); … … 650 666 STAM_REG(pVM, &pVM->tm.s.StatVirtualGetSetFF, STAMTYPE_COUNTER, "/TM/VirtualGetSetFF", STAMUNIT_OCCURENCES, "Times we set the FF when calling TMTimerGet."); 651 667 STAM_REG(pVM, &pVM->tm.s.StatVirtualSyncGet, STAMTYPE_COUNTER, "/TM/VirtualSyncGet", STAMUNIT_OCCURENCES, "The number of times tmVirtualSyncGetEx was called."); 668 STAM_REG(pVM, &pVM->tm.s.StatVirtualSyncGetAdjLast, STAMTYPE_COUNTER, "/TM/VirtualSyncGet/AdjLast", STAMUNIT_OCCURENCES, "Times we've adjusted against the last returned time stamp ."); 652 669 STAM_REG(pVM, &pVM->tm.s.StatVirtualSyncGetELoop, STAMTYPE_COUNTER, "/TM/VirtualSyncGet/ELoop", STAMUNIT_OCCURENCES, "Times tmVirtualSyncGetEx has given up getting a consistent virtual sync data set."); 653 670 STAM_REG(pVM, &pVM->tm.s.StatVirtualSyncGetExpired, STAMTYPE_COUNTER, "/TM/VirtualSyncGet/Expired", STAMUNIT_OCCURENCES, "Times tmVirtualSyncGetEx encountered an expired timer stopping the clock."); … … 1898 1915 VMCPU_FF_CLEAR(pVCpuDst, VMCPU_FF_TIMER); /* Clear the FF once we started working for real. */ 1899 1916 1900 if (pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC].offSchedule) 1901 tmTimerQueueSchedule(pVM, &pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC]); 1917 Assert(!pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC].offSchedule); 1902 1918 tmR3TimerQueueRunVirtualSync(pVM); 1903 1919 if (pVM->tm.s.fVirtualSyncTicking) /** @todo move into tmR3TimerQueueRunVirtualSync - FIXME */ … … 2034 2050 * @param pVM The VM to run the timers for. 2035 2051 * 2036 * @remarks The caller must own both the TM/EMT and the Virtual Sync locks. 2052 * @remarks The caller must the Virtual Sync lock. Owning the TM lock is no 2053 * longer important. 2037 2054 */ 2038 2055 static void tmR3TimerQueueRunVirtualSync(PVM pVM) … … 2040 2057 PTMTIMERQUEUE const pQueue = &pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC]; 2041 2058 VM_ASSERT_EMT(pVM); 2059 Assert(PDMCritSectIsOwner(&pVM->tm.s.VirtualSyncLock)); 2042 2060 2043 2061 /* … … 2103 2121 u64Now = u64VirtualNow - off; 2104 2122 2123 /* Adjust against last returned time. */ 2124 uint64_t u64Last = ASMAtomicUoReadU64(&pVM->tm.s.u64VirtualSync); 2125 if (u64Last > u64Now) 2126 { 2127 u64Now = u64Last + 1; 2128 STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetAdjLast); 2129 } 2130 2105 2131 /* Check if stopped by expired timer. */ 2106 2132 uint64_t u64Expire = pNext->u64Expire; … … 2113 2139 Log4(("TM: %'RU64/-%'8RU64: exp tmr [tmR3TimerQueueRunVirtualSync]\n", u64Now, u64VirtualNow - u64Now - offSyncGivenUp)); 2114 2140 } 2115 else if (fUpdateStuff)2141 else 2116 2142 { 2117 ASMAtomicWriteU64(&pVM->tm.s.offVirtualSync, off); 2118 ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSyncCatchUpPrev, u64VirtualNow); 2119 if (fStopCatchup) 2143 ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSync, u64Now); 2144 if (fUpdateStuff) 2120 2145 { 2121 ASMAtomicWriteBool(&pVM->tm.s.fVirtualSyncCatchUp, false); 2122 Log4(("TM: %'RU64/0: caught up [tmR3TimerQueueRunVirtualSync]\n", u64VirtualNow)); 2146 ASMAtomicWriteU64(&pVM->tm.s.offVirtualSync, off); 2147 ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSyncCatchUpPrev, u64VirtualNow); 2148 ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSync, u64Now); 2149 if (fStopCatchup) 2150 { 2151 ASMAtomicWriteBool(&pVM->tm.s.fVirtualSyncCatchUp, false); 2152 Log4(("TM: %'RU64/0: caught up [tmR3TimerQueueRunVirtualSync]\n", u64VirtualNow)); 2153 } 2123 2154 } 2124 2155 } … … 2148 2179 while (pNext && pNext->u64Expire <= u64Max) 2149 2180 { 2150 PTMTIMER pTimer = pNext; 2181 /* Advance */ 2182 PTMTIMER pTimer = pNext; 2151 2183 pNext = TMTIMER_GET_NEXT(pTimer); 2152 PPDMCRITSECT pCritSect = pTimer->pCritSect; 2184 2185 /* Take the associated lock. */ 2186 PPDMCRITSECT pCritSect = pTimer->pCritSect; 2153 2187 if (pCritSect) 2154 2188 PDMCritSectEnter(pCritSect, VERR_INTERNAL_ERROR); 2189 2155 2190 Log2(("tmR3TimerQueueRun: %p:{.enmState=%s, .enmClock=%d, .enmType=%d, u64Expire=%llx (now=%llx) .pszDesc=%s}\n", 2156 2191 pTimer, tmTimerState(pTimer->enmState), pTimer->enmClock, pTimer->enmType, pTimer->u64Expire, u64Now, pTimer->pszDesc)); 2157 bool fRc; 2158 TM_TRY_SET_STATE(pTimer, TMTIMERSTATE_EXPIRED_GET_UNLINK, TMTIMERSTATE_ACTIVE, fRc); 2159 if (fRc) 2160 { 2161 /* unlink */ 2162 const PTMTIMER pPrev = TMTIMER_GET_PREV(pTimer); 2163 if (pPrev) 2164 TMTIMER_SET_NEXT(pPrev, pNext); 2165 else 2166 { 2167 TMTIMER_SET_HEAD(pQueue, pNext); 2168 pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX; 2169 } 2170 if (pNext) 2171 TMTIMER_SET_PREV(pNext, pPrev); 2172 pTimer->offNext = 0; 2173 pTimer->offPrev = 0; 2174 2175 /* advance the clock - don't permit timers to be out of order or armed in the 'past'. */ 2192 2193 /* Advance the clock - don't permit timers to be out of order or armed 2194 in the 'past'. */ 2176 2195 #ifdef DEBUG_bird 2177 2196 #ifdef VBOX_STRICT 2178 2179 2197 AssertMsg(pTimer->u64Expire >= u64Prev, ("%'RU64 < %'RU64 %s\n", pTimer->u64Expire, u64Prev, pTimer->pszDesc)); 2198 u64Prev = pTimer->u64Expire; 2180 2199 #endif 2181 2200 #endif 2182 ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSync, pTimer->u64Expire); 2183 ASMAtomicWriteBool(&pVM->tm.s.fVirtualSyncTicking, false); 2184 2185 /* fire */ 2186 TM_SET_STATE(pTimer, TMTIMERSTATE_EXPIRED_DELIVER); 2187 switch (pTimer->enmType) 2188 { 2189 case TMTIMERTYPE_DEV: pTimer->u.Dev.pfnTimer(pTimer->u.Dev.pDevIns, pTimer, pTimer->pvUser); break; 2190 case TMTIMERTYPE_USB: pTimer->u.Usb.pfnTimer(pTimer->u.Usb.pUsbIns, pTimer, pTimer->pvUser); break; 2191 case TMTIMERTYPE_DRV: pTimer->u.Drv.pfnTimer(pTimer->u.Drv.pDrvIns, pTimer, pTimer->pvUser); break; 2192 case TMTIMERTYPE_INTERNAL: pTimer->u.Internal.pfnTimer(pVM, pTimer, pTimer->pvUser); break; 2193 case TMTIMERTYPE_EXTERNAL: pTimer->u.External.pfnTimer(pTimer->pvUser); break; 2194 default: 2195 AssertMsgFailed(("Invalid timer type %d (%s)\n", pTimer->enmType, pTimer->pszDesc)); 2196 break; 2197 } 2198 2199 /* Change the state if it wasn't changed already in the handler. 2200 Reset the Hz hint too since this is the same as TMTimerStop. */ 2201 TM_TRY_SET_STATE(pTimer, TMTIMERSTATE_STOPPED, TMTIMERSTATE_EXPIRED_DELIVER, fRc); 2202 if (fRc && pTimer->uHzHint) 2203 { 2204 if (pTimer->uHzHint >= pVM->tm.s.uMaxHzHint) 2205 ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, true); 2206 pTimer->uHzHint = 0; 2207 } 2208 Log2(("tmR3TimerQueueRun: new state %s\n", tmTimerState(pTimer->enmState))); 2201 ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSync, pTimer->u64Expire); 2202 ASMAtomicWriteBool(&pVM->tm.s.fVirtualSyncTicking, false); 2203 2204 /* Unlink it, change the state and do the callout. */ 2205 tmTimerQueueUnlinkActive(pQueue, pTimer); 2206 TM_SET_STATE(pTimer, TMTIMERSTATE_EXPIRED_DELIVER); 2207 switch (pTimer->enmType) 2208 { 2209 case TMTIMERTYPE_DEV: pTimer->u.Dev.pfnTimer(pTimer->u.Dev.pDevIns, pTimer, pTimer->pvUser); break; 2210 case TMTIMERTYPE_USB: pTimer->u.Usb.pfnTimer(pTimer->u.Usb.pUsbIns, pTimer, pTimer->pvUser); break; 2211 case TMTIMERTYPE_DRV: pTimer->u.Drv.pfnTimer(pTimer->u.Drv.pDrvIns, pTimer, pTimer->pvUser); break; 2212 case TMTIMERTYPE_INTERNAL: pTimer->u.Internal.pfnTimer(pVM, pTimer, pTimer->pvUser); break; 2213 case TMTIMERTYPE_EXTERNAL: pTimer->u.External.pfnTimer(pTimer->pvUser); break; 2214 default: 2215 AssertMsgFailed(("Invalid timer type %d (%s)\n", pTimer->enmType, pTimer->pszDesc)); 2216 break; 2209 2217 } 2218 2219 /* Change the state if it wasn't changed already in the handler. 2220 Reset the Hz hint too since this is the same as TMTimerStop. */ 2221 bool fRc; 2222 TM_TRY_SET_STATE(pTimer, TMTIMERSTATE_STOPPED, TMTIMERSTATE_EXPIRED_DELIVER, fRc); 2223 if (fRc && pTimer->uHzHint) 2224 { 2225 if (pTimer->uHzHint >= pVM->tm.s.uMaxHzHint) 2226 ASMAtomicWriteBool(&pVM->tm.s.fHzHintNeedsUpdating, true); 2227 pTimer->uHzHint = 0; 2228 } 2229 Log2(("tmR3TimerQueueRun: new state %s\n", tmTimerState(pTimer->enmState))); 2230 2231 /* Leave the associated lock. */ 2210 2232 if (pCritSect) 2211 2233 PDMCritSectLeave(pCritSect); 2212 2234 } /* run loop */ 2235 2213 2236 2214 2237 /* … … 2387 2410 Log2(("TMR3VirtualSyncFF: running queue\n")); 2388 2411 2389 if (pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC].offSchedule) 2390 tmTimerQueueSchedule(pVM, &pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC]); 2412 Assert(!pVM->tm.s.paTimerQueuesR3[TMCLOCK_VIRTUAL_SYNC].offSchedule); 2391 2413 tmR3TimerQueueRunVirtualSync(pVM); 2392 2414 if (pVM->tm.s.fVirtualSyncTicking) /** @todo move into tmR3TimerQueueRunVirtualSync - FIXME */ -
trunk/src/VBox/VMM/include/TMInternal.h
r37358 r37517 400 400 /** Alignment. */ 401 401 RTRCPTR AlignmentRCPtr; 402 /** The guest virtual timer synchronous time when fVirtualSyncTicking is cleared. */ 402 /** The guest virtual timer synchronous time when fVirtualSyncTicking is cleared. 403 * When fVirtualSyncTicking is set it holds the last time returned to 404 * the guest (while the lock was held). */ 403 405 uint64_t volatile u64VirtualSync; 404 406 /** The offset of the timer synchronous virtual clock (TMCLOCK_VIRTUAL_SYNC) relative … … 505 507 /** Lock serializing access to the timer lists. */ 506 508 PDMCRITSECT TimerCritSect; 507 /** Lock serializing access to the VirtualSync clock. */ 509 /** Lock serializing access to the VirtualSync clock and the associated 510 * timer queue. */ 508 511 PDMCRITSECT VirtualSyncLock; 509 512 … … 529 532 STAMCOUNTER StatVirtualGetSetFF; 530 533 STAMCOUNTER StatVirtualSyncGet; 534 STAMCOUNTER StatVirtualSyncGetAdjLast; 531 535 STAMCOUNTER StatVirtualSyncGetELoop; 532 536 STAMCOUNTER StatVirtualSyncGetExpired; … … 536 540 STAMCOUNTER StatVirtualPause; 537 541 STAMCOUNTER StatVirtualResume; 538 /* @} */542 /** @} */ 539 543 /** TMTimerPoll 540 544 * @{ */ … … 548 552 STAMCOUNTER StatPollVirtualSync; 549 553 /** @} */ 550 /** TMTimerSet 554 /** TMTimerSet sans virtual sync timers. 551 555 * @{ */ 552 556 STAMCOUNTER StatTimerSet; … … 562 566 STAMCOUNTER StatTimerSetStPendResched; 563 567 STAMCOUNTER StatTimerSetStOther; 564 /** @} */ 565 /** TMTimerSetRelative 568 /** @} */ 569 /** TMTimerSet on virtual sync timers. 570 * @{ */ 571 STAMCOUNTER StatTimerSetVs; 572 STAMPROFILE StatTimerSetVsRZ; 573 STAMPROFILE StatTimerSetVsR3; 574 STAMCOUNTER StatTimerSetVsStStopped; 575 STAMCOUNTER StatTimerSetVsStExpDeliver; 576 STAMCOUNTER StatTimerSetVsStActive; 577 /** @} */ 578 /** TMTimerSetRelative sans virtual sync timers 566 579 * @{ */ 567 580 STAMCOUNTER StatTimerSetRelative; … … 569 582 STAMPROFILE StatTimerSetRelativeR3; 570 583 STAMCOUNTER StatTimerSetRelativeOpt; 571 STAMCOUNTER StatTimerSetRelativeRacyVirtSync;572 584 STAMCOUNTER StatTimerSetRelativeStStopped; 573 585 STAMCOUNTER StatTimerSetRelativeStExpDeliver; … … 579 591 STAMCOUNTER StatTimerSetRelativeStOther; 580 592 /** @} */ 581 /** TMTimerStop 593 /** TMTimerSetRelative on virtual sync timers. 594 * @{ */ 595 STAMCOUNTER StatTimerSetRelativeVs; 596 STAMPROFILE StatTimerSetRelativeVsRZ; 597 STAMPROFILE StatTimerSetRelativeVsR3; 598 STAMCOUNTER StatTimerSetRelativeVsStStopped; 599 STAMCOUNTER StatTimerSetRelativeVsStExpDeliver; 600 STAMCOUNTER StatTimerSetRelativeVsStActive; 601 /** @} */ 602 /** TMTimerStop sans virtual sync. 582 603 * @{ */ 583 604 STAMPROFILE StatTimerStopRZ; 584 605 STAMPROFILE StatTimerStopR3; 606 /** @} */ 607 /** TMTimerStop on virtual sync timers. 608 * @{ */ 609 STAMPROFILE StatTimerStopVsRZ; 610 STAMPROFILE StatTimerStopVsR3; 585 611 /** @} */ 586 612 /** VirtualSync - Running and Catching Up
Note:
See TracChangeset
for help on using the changeset viewer.