VirtualBox

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

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

rebranding: IPRT files again.

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