VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/nt/time-nt.cpp@ 78273

Last change on this file since 78273 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 7.5 KB
Line 
1/* $Id: time-nt.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * IPRT - Time, Windows.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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 "internal-r3-nt.h"
33
34#include <iprt/time.h>
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/errcore.h>
38#include <iprt/ldr.h>
39#include <iprt/uint128.h>
40#include "internal/time.h"
41
42
43/*********************************************************************************************************************************
44* Global Variables *
45*********************************************************************************************************************************/
46/** Whether we've tried to resolve g_pfnRtlGetSystemTimePrecise or not. */
47static bool g_fInitialized = false;
48/** Pointer to RtlGetSystemTimePrecise, added in 6.2 (windows 8). */
49static PFNRTLGETSYSTEMTIMEPRECISE g_pfnRtlGetSystemTimePrecise = NULL;
50
51
52/**
53 * Initializes globals.
54 */
55static void rtTimeNtInitialize(void)
56{
57 /*
58 * Make sure we don't recurse here when calling into RTLdr.
59 */
60 if (ASMAtomicCmpXchgBool(&g_fInitialized, true, false))
61 {
62 void *pvFunc = RTLdrGetSystemSymbol("ntdll.dll", "RtlGetSystemTimePrecise");
63 if (pvFunc)
64 ASMAtomicWritePtr((void * volatile *)&g_pfnRtlGetSystemTimePrecise, pvFunc);
65 ASMCompilerBarrier();
66 }
67}
68
69
70static uint64_t rtTimeGetSystemNanoTS(void)
71{
72 if (RT_UNLIKELY(!g_fInitialized))
73 rtTimeNtInitialize();
74
75 KUSER_SHARED_DATA volatile *pUserSharedData = (KUSER_SHARED_DATA volatile *)MM_SHARED_USER_DATA_VA;
76
77#if 1
78 /*
79 * If there is precise time, get the precise system time and calculate the
80 * interrupt time from it. (Microsoft doesn't expose interrupt time to user
81 * application, which is very unfortunate as there are a lot place where
82 * monotonic time is applicable but developer is "forced" to use wall clock.)
83 */
84 if (g_pfnRtlGetSystemTimePrecise)
85 {
86 for (;;)
87 {
88 uint64_t uUpdateLockBefore;
89 while ((uUpdateLockBefore = pUserSharedData->TimeUpdateLock) & 1)
90 ASMNopPause();
91
92 uint64_t uInterruptTime = *(uint64_t volatile *)&pUserSharedData->InterruptTime;
93 uint64_t uBaselineInterruptTimeQpc = pUserSharedData->BaselineInterruptTimeQpc;
94 uint64_t uQpcInterruptTimeIncrement = pUserSharedData->QpcInterruptTimeIncrement;
95 uint8_t uQpcInterruptTimeIncrementShift = pUserSharedData->QpcInterruptTimeIncrementShift;
96 LARGE_INTEGER QpcValue;
97 RtlQueryPerformanceCounter(&QpcValue);
98
99 if (pUserSharedData->TimeUpdateLock == uUpdateLockBefore)
100 {
101 uint64_t uQpcValue = QpcValue.QuadPart;
102 if (uQpcValue <= uBaselineInterruptTimeQpc)
103 return uInterruptTime * 100;
104
105 /* Calc QPC delta since base line. */
106 uQpcValue -= uBaselineInterruptTimeQpc;
107 uQpcValue--;
108
109 /* Multiply by 10 million. */
110 uQpcValue *= UINT32_C(10000000);
111
112 /* Multiply by QPC interrupt time increment value. */
113 RTUINT128U Tmp128;
114 RTUInt128MulU64ByU64(&Tmp128, uQpcValue, uQpcInterruptTimeIncrement);
115
116 /* Shift the upper 64 bits by the increment shift factor. */
117 uint64_t uResult = Tmp128.s.Hi >> uQpcInterruptTimeIncrementShift;
118
119 /* Add to base interrupt time value. */
120 uResult += uInterruptTime;
121
122 /* Convert from NT unit to nano seconds. */
123 return uResult * 100;
124 }
125
126 ASMNopPause();
127 }
128 }
129#endif
130
131 /*
132 * Just read interrupt time.
133 */
134#if ARCH_BITS >= 64
135 uint64_t uRet = *(uint64_t volatile *)&pUserSharedData->InterruptTime; /* This is what KeQueryInterruptTime does. */
136 uRet *= 100;
137 return uRet;
138#else
139
140 LARGE_INTEGER NtTime;
141 do
142 {
143 NtTime.HighPart = pUserSharedData->InterruptTime.High1Time;
144 NtTime.LowPart = pUserSharedData->InterruptTime.LowPart;
145 } while (pUserSharedData->InterruptTime.High2Time != NtTime.HighPart);
146
147 return (uint64_t)NtTime.QuadPart * 100;
148#endif
149}
150
151
152RTDECL(uint64_t) RTTimeSystemNanoTS(void)
153{
154 return rtTimeGetSystemNanoTS();
155}
156
157
158RTDECL(uint64_t) RTTimeSystemMilliTS(void)
159{
160 return rtTimeGetSystemNanoTS() / RT_NS_1MS;
161}
162
163
164RTDECL(PRTTIMESPEC) RTTimeNow(PRTTIMESPEC pTime)
165{
166 /*
167 * Get the precise time if possible.
168 */
169 if (RT_UNLIKELY(!g_fInitialized))
170 rtTimeNtInitialize();
171 if (g_pfnRtlGetSystemTimePrecise != NULL)
172 return RTTimeSpecSetNtTime(pTime, g_pfnRtlGetSystemTimePrecise());
173
174 /*
175 * Just read system time.
176 */
177 KUSER_SHARED_DATA volatile *pUserSharedData = (KUSER_SHARED_DATA volatile *)MM_SHARED_USER_DATA_VA;
178#ifdef RT_ARCH_AMD64
179 uint64_t uRet = *(uint64_t volatile *)&pUserSharedData->SystemTime; /* This is what KeQuerySystemTime does. */
180 return RTTimeSpecSetNtTime(pTime, uRet);
181#else
182
183 LARGE_INTEGER NtTime;
184 do
185 {
186 NtTime.HighPart = pUserSharedData->SystemTime.High1Time;
187 NtTime.LowPart = pUserSharedData->SystemTime.LowPart;
188 } while (pUserSharedData->SystemTime.High2Time != NtTime.HighPart);
189 return RTTimeSpecSetNtTime(pTime, NtTime.QuadPart);
190#endif
191}
192
193
194RTDECL(PRTTIMESPEC) RTTimeLocalNow(PRTTIMESPEC pTime)
195{
196 return RTTimeSpecAddNano(RTTimeNow(pTime), RTTimeLocalDeltaNano());
197}
198
199
200RTDECL(int64_t) RTTimeLocalDeltaNano(void)
201{
202 /*
203 * UTC = local + TimeZoneBias; The bias is given in NT units.
204 */
205 KUSER_SHARED_DATA volatile *pUserSharedData = (KUSER_SHARED_DATA volatile *)MM_SHARED_USER_DATA_VA;
206 LARGE_INTEGER Delta;
207#if ARCH_BITS == 64
208 Delta.QuadPart = *(int64_t volatile *)&pUserSharedData->TimeZoneBias;
209#else
210 do
211 {
212 Delta.HighPart = pUserSharedData->TimeZoneBias.High1Time;
213 Delta.LowPart = pUserSharedData->TimeZoneBias.LowPart;
214 } while (pUserSharedData->TimeZoneBias.High2Time != Delta.HighPart);
215#endif
216 return Delta.QuadPart * -100;
217}
218
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