VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/time/timesup.cpp@ 54224

Last change on this file since 54224 was 54224, checked in by vboxsync, 10 years ago

SUP,IPRT: Started as a build fix ended up as a cleanup (mostly untested as I'm windows). We'll keep SUP_IOCTL_TSC_READ for the purpose of dealing with the i64TSCDelta == INT64_MAX in SUPReadTsc/SUPReadTscWithDelta. Moved the excessive inline code from sup.h to SUPLibAll.cpp (new file) and SUPDrv.c (apply delta). Don't bother too much about trying to share code between SUPLibAll.cpp and SUPDrv.c/++ as the SUPReadTsc[WithDelta] scenario does not care about knowing when things goes bad, it just needs a TSC that is as good as we can get. The SUPDrv.c code on the other hand probably needs other kind of status codes, assertions and whatnot to be better off with its own version of the code. Remove the now unused assembly macro for applying the delta - the way the delta is applied will not change, period, so better just document it instead.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 9.4 KB
Line 
1/* $Id: timesup.cpp 54224 2015-02-16 22:41:32Z vboxsync $ */
2/** @file
3 * IPRT - Time using SUPLib.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define LOG_GROUP RTLOGGROUP_TIME
32#include <iprt/time.h>
33#include "internal/iprt.h"
34
35#include <iprt/assert.h>
36#include <iprt/err.h>
37#include <iprt/log.h>
38#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
39# include <iprt/asm.h>
40# include <iprt/asm-amd64-x86.h>
41# include <iprt/x86.h>
42# include <VBox/sup.h>
43#endif
44#include "internal/time.h"
45
46
47/*******************************************************************************
48* Internal Functions *
49*******************************************************************************/
50#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
51static DECLCALLBACK(void) rtTimeNanoTSInternalBitch(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS);
52static DECLCALLBACK(uint64_t) rtTimeNanoTSInternalFallback(PRTTIMENANOTSDATA pData);
53static DECLCALLBACK(uint64_t) rtTimeNanoTSInternalRediscover(PRTTIMENANOTSDATA pData);
54#endif
55
56
57/*******************************************************************************
58* Global Variables *
59*******************************************************************************/
60#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
61/** The previous timestamp value returned by RTTimeNanoTS. */
62static uint64_t g_TimeNanoTSPrev = 0;
63
64/** The RTTimeNanoTS data structure that's passed down to the worker functions. */
65static RTTIMENANOTSDATA g_TimeNanoTSData =
66{
67 /* .pu64Prev = */ &g_TimeNanoTSPrev,
68 /* .pfnBad = */ rtTimeNanoTSInternalBitch,
69 /* .pfnRediscover = */ rtTimeNanoTSInternalRediscover,
70 /* .pvDummy = */ NULL,
71 /* .c1nsSteps = */ 0,
72 /* .cExpired = */ 0,
73 /* .cBadPrev = */ 0,
74 /* .cUpdateRaces = */ 0
75};
76
77/** The index into g_apfnWorkers for the function to use.
78 * This cannot be a pointer because that'll break down in GC due to code relocation. */
79static uint32_t g_iWorker = 0;
80/** Array of rtTimeNanoTSInternal worker functions.
81 * This array is indexed by g_iWorker. */
82static const PFNTIMENANOTSINTERNAL g_apfnWorkers[] =
83{
84# define RTTIMENANO_WORKER_DETECT 0
85 rtTimeNanoTSInternalRediscover,
86
87# define RTTIMENANO_WORKER_LEGACY_SYNC_NO_DELTA 1
88 RTTimeNanoTSLegacySyncNoDelta,
89# define RTTIMENANO_WORKER_LEGACY_SYNC_WITH_DELTA 2
90 RTTimeNanoTSLegacySyncWithDelta,
91# define RTTIMENANO_WORKER_LEGACY_ASYNC 3
92 RTTimeNanoTSLegacyAsync,
93# define RTTIMENANO_WORKER_LEGACY_INVAR_NO_DELTA 4
94 RTTimeNanoTSLFenceInvariantNoDelta,
95# define RTTIMENANO_WORKER_LEGACY_INVAR_WITH_DELTA 5
96 RTTimeNanoTSLFenceInvariantWithDelta,
97
98# define RTTIMENANO_WORKER_LFENCE_SYNC_NO_DELTA 6
99 RTTimeNanoTSLFenceSyncNoDelta,
100# define RTTIMENANO_WORKER_LFENCE_SYNC_WITH_DELTA 7
101 RTTimeNanoTSLFenceSyncWithDelta,
102# define RTTIMENANO_WORKER_LFENCE_ASYNC 8
103 RTTimeNanoTSLFenceAsync,
104# define RTTIMENANO_WORKER_LFENCE_INVAR_NO_DELTA 9
105 RTTimeNanoTSLFenceInvariantNoDelta,
106# define RTTIMENANO_WORKER_LFENCE_INVAR_WITH_DELTA 10
107 RTTimeNanoTSLFenceInvariantWithDelta,
108
109# define RTTIMENANO_WORKER_FALLBACK 11
110 rtTimeNanoTSInternalFallback,
111};
112
113
114/**
115 * Helper function that's used by the assembly routines when something goes bust.
116 *
117 * @param pData Pointer to the data structure.
118 * @param u64NanoTS The calculated nano ts.
119 * @param u64DeltaPrev The delta relative to the previously returned timestamp.
120 * @param u64PrevNanoTS The previously returned timestamp (as it was read it).
121 */
122static DECLCALLBACK(void) rtTimeNanoTSInternalBitch(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS)
123{
124 pData->cBadPrev++;
125 if ((int64_t)u64DeltaPrev < 0)
126 LogRel(("TM: u64DeltaPrev=%RI64 u64PrevNanoTS=0x%016RX64 u64NanoTS=0x%016RX64\n",
127 u64DeltaPrev, u64PrevNanoTS, u64NanoTS));
128 else
129 Log(("TM: u64DeltaPrev=%RI64 u64PrevNanoTS=0x%016RX64 u64NanoTS=0x%016RX64 (debugging?)\n",
130 u64DeltaPrev, u64PrevNanoTS, u64NanoTS));
131}
132
133/**
134 * Fallback function.
135 */
136static DECLCALLBACK(uint64_t) rtTimeNanoTSInternalFallback(PRTTIMENANOTSDATA pData)
137{
138 PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
139 if ( pGip
140 && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC
141 && ( pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
142 || pGip->u32Mode == SUPGIPMODE_SYNC_TSC
143 || pGip->u32Mode == SUPGIPMODE_ASYNC_TSC))
144 return rtTimeNanoTSInternalRediscover(pData);
145 NOREF(pData);
146# ifndef IN_RC
147 return RTTimeSystemNanoTS();
148# else
149 return 0;
150# endif
151}
152
153
154/**
155 * Called the first time somebody asks for the time or when the GIP
156 * is mapped/unmapped.
157 */
158static DECLCALLBACK(uint64_t) rtTimeNanoTSInternalRediscover(PRTTIMENANOTSDATA pData)
159{
160 uint32_t iWorker;
161 PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
162 if ( pGip
163 && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC
164 && ( pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
165 || pGip->u32Mode == SUPGIPMODE_SYNC_TSC
166 || pGip->u32Mode == SUPGIPMODE_ASYNC_TSC))
167 {
168 if (ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SSE2)
169 iWorker = pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
170 ? !pGip->fOsTscDeltasInSync && !pGip->fTscDeltasRoughlyInSync
171 ? RTTIMENANO_WORKER_LFENCE_INVAR_WITH_DELTA : RTTIMENANO_WORKER_LFENCE_INVAR_NO_DELTA
172 : pGip->u32Mode == SUPGIPMODE_SYNC_TSC
173 ? false /** @todo !pGip->fOsTscDeltasInSync && !pGip->fTscDeltasRoughlyInSync */
174 ? RTTIMENANO_WORKER_LFENCE_SYNC_WITH_DELTA : RTTIMENANO_WORKER_LFENCE_SYNC_NO_DELTA
175 : RTTIMENANO_WORKER_LFENCE_ASYNC;
176 else
177 iWorker = pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
178 ? !pGip->fOsTscDeltasInSync && !pGip->fTscDeltasRoughlyInSync
179 ? RTTIMENANO_WORKER_LEGACY_INVAR_WITH_DELTA : RTTIMENANO_WORKER_LEGACY_INVAR_NO_DELTA
180 : pGip->u32Mode == SUPGIPMODE_SYNC_TSC
181 ? false /** @todo !pGip->fOsTscDeltasInSync && !pGip->fTscDeltasRoughlyInSync */
182 ? RTTIMENANO_WORKER_LEGACY_SYNC_WITH_DELTA : RTTIMENANO_WORKER_LEGACY_SYNC_NO_DELTA
183 : RTTIMENANO_WORKER_LEGACY_ASYNC;
184 }
185 else
186 iWorker = RTTIMENANO_WORKER_FALLBACK;
187
188 ASMAtomicWriteU32((uint32_t volatile *)&g_iWorker, iWorker);
189 return g_apfnWorkers[iWorker](pData);
190}
191
192#endif /* !IN_GUEST && !RT_NO_GIP */
193
194
195/**
196 * Internal worker for getting the current nanosecond timestamp.
197 */
198DECLINLINE(uint64_t) rtTimeNanoTSInternal(void)
199{
200#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
201 return g_apfnWorkers[g_iWorker](&g_TimeNanoTSData);
202#else
203 return RTTimeSystemNanoTS();
204#endif
205}
206
207
208/**
209 * Gets the current nanosecond timestamp.
210 *
211 * @returns nanosecond timestamp.
212 */
213RTDECL(uint64_t) RTTimeNanoTS(void)
214{
215 return rtTimeNanoTSInternal();
216}
217RT_EXPORT_SYMBOL(RTTimeNanoTS);
218
219
220/**
221 * Gets the current millisecond timestamp.
222 *
223 * @returns millisecond timestamp.
224 */
225RTDECL(uint64_t) RTTimeMilliTS(void)
226{
227 return rtTimeNanoTSInternal() / 1000000;
228}
229RT_EXPORT_SYMBOL(RTTimeMilliTS);
230
231
232#if !defined(IN_GUEST) && !defined(RT_NO_GIP)
233/**
234 * Debugging the time api.
235 *
236 * @returns the number of 1ns steps which has been applied by RTTimeNanoTS().
237 */
238RTDECL(uint32_t) RTTimeDbgSteps(void)
239{
240 return g_TimeNanoTSData.c1nsSteps;
241}
242RT_EXPORT_SYMBOL(RTTimeDbgSteps);
243
244
245/**
246 * Debugging the time api.
247 *
248 * @returns the number of times the TSC interval expired RTTimeNanoTS().
249 */
250RTDECL(uint32_t) RTTimeDbgExpired(void)
251{
252 return g_TimeNanoTSData.cExpired;
253}
254RT_EXPORT_SYMBOL(RTTimeDbgExpired);
255
256
257/**
258 * Debugging the time api.
259 *
260 * @returns the number of bad previous values encountered by RTTimeNanoTS().
261 */
262RTDECL(uint32_t) RTTimeDbgBad(void)
263{
264 return g_TimeNanoTSData.cBadPrev;
265}
266RT_EXPORT_SYMBOL(RTTimeDbgBad);
267
268
269/**
270 * Debugging the time api.
271 *
272 * @returns the number of update races in RTTimeNanoTS().
273 */
274RTDECL(uint32_t) RTTimeDbgRaces(void)
275{
276 return g_TimeNanoTSData.cUpdateRaces;
277}
278RT_EXPORT_SYMBOL(RTTimeDbgRaces);
279#endif /* !IN_GUEST && !RT_NO_GIP */
280
Note: See TracBrowser for help on using the repository browser.

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