VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/time/timesupref.h@ 5468

Last change on this file since 5468 was 5468, checked in by vboxsync, 17 years ago

silly typo.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 5.5 KB
Line 
1/* $Id: timesupref.h 5468 2007-10-24 03:58:47Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime - Time using SUPLib, the C Code Template.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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 */
18
19
20/**
21 * The C reference implementation of the assembly routines.
22 *
23 * Calculate NanoTS using the information in the global information page (GIP)
24 * which the support library (SUPLib) exports.
25 *
26 * This function guarantees that the returned timestamp is later (in time) than
27 * any previous calls in the same thread.
28 *
29 * @remark The way the ever increasing time guarantee is currently implemented means
30 * that if you call this function at a freqency higher than 1GHz you're in for
31 * trouble. We currently assume that no idiot will do that for real life purposes.
32 *
33 * @returns Nanosecond timestamp.
34 * @param pData Pointer to the data structure.
35 */
36RTDECL(uint64_t) rtTimeNanoTSInternalRef(PRTTIMENANOTSDATA pData)
37{
38 uint64_t u64Delta;
39 uint32_t u32NanoTSFactor0;
40 uint64_t u64TSC;
41 uint64_t u64NanoTS;
42 uint32_t u32UpdateIntervalTSC;
43 uint64_t u64PrevNanoTS;
44
45 /*
46 * Read the GIP data and the previous value.
47 */
48 for (;;)
49 {
50 PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
51#ifdef IN_RING3
52 if (RT_UNLIKELY(!pGip || pGip->u32Magic != SUPGLOBALINFOPAGE_MAGIC))
53 return pData->pfnRediscover(pData);
54#endif
55
56#ifdef ASYNC_GIP
57 uint8_t u8ApicId = ASMGetApicId();
58 PSUPGIPCPU pGipCpu = &pGip->aCPUs[u8ApicId];
59#else
60 PSUPGIPCPU pGipCpu = &pGip->aCPUs[0];
61#endif
62
63#ifdef NEED_TRANSACTION_ID
64 uint32_t u32TransactionId = pGipCpu->u32TransactionId;
65 uint32_t volatile Tmp1;
66 ASMAtomicXchgU32(&Tmp1, u32TransactionId);
67#endif
68
69 u32UpdateIntervalTSC = pGipCpu->u32UpdateIntervalTSC;
70 u64NanoTS = pGipCpu->u64NanoTS;
71 u64TSC = pGipCpu->u64TSC;
72 u32NanoTSFactor0 = pGip->u32UpdateIntervalNS;
73 u64Delta = ASMReadTSC();
74 u64PrevNanoTS = ASMAtomicReadU64(pData->pu64Prev);
75
76#ifdef NEED_TRANSACTION_ID
77# ifdef ASYNC_GIP
78 if (RT_UNLIKELY(u8ApicId != ASMGetApicId()))
79 continue;
80# elif !defined(RT_ARCH_X86)
81 uint32_t volatile Tmp2;
82 ASMAtomicXchgU32(&Tmp2, u64Delta);
83# endif
84 if (RT_UNLIKELY( pGipCpu->u32TransactionId != u32TransactionId
85 || (u32TransactionId & 1)))
86 continue;
87#endif
88 break;
89 }
90
91 /*
92 * Calc NanoTS delta.
93 */
94 u64Delta -= u64TSC;
95 if (RT_UNLIKELY(u64Delta > u32UpdateIntervalTSC))
96 {
97 /*
98 * We've expired the interval, cap it. If we're here for the 2nd
99 * time without any GIP update inbetween, the checks against
100 * *pu64Prev below will force 1ns stepping.
101 */
102 pData->cExpired++;
103 u64Delta = u32UpdateIntervalTSC;
104 }
105#if !defined(_MSC_VER) || defined(RT_ARCH_AMD64) /* GCC makes very pretty code from these two inline calls, while MSC cannot. */
106 u64Delta = ASMMult2xU32RetU64((uint32_t)u64Delta, u32NanoTSFactor0);
107 u64Delta = ASMDivU64ByU32RetU32(u64Delta, u32UpdateIntervalTSC);
108#else
109 __asm
110 {
111 mov eax, dword ptr [u64Delta]
112 mul dword ptr [u32NanoTSFactor0]
113 div dword ptr [u32UpdateIntervalTSC]
114 mov dword ptr [u64Delta], eax
115 xor edx, edx
116 mov dword ptr [u64Delta + 4], edx
117 }
118#endif
119
120 /*
121 * Calculate the time and compare it with the previously returned value.
122 */
123 u64NanoTS += u64Delta;
124 uint64_t u64DeltaPrev = u64NanoTS - u64PrevNanoTS;
125 if (RT_LIKELY( u64DeltaPrev > 0
126 && u64DeltaPrev < UINT64_C(86000000000000) /* 24h */))
127 /* Frequent - less than 24h since last call. */;
128 else if (RT_LIKELY( (int64_t)u64DeltaPrev <= 0
129 && (int64_t)u64DeltaPrev + u32NanoTSFactor0 * 2 >= 0))
130 {
131 /* Occasional - u64NanoTS is in the recent 'past' relative the previous call. */
132 ASMAtomicIncU32(&pData->c1nsSteps);
133 u64NanoTS = u64PrevNanoTS + 1;
134 }
135 else if (!u64PrevNanoTS)
136 /* We're resuming (see TMVirtualResume). */;
137 else
138 {
139 /* Something has gone bust, if negative offset it's real bad. */
140 ASMAtomicIncU32(&pData->cBadPrev);
141 pData->pfnBad(pData, u64NanoTS, u64DeltaPrev, u64PrevNanoTS);
142 }
143
144 if (RT_UNLIKELY(!ASMAtomicCmpXchgU64(pData->pu64Prev, u64NanoTS, u64PrevNanoTS)))
145 {
146 /*
147 * Attempt updating the previous value, provided we're still ahead of it.
148 *
149 * There is no point in recalculating u64NanoTS because we got preemted or if
150 * we raced somebody while the GIP was updated, since these are events
151 * that might occure at any point in the return path as well.
152 */
153 pData->cUpdateRaces++;
154 for (int cTries = 25;;)
155 {
156 u64PrevNanoTS = ASMAtomicReadU64(pData->pu64Prev);
157 if (u64PrevNanoTS >= u64NanoTS)
158 break;
159 if (ASMAtomicCmpXchgU64(pData->pu64Prev, u64NanoTS, u64PrevNanoTS))
160 break;
161 AssertBreak(--cTries <= 0, );
162 }
163 }
164 return u64NanoTS;
165}
166
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