VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/TMAllVirtual.cpp@ 1

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.2 KB
Line 
1/** @file
2 *
3 * TM - Timeout Manager, Virtual Time, All Contexts.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_TM
27#include <VBox/tm.h>
28#ifdef IN_RING3
29# include <VBox/rem.h>
30#endif
31#include "TMInternal.h"
32#include <VBox/vm.h>
33#include <VBox/err.h>
34#include <VBox/log.h>
35#include <VBox/sup.h>
36
37#include <iprt/time.h>
38#include <iprt/assert.h>
39#include <iprt/asm.h>
40
41
42
43
44/**
45 * Gets the current TMCLOCK_VIRTUAL time
46 *
47 * @returns The timestamp.
48 * @param pVM VM handle.
49 *
50 * @remark While the flow of time will never go backwards, the speed of the
51 * progress varies due to inaccurate RTTimeNanoTS and TSC. The latter can be
52 * influenced by power saving (SpeedStep, PowerNow!), while the former
53 * makes use of TSC and kernel timers.
54 */
55TMDECL(uint64_t) TMVirtualGet(PVM pVM)
56{
57 uint64_t u64;
58 if (pVM->tm.s.fVirtualTicking)
59 {
60 STAM_COUNTER_INC(&pVM->tm.s.StatVirtualGet);
61 u64 = RTTimeNanoTS() - pVM->tm.s.u64VirtualOffset;
62
63 /*
64 * Use the chance to check for expired timers.
65 */
66 if ( !VM_FF_ISSET(pVM, VM_FF_TIMER)
67 && ( pVM->tm.s.CTXALLSUFF(paTimerQueues)[TMCLOCK_VIRTUAL].u64Expire <= u64
68 || ( pVM->tm.s.fVirtualSyncTicking
69 && pVM->tm.s.CTXALLSUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire <= u64 - pVM->tm.s.u64VirtualSyncOffset
70 )
71 )
72 )
73 {
74 VM_FF_SET(pVM, VM_FF_TIMER);
75#ifdef IN_RING3
76 REMR3NotifyTimerPending(pVM);
77 VMR3NotifyFF(pVM, true);
78#endif
79 }
80 }
81 else
82 u64 = pVM->tm.s.u64Virtual;
83 return u64;
84}
85
86
87/**
88 * Gets the current TMCLOCK_VIRTUAL_SYNC time.
89 *
90 * @returns The timestamp.
91 * @param pVM VM handle.
92 */
93TMDECL(uint64_t) TMVirtualGetSync(PVM pVM)
94{
95 uint64_t u64;
96 if (pVM->tm.s.fVirtualSyncTicking)
97 {
98 STAM_COUNTER_INC(&pVM->tm.s.StatVirtualGetSync);
99
100 /*
101 * Do TMVirtualGet() to get the current TMCLOCK_VIRTUAL time.
102 */
103 Assert(pVM->tm.s.fVirtualTicking);
104 u64 = RTTimeNanoTS() - pVM->tm.s.u64VirtualOffset;
105 if ( !VM_FF_ISSET(pVM, VM_FF_TIMER)
106 && pVM->tm.s.CTXALLSUFF(paTimerQueues)[TMCLOCK_VIRTUAL].u64Expire <= u64)
107 {
108 VM_FF_SET(pVM, VM_FF_TIMER);
109#ifdef IN_RING3
110 REMR3NotifyTimerPending(pVM);
111 VMR3NotifyFF(pVM, true);
112#endif
113 }
114
115 /*
116 * Read the offset and adjust if we're playing catch-up.
117 *
118 * The catch-up adjusting work by us decrementing the offset by a percentage of
119 * the time elapsed since the previous TMVritualGetSync call. We take some simple
120 * precautions against racing other threads here, but assume that this isn't going
121 * to be much of a problem since calls to this function is unlikely from threads
122 * other than the EMT.
123 *
124 * It's possible to get a very long or even negative interval between two read
125 * for the following reasons:
126 * - Someone might have suspended the process execution, frequently the case when
127 * debugging the process.
128 * - We might be on a different CPU which TSC isn't quite in sync with the
129 * other CPUs in the system.
130 * - RTTimeNanoTS() is returning sligtly different values in GC, R0 and R3 because
131 * of the static variable it uses with the previous read time.
132 * - Another thread is racing us and we might have been preemnted while inside
133 * this function.
134 *
135 * Assuming nano second virtual time, we can simply ignore any intervals which has
136 * any of the upper 32 bits set. This will have the nice sideeffect of allowing us
137 * to use (faster) 32-bit math.
138 */
139 AssertCompile(TMCLOCK_FREQ_VIRTUAL <= 2000000000); /* (assumes low 32-bit >= 2 seconds) */
140 uint64_t u64Offset = pVM->tm.s.u64VirtualSyncOffset;
141 if (pVM->tm.s.fVirtualSyncCatchUp)
142 {
143 const uint64_t u64Prev = pVM->tm.s.u64VirtualSyncCatchUpPrev;
144 uint64_t u64Delta = u64 - u64Prev;
145 if (!(u64Delta >> 32))
146 {
147 uint32_t u32Sub = ASMDivU64ByU32RetU32(ASMMult2xU32RetU64((uint32_t)u64Delta, pVM->tm.s.u32VirtualSyncCatchupPrecentage),
148 100);
149 if (u32Sub < (uint32_t)u64Delta)
150 {
151 const uint64_t u64NewOffset = u64Offset - u32Sub;
152 if (ASMAtomicCmpXchgU64(&pVM->tm.s.u64VirtualSyncCatchUpPrev, u64, u64Prev))
153 ASMAtomicCmpXchgU64(&pVM->tm.s.u64VirtualSyncOffset, u64NewOffset, u64Offset);
154 u64Offset = u64NewOffset;
155 }
156 else
157 {
158 /* we've completely caught up. */
159 if ( ASMAtomicCmpXchgU64(&pVM->tm.s.u64VirtualSyncCatchUpPrev, u64, u64Prev)
160 && ASMAtomicCmpXchgU64(&pVM->tm.s.u64VirtualSyncOffset, 0, u64Offset))
161 ASMAtomicXchgSize(&pVM->tm.s.fVirtualSyncCatchUp, false);
162 }
163 }
164 else
165 {
166 /* Update the previous TMVirtualGetSync time it's not a negative delta. */
167 if (!(u64Delta >> 63))
168 ASMAtomicCmpXchgU64(&pVM->tm.s.u64VirtualSyncCatchUpPrev, u64, u64Prev);
169 Log(("TMVirtualGetSync: u64Delta=%VRU64\n", u64Delta));
170 }
171 }
172
173 /*
174 * Complete the calculation of the current TMCLOCK_VIRTUAL_SYNC time.
175 * The current approach will not let us pass any expired timer.
176 */
177 u64 -= u64Offset;
178 if (pVM->tm.s.CTXALLSUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire <= u64)
179 {
180 if (!VM_FF_ISSET(pVM, VM_FF_TIMER))
181 {
182 VM_FF_SET(pVM, VM_FF_TIMER);
183#ifdef IN_RING3
184 REMR3NotifyTimerPending(pVM);
185 VMR3NotifyFF(pVM, true);
186#endif
187 }
188 const uint64_t u64Expire = pVM->tm.s.CTXALLSUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire;
189 if (u64Expire < u64)
190 u64 = u64Expire;
191 }
192 }
193 else
194 u64 = pVM->tm.s.u64VirtualSync;
195 return u64;
196}
197
198
199/**
200 * Gets the current TMCLOCK_VIRTUAL frequency.
201 *
202 * @returns The freqency.
203 * @param pVM VM handle.
204 */
205TMDECL(uint64_t) TMVirtualGetFreq(PVM pVM)
206{
207 return TMCLOCK_FREQ_VIRTUAL;
208}
209
210
211//#define TM_CONTINUOUS_TIME
212
213/**
214 * Resumes the virtual clock.
215 *
216 * @returns VINF_SUCCESS on success.
217 * @returns VINF_INTERNAL_ERROR and VBOX_STRICT assertion if called out of order.
218 * @param pVM VM handle.
219 */
220TMDECL(int) TMVirtualResume(PVM pVM)
221{
222 if (!pVM->tm.s.fVirtualTicking)
223 {
224 STAM_COUNTER_INC(&pVM->tm.s.StatVirtualResume);
225 pVM->tm.s.u64VirtualOffset = RTTimeNanoTS() - pVM->tm.s.u64Virtual;
226 pVM->tm.s.fVirtualTicking = true;
227 pVM->tm.s.fVirtualSyncTicking = true;
228 return VINF_SUCCESS;
229 }
230
231#ifndef TM_CONTINUOUS_TIME
232 AssertFailed();
233 return VERR_INTERNAL_ERROR;
234#else
235 return VINF_SUCCESS;
236#endif
237}
238
239
240/**
241 * Pauses the virtual clock.
242 *
243 * @returns VINF_SUCCESS on success.
244 * @returns VINF_INTERNAL_ERROR and VBOX_STRICT assertion if called out of order.
245 * @param pVM VM handle.
246 */
247TMDECL(int) TMVirtualPause(PVM pVM)
248{
249 if (pVM->tm.s.fVirtualTicking)
250 {
251#ifndef TM_CONTINUOUS_TIME
252 STAM_COUNTER_INC(&pVM->tm.s.StatVirtualPause);
253 pVM->tm.s.u64Virtual = RTTimeNanoTS() - pVM->tm.s.u64VirtualOffset;
254 pVM->tm.s.fVirtualSyncTicking = false;
255 pVM->tm.s.fVirtualTicking = false;
256#endif
257 return VINF_SUCCESS;
258 }
259
260 AssertFailed();
261 return VERR_INTERNAL_ERROR;
262}
263
264
265/**
266 * Converts from virtual ticks to nanoseconds.
267 *
268 * @returns nanoseconds.
269 * @param pVM The VM handle.
270 * @param u64VirtualTicks The virtual ticks to convert.
271 * @remark There could be rounding errors here. We just do a simple integere divide
272 * without any adjustments.
273 */
274TMDECL(uint64_t) TMVirtualToNano(PVM pVM, uint64_t u64VirtualTicks)
275{
276 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
277 return u64VirtualTicks;
278}
279
280
281/**
282 * Converts from virtual ticks to microseconds.
283 *
284 * @returns microseconds.
285 * @param pVM The VM handle.
286 * @param u64VirtualTicks The virtual ticks to convert.
287 * @remark There could be rounding errors here. We just do a simple integere divide
288 * without any adjustments.
289 */
290TMDECL(uint64_t) TMVirtualToMicro(PVM pVM, uint64_t u64VirtualTicks)
291{
292 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
293 return u64VirtualTicks / 1000;
294}
295
296
297/**
298 * Converts from virtual ticks to milliseconds.
299 *
300 * @returns milliseconds.
301 * @param pVM The VM handle.
302 * @param u64VirtualTicks The virtual ticks to convert.
303 * @remark There could be rounding errors here. We just do a simple integere divide
304 * without any adjustments.
305 */
306TMDECL(uint64_t) TMVirtualToMilli(PVM pVM, uint64_t u64VirtualTicks)
307{
308 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
309 return u64VirtualTicks / 1000000;
310}
311
312
313/**
314 * Converts from nanoseconds to virtual ticks.
315 *
316 * @returns virtual ticks.
317 * @param pVM The VM handle.
318 * @param u64NanoTS The nanosecond value ticks to convert.
319 * @remark There could be rounding and overflow errors here.
320 */
321TMDECL(uint64_t) TMVirtualFromNano(PVM pVM, uint64_t u64NanoTS)
322{
323 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
324 return u64NanoTS;
325}
326
327
328/**
329 * Converts from microseconds to virtual ticks.
330 *
331 * @returns virtual ticks.
332 * @param pVM The VM handle.
333 * @param u64MicroTS The microsecond value ticks to convert.
334 * @remark There could be rounding and overflow errors here.
335 */
336TMDECL(uint64_t) TMVirtualFromMicro(PVM pVM, uint64_t u64MicroTS)
337{
338 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
339 return u64MicroTS * 1000;
340}
341
342
343/**
344 * Converts from milliseconds to virtual ticks.
345 *
346 * @returns virtual ticks.
347 * @param pVM The VM handle.
348 * @param u64MilliTS The millisecond value ticks to convert.
349 * @remark There could be rounding and overflow errors here.
350 */
351TMDECL(uint64_t) TMVirtualFromMilli(PVM pVM, uint64_t u64MilliTS)
352{
353 AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
354 return u64MilliTS * 1000000;
355}
356
Note: See TracBrowser for help on using the repository browser.

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