Changeset 20733 in vbox for trunk/src/VBox/VMM/VMMAll/TMAll.cpp
- Timestamp:
- Jun 20, 2009 6:25:43 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/TMAll.cpp
r20120 r20733 751 751 VMMDECL(int) TMTimerSet(PTMTIMER pTimer, uint64_t u64Expire) 752 752 { 753 STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX ALLSUFF(StatTimerSet), a);753 STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSet), a); 754 754 TMTIMER_ASSERT_CRITSECT(pTimer); 755 755 … … 852 852 853 853 /** 854 * Return the current time for the specified clock, setting pu64Now if not NULL. 855 * 856 * @returns Current time. 857 * @param pVM The VM handle. 858 * @param enmClock The clock to query. 859 * @param pu64Now Optional pointer where to store the return time 860 */ 861 DECL_FORCE_INLINE(uint64_t) tmTimerSetRelativeNowWorker(PVM pVM, TMCLOCK enmClock, uint64_t *pu64Now) 862 { 863 uint64_t u64Now; 864 switch (enmClock) 865 { 866 case TMCLOCK_VIRTUAL_SYNC: 867 u64Now = TMVirtualSyncGet(pVM); 868 break; 869 case TMCLOCK_VIRTUAL: 870 u64Now = TMVirtualGet(pVM); 871 break; 872 case TMCLOCK_REAL: 873 u64Now = TMRealGet(pVM); 874 break; 875 default: 876 AssertFatalMsgFailed(("%d\n", enmClock)); 877 } 878 879 if (pu64Now) 880 *pu64Now = u64Now; 881 return u64Now; 882 } 883 884 885 /** 886 * Arm a timer with a expire time relative to the current time. 887 * 888 * @returns VBox status. 889 * @param pTimer Timer handle as returned by one of the create functions. 890 * @param cTicksToNext Clock ticks until the next time expiration. 891 * @param pu64Now Where to return the current time stamp used. 892 * Optional. 893 */ 894 VMMDECL(int) TMTimerSetRelative(PTMTIMER pTimer, uint64_t cTicksToNext, uint64_t *pu64Now) 895 { 896 STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a); 897 TMTIMER_ASSERT_CRITSECT(pTimer); 898 PVM pVM = pTimer->CTX_SUFF(pVM); 899 TMCLOCK enmClock = pTimer->enmClock; 900 bool fOwnLock = false; 901 int rc; 902 903 /** @todo find the most frequently used paths and make them skip tmSchedule and tmTimerTryWithLink. */ 904 for (int cRetries = 1000; ; cRetries--) 905 { 906 /* 907 * Try to take the appropriate lock to increase the likelyhood 908 * that we don't race timer queue running and to some extend 909 * clock queries. 910 */ 911 if (!fOwnLock) 912 { 913 if (enmClock == TMCLOCK_VIRTUAL_SYNC) 914 fOwnLock = RT_SUCCESS(tmVirtualSyncTryLock(pVM)); 915 else 916 fOwnLock = RT_SUCCESS(tmTryLock(pVM)); 917 } 918 919 /* 920 * Change to any of the SET_EXPIRE states if valid and then to SCHEDULE or RESCHEDULE. 921 */ 922 TMTIMERSTATE enmState = pTimer->enmState; 923 switch (enmState) 924 { 925 case TMTIMERSTATE_EXPIRED_DELIVER: 926 case TMTIMERSTATE_STOPPED: 927 if (tmTimerTryWithLink(pTimer, TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE, enmState)) 928 { 929 Assert(!pTimer->offPrev); 930 Assert(!pTimer->offNext); 931 pTimer->u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now); 932 Log2(("TMTimerSetRelative: %p:{.enmState=%s, .pszDesc='%s', .u64Expire=%'RU64} cRetries=%d [EXP/STOP]\n", 933 pTimer, tmTimerState(enmState), R3STRING(pTimer->pszDesc), pTimer->u64Expire, cRetries)); 934 TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_SCHEDULE); 935 tmSchedule(pTimer); 936 rc = VINF_SUCCESS; 937 break; 938 } 939 rc = VERR_TRY_AGAIN; 940 break; 941 942 case TMTIMERSTATE_PENDING_SCHEDULE: 943 case TMTIMERSTATE_PENDING_STOP_SCHEDULE: 944 if (tmTimerTry(pTimer, TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE, enmState)) 945 { 946 pTimer->u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now); 947 Log2(("TMTimerSetRelative: %p:{.enmState=%s, .pszDesc='%s', .u64Expire=%'RU64} cRetries=%d [PEND_SCHED]\n", 948 pTimer, tmTimerState(enmState), R3STRING(pTimer->pszDesc), pTimer->u64Expire, cRetries)); 949 TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_SCHEDULE); 950 tmSchedule(pTimer); 951 rc = VINF_SUCCESS; 952 break; 953 } 954 rc = VERR_TRY_AGAIN; 955 break; 956 957 958 case TMTIMERSTATE_ACTIVE: 959 if (tmTimerTryWithLink(pTimer, TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE, enmState)) 960 { 961 pTimer->u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now); 962 Log2(("TMTimerSetRelative: %p:{.enmState=%s, .pszDesc='%s', .u64Expire=%'RU64} cRetries=%d [ACTIVE]\n", 963 pTimer, tmTimerState(enmState), R3STRING(pTimer->pszDesc), pTimer->u64Expire, cRetries)); 964 TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_RESCHEDULE); 965 tmSchedule(pTimer); 966 rc = VINF_SUCCESS; 967 break; 968 } 969 rc = VERR_TRY_AGAIN; 970 break; 971 972 case TMTIMERSTATE_PENDING_RESCHEDULE: 973 case TMTIMERSTATE_PENDING_STOP: 974 if (tmTimerTry(pTimer, TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE, enmState)) 975 { 976 pTimer->u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now); 977 Log2(("TMTimerSetRelative: %p:{.enmState=%s, .pszDesc='%s', .u64Expire=%'RU64} cRetries=%d [PEND_RESCH/STOP]\n", 978 pTimer, tmTimerState(enmState), R3STRING(pTimer->pszDesc), pTimer->u64Expire, cRetries)); 979 TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_RESCHEDULE); 980 tmSchedule(pTimer); 981 rc = VINF_SUCCESS; 982 break; 983 } 984 rc = VERR_TRY_AGAIN; 985 break; 986 987 988 case TMTIMERSTATE_EXPIRED_GET_UNLINK: 989 case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE: 990 case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE: 991 #ifdef IN_RING3 992 if (!RTThreadYield()) 993 RTThreadSleep(1); 994 #else 995 /** @todo call host context and yield after a couple of iterations */ 996 #endif 997 rc = VERR_TRY_AGAIN; 998 break; 999 1000 /* 1001 * Invalid states. 1002 */ 1003 case TMTIMERSTATE_DESTROY: 1004 case TMTIMERSTATE_FREE: 1005 AssertMsgFailed(("Invalid timer state %d (%s)\n", enmState, R3STRING(pTimer->pszDesc))); 1006 rc = VERR_TM_INVALID_STATE; 1007 break; 1008 1009 default: 1010 AssertMsgFailed(("Unknown timer state %d (%s)\n", enmState, R3STRING(pTimer->pszDesc))); 1011 rc = VERR_TM_UNKNOWN_STATE; 1012 break; 1013 } 1014 1015 /* switch + loop is tedious to break out of. */ 1016 if (rc == VINF_SUCCESS) 1017 break; 1018 1019 if (rc != VERR_TRY_AGAIN) 1020 { 1021 tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now); 1022 break; 1023 } 1024 if (cRetries > 0) 1025 { 1026 AssertMsgFailed(("Failed waiting for stable state. state=%d (%s)\n", pTimer->enmState, R3STRING(pTimer->pszDesc))); 1027 rc = VERR_INTERNAL_ERROR; 1028 tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now); 1029 break; 1030 } 1031 } /* for (;;) */ 1032 1033 /* 1034 * Clean up and return. 1035 */ 1036 if (fOwnLock) 1037 { 1038 if (enmClock == TMCLOCK_VIRTUAL_SYNC) 1039 tmVirtualSyncUnlock(pVM); 1040 else 1041 tmUnlock(pVM); 1042 } 1043 1044 STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a); 1045 return rc; 1046 } 1047 1048 1049 /** 854 1050 * Arm a timer with a (new) expire time relative to current time. 855 1051 * … … 866 1062 { 867 1063 case TMCLOCK_VIRTUAL: 868 return TMTimerSet(pTimer, cMilliesToNext * (uint64_t)TMCLOCK_FREQ_VIRTUAL / 1000 + TMVirtualGet(pVM)); 1064 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000); 1065 return TMTimerSetRelative(pTimer, cMilliesToNext * UINT64_C(1000000), NULL); 1066 869 1067 case TMCLOCK_VIRTUAL_SYNC: 870 return TMTimerSet(pTimer, cMilliesToNext * (uint64_t)TMCLOCK_FREQ_VIRTUAL / 1000 + TMVirtualSyncGet(pVM)); 1068 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000); 1069 return TMTimerSetRelative(pTimer, cMilliesToNext * UINT64_C(1000000), NULL); 1070 871 1071 case TMCLOCK_REAL: 872 1072 AssertCompile(TMCLOCK_FREQ_REAL == 1000); 873 return TMTimerSet(pTimer, cMilliesToNext + TMRealGet(pVM)); 874 case TMCLOCK_TSC: 875 return TMTimerSet(pTimer, cMilliesToNext * pVM->tm.s.cTSCTicksPerSecond / 1000 + TMCpuTickGet(pVCpu)); 1073 return TMTimerSetRelative(pTimer, cMilliesToNext, NULL); 876 1074 877 1075 default: … … 898 1096 case TMCLOCK_VIRTUAL: 899 1097 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000); 900 return TMTimerSet (pTimer, cMicrosToNext * 1000 + TMVirtualGet(pVM));1098 return TMTimerSetRelative(pTimer, cMicrosToNext * 1000, NULL); 901 1099 902 1100 case TMCLOCK_VIRTUAL_SYNC: 903 1101 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000); 904 return TMTimerSet (pTimer, cMicrosToNext * 1000 + TMVirtualSyncGet(pVM));1102 return TMTimerSetRelative(pTimer, cMicrosToNext * 1000, NULL); 905 1103 906 1104 case TMCLOCK_REAL: 907 1105 AssertCompile(TMCLOCK_FREQ_REAL == 1000); 908 return TMTimerSet(pTimer, cMicrosToNext / 1000 + TMRealGet(pVM)); 909 910 case TMCLOCK_TSC: 911 return TMTimerSet(pTimer, TMTimerFromMicro(pTimer, cMicrosToNext) + TMCpuTickGet(pVCpu)); 1106 return TMTimerSetRelative(pTimer, cMicrosToNext / 1000, NULL); 912 1107 913 1108 default: … … 934 1129 case TMCLOCK_VIRTUAL: 935 1130 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000); 936 return TMTimerSet (pTimer, cNanosToNext + TMVirtualGet(pVM));1131 return TMTimerSetRelative(pTimer, cNanosToNext, NULL); 937 1132 938 1133 case TMCLOCK_VIRTUAL_SYNC: 939 1134 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000); 940 return TMTimerSet (pTimer, cNanosToNext + TMVirtualSyncGet(pVM));1135 return TMTimerSetRelative(pTimer, cNanosToNext, NULL); 941 1136 942 1137 case TMCLOCK_REAL: 943 1138 AssertCompile(TMCLOCK_FREQ_REAL == 1000); 944 return TMTimerSet(pTimer, cNanosToNext / 1000000 + TMRealGet(pVM)); 945 946 case TMCLOCK_TSC: 947 return TMTimerSet(pTimer, TMTimerFromNano(pTimer, cNanosToNext) + TMCpuTickGet(pVCpu)); 1139 return TMTimerSetRelative(pTimer, cNanosToNext / 1000000, NULL); 948 1140 949 1141 default: … … 963 1155 VMMDECL(int) TMTimerStop(PTMTIMER pTimer) 964 1156 { 965 STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX ALLSUFF(StatTimerStop), a);1157 STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a); 966 1158 TMTIMER_ASSERT_CRITSECT(pTimer); 967 1159 … … 1067 1259 u64 = TMRealGet(pVM); 1068 1260 break; 1069 case TMCLOCK_TSC:1070 {1071 PVMCPU pVCpu = &pVM->aCpus[0]; /* just take the first VCPU */1072 u64 = TMCpuTickGet(pVCpu);1073 break;1074 }1075 1261 default: 1076 1262 AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock)); … … 1099 1285 case TMCLOCK_REAL: 1100 1286 return TMCLOCK_FREQ_REAL; 1101 1102 case TMCLOCK_TSC:1103 return TMCpuTicksPerSecond(pTimer->CTX_SUFF(pVM));1104 1287 1105 1288 default: … … 1168 1351 return u64Ticks * 1000000; 1169 1352 1170 case TMCLOCK_TSC:1171 AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));1172 return 0;1173 1174 1353 default: 1175 1354 AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock)); … … 1201 1380 return u64Ticks * 1000; 1202 1381 1203 case TMCLOCK_TSC:1204 AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));1205 return 0;1206 1207 1382 default: 1208 1383 AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock)); … … 1234 1409 return u64Ticks; 1235 1410 1236 case TMCLOCK_TSC:1237 AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));1238 return 0;1239 1240 1411 default: 1241 1412 AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock)); … … 1266 1437 return u64NanoTS / 1000000; 1267 1438 1268 case TMCLOCK_TSC:1269 AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));1270 return 0;1271 1272 1439 default: 1273 1440 AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock)); … … 1298 1465 return u64MicroTS / 1000; 1299 1466 1300 case TMCLOCK_TSC:1301 AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));1302 return 0;1303 1304 1467 default: 1305 1468 AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock)); … … 1329 1492 AssertCompile(TMCLOCK_FREQ_REAL == 1000); 1330 1493 return u64MilliTS; 1331 1332 case TMCLOCK_TSC:1333 AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));1334 return 0;1335 1494 1336 1495 default:
Note:
See TracChangeset
for help on using the changeset viewer.