Revert some changes which don't have proper dependencies.
[mono-project.git] / mono / utils / mono-time.c
blob6874cc3781c2e1e94265763da6d1b496a74ab201
1 /**
2 * \file
3 * Time utility functions.
4 * Author: Paolo Molaro (<lupus@ximian.com>)
5 * Copyright (C) 2008 Novell, Inc.
6 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
7 */
9 #include <config.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <errno.h>
14 #ifdef HAVE_SYS_TIME_H
15 #include <sys/time.h>
16 #endif
18 #include <mono/utils/mono-time.h>
19 #include <mono/utils/atomic.h>
21 #if HAVE_MACH_ABSOLUTE_TIME
22 #include <mach/mach_time.h>
23 #endif
25 #define MTICKS_PER_SEC (10 * 1000 * 1000)
27 typedef enum _TimeConversionConstants
29 tccSecondsToMillieSeconds = 1000, // 10^3
30 tccSecondsToMicroSeconds = 1000000, // 10^6
31 tccSecondsToNanoSeconds = 1000000000, // 10^9
32 tccMillieSecondsToMicroSeconds = 1000, // 10^3
33 tccMillieSecondsToNanoSeconds = 1000000, // 10^6
34 tccMicroSecondsToNanoSeconds = 1000, // 10^3
35 tccSecondsTo100NanoSeconds = 10000000, // 10^7
36 tccMicroSecondsTo100NanoSeconds = 10 // 10^1
37 } TimeConversionConstants;
39 gint64
40 mono_msec_ticks (void)
42 return mono_100ns_ticks () / 10 / 1000;
45 #ifdef HOST_WIN32
46 #include <windows.h>
48 #ifndef _MSC_VER
49 /* we get "error: implicit declaration of function 'GetTickCount64'" */
50 WINBASEAPI ULONGLONG WINAPI GetTickCount64(void);
51 #endif
53 gint64
54 mono_msec_boottime (void)
56 /* GetTickCount () is reportedly monotonic */
57 return GetTickCount64 ();
60 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
61 gint64
62 mono_100ns_ticks (void)
64 static LARGE_INTEGER freq;
65 static UINT64 start_time;
66 UINT64 cur_time;
67 LARGE_INTEGER value;
69 if (!freq.QuadPart) {
70 if (!QueryPerformanceFrequency (&freq))
71 return mono_100ns_datetime ();
72 QueryPerformanceCounter (&value);
73 start_time = value.QuadPart;
75 QueryPerformanceCounter (&value);
76 cur_time = value.QuadPart;
77 /* we use unsigned numbers and return the difference to avoid overflows */
78 return (cur_time - start_time) * (double)MTICKS_PER_SEC / freq.QuadPart;
81 /* Returns the number of 100ns ticks since Jan 1, 1601, UTC timezone */
82 gint64
83 mono_100ns_datetime (void)
85 ULARGE_INTEGER ft;
87 if (sizeof(ft) != sizeof(FILETIME))
88 g_assert_not_reached ();
90 GetSystemTimeAsFileTime ((FILETIME*) &ft);
91 return ft.QuadPart;
94 #else
97 #if defined (HAVE_SYS_PARAM_H)
98 #include <sys/param.h>
99 #endif
100 #if defined(HAVE_SYS_SYSCTL_H)
101 #include <sys/sysctl.h>
102 #endif
104 #if defined(HOST_DARWIN)
105 #include <mach/mach.h>
106 #include <mach/mach_time.h>
107 #endif
109 #include <time.h>
111 /* Returns the number of milliseconds from boot time: this should be monotonic */
112 /* Adapted from CoreCLR: https://github.com/dotnet/coreclr/blob/66d2738ea96fcce753dec1370e79a0c78f7b6adb/src/pal/src/misc/time.cpp */
113 gint64
114 mono_msec_boottime (void)
116 /* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */
117 #if !defined (TARGET_WASM) && ((defined(HAVE_CLOCK_MONOTONIC_COARSE) || defined(HAVE_CLOCK_MONOTONIC)) && !(defined(TARGET_IOS) || defined(TARGET_OSX) || defined(TARGET_WATCHOS) || defined(TARGET_TVOS)))
118 clockid_t clockType =
119 #if HAVE_CLOCK_MONOTONIC_COARSE
120 CLOCK_MONOTONIC_COARSE; /* good enough resolution, fastest speed */
121 #else
122 CLOCK_MONOTONIC;
123 #endif
124 struct timespec ts;
125 if (clock_gettime (clockType, &ts) != 0) {
126 g_error ("clock_gettime(CLOCK_MONOTONIC*) failed; errno is %d", errno, strerror (errno));
127 return 0;
129 return (ts.tv_sec * tccSecondsToMillieSeconds) + (ts.tv_nsec / tccMillieSecondsToNanoSeconds);
131 #elif HAVE_MACH_ABSOLUTE_TIME
132 static gboolean timebase_inited;
133 static mach_timebase_info_data_t s_TimebaseInfo;
135 if (!timebase_inited) {
136 kern_return_t machRet;
137 mach_timebase_info_data_t tmp;
138 machRet = mach_timebase_info (&tmp);
139 g_assert (machRet == KERN_SUCCESS);
140 /* Assume memcpy works correctly if ran concurrently */
141 memcpy (&s_TimebaseInfo, &tmp, sizeof (mach_timebase_info_data_t));
142 mono_memory_barrier ();
143 timebase_inited = TRUE;
144 } else {
145 // This barrier prevents reading s_TimebaseInfo before reading timebase_inited.
146 mono_memory_barrier ();
148 return (mach_absolute_time () * s_TimebaseInfo.numer / s_TimebaseInfo.denom) / tccMillieSecondsToNanoSeconds;
150 #elif HAVE_GETHRTIME
151 return (gint64)(gethrtime () / tccMillieSecondsToNanoSeconds);
153 #elif HAVE_READ_REAL_TIME
154 timebasestruct_t tb;
155 read_real_time (&tb, TIMEBASE_SZ);
156 if (time_base_to_time (&tb, TIMEBASE_SZ) != 0) {
157 g_error ("time_base_to_time() failed; errno is %d (%s)", errno, strerror (errno));
158 return 0;
160 return (tb.tb_high * tccSecondsToMillieSeconds) + (tb.tb_low / tccMillieSecondsToNanoSeconds);
162 #else
163 struct timeval tv;
164 if (gettimeofday (&tv, NULL) == -1) {
165 g_error ("gettimeofday() failed; errno is %d (%s)", errno, strerror (errno));
166 return 0;
168 return (tv.tv_sec * tccSecondsToMillieSeconds) + (tv.tv_usec / tccMillieSecondsToMicroSeconds);
170 #endif /* HAVE_CLOCK_MONOTONIC */
173 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
174 gint64
175 mono_100ns_ticks (void)
177 struct timeval tv;
178 #if defined(HOST_DARWIN)
179 /* http://developer.apple.com/library/mac/#qa/qa1398/_index.html */
180 static mach_timebase_info_data_t timebase;
181 guint64 now = mach_absolute_time ();
182 if (timebase.denom == 0) {
183 mach_timebase_info (&timebase);
184 timebase.denom *= 100; /* we return 100ns ticks */
186 return now * timebase.numer / timebase.denom;
187 #elif defined(CLOCK_MONOTONIC) && !defined(__PASE__)
188 /* !__PASE__ is defined because i 7.1 doesn't have clock_getres */
189 struct timespec tspec;
190 static struct timespec tspec_freq = {0};
191 static int can_use_clock = 0;
192 if (!tspec_freq.tv_nsec) {
193 can_use_clock = clock_getres (CLOCK_MONOTONIC, &tspec_freq) == 0;
194 /*printf ("resolution: %lu.%lu\n", tspec_freq.tv_sec, tspec_freq.tv_nsec);*/
196 if (can_use_clock) {
197 if (clock_gettime (CLOCK_MONOTONIC, &tspec) == 0) {
198 /*printf ("time: %lu.%lu\n", tspec.tv_sec, tspec.tv_nsec); */
199 return ((gint64)tspec.tv_sec * MTICKS_PER_SEC + tspec.tv_nsec / 100);
202 #endif
203 if (gettimeofday (&tv, NULL) == 0)
204 return ((gint64)tv.tv_sec * 1000000 + tv.tv_usec) * 10;
205 return 0;
209 * Magic number to convert unix epoch start to windows epoch start
210 * Jan 1, 1970 into a value which is relative to Jan 1, 1601.
212 #define EPOCH_ADJUST ((guint64)11644473600LL)
214 /* Returns the number of 100ns ticks since 1/1/1601, UTC timezone */
215 gint64
216 mono_100ns_datetime (void)
218 struct timeval tv;
219 if (gettimeofday (&tv, NULL) == 0)
220 return mono_100ns_datetime_from_timeval (tv);
221 return 0;
224 gint64
225 mono_100ns_datetime_from_timeval (struct timeval tv)
227 return (((gint64)tv.tv_sec + EPOCH_ADJUST) * 1000000 + tv.tv_usec) * 10;
230 #endif