[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mono / utils / mono-time.c
blobbeec0266134de9b98e6f095c62b949e1e05bed76
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 #ifdef HOST_DARWIN
19 #include <mach/clock.h>
20 #include <mach/mach.h>
21 #endif
24 #include <mono/utils/mono-time.h>
25 #include <mono/utils/atomic.h>
27 #if HAVE_MACH_ABSOLUTE_TIME
28 #include <mach/mach_time.h>
29 #endif
31 #define MTICKS_PER_SEC (10 * 1000 * 1000)
33 typedef enum _TimeConversionConstants
35 tccSecondsToMillieSeconds = 1000, // 10^3
36 tccSecondsToMicroSeconds = 1000000, // 10^6
37 tccSecondsToNanoSeconds = 1000000000, // 10^9
38 tccMillieSecondsToMicroSeconds = 1000, // 10^3
39 tccMillieSecondsToNanoSeconds = 1000000, // 10^6
40 tccMicroSecondsToNanoSeconds = 1000, // 10^3
41 tccSecondsTo100NanoSeconds = 10000000, // 10^7
42 tccMicroSecondsTo100NanoSeconds = 10 // 10^1
43 } TimeConversionConstants;
45 gint64
46 mono_msec_ticks (void)
48 return mono_100ns_ticks () / 10 / 1000;
51 #ifdef HOST_WIN32
52 #include <windows.h>
54 #ifndef _MSC_VER
55 /* we get "error: implicit declaration of function 'GetTickCount64'" */
56 WINBASEAPI ULONGLONG WINAPI GetTickCount64(void);
57 #endif
59 gint64
60 mono_msec_boottime (void)
62 /* GetTickCount () is reportedly monotonic */
63 return GetTickCount64 ();
66 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
67 gint64
68 mono_100ns_ticks (void)
70 static LARGE_INTEGER freq;
71 static UINT64 start_time;
72 UINT64 cur_time;
73 LARGE_INTEGER value;
75 if (!freq.QuadPart) {
76 if (!QueryPerformanceFrequency (&freq))
77 return mono_100ns_datetime ();
78 QueryPerformanceCounter (&value);
79 start_time = value.QuadPart;
81 QueryPerformanceCounter (&value);
82 cur_time = value.QuadPart;
83 /* we use unsigned numbers and return the difference to avoid overflows */
84 return (cur_time - start_time) * (double)MTICKS_PER_SEC / freq.QuadPart;
87 /* Returns the number of 100ns ticks since Jan 1, 1601, UTC timezone */
88 gint64
89 mono_100ns_datetime (void)
91 ULARGE_INTEGER ft;
93 if (sizeof(ft) != sizeof(FILETIME))
94 g_assert_not_reached ();
96 GetSystemTimeAsFileTime ((FILETIME*) &ft);
97 return ft.QuadPart;
100 #else
103 #if defined (HAVE_SYS_PARAM_H)
104 #include <sys/param.h>
105 #endif
106 #if defined(HAVE_SYS_SYSCTL_H)
107 #include <sys/sysctl.h>
108 #endif
110 #if defined(HOST_DARWIN)
111 #include <mach/mach.h>
112 #include <mach/mach_time.h>
113 #endif
115 #include <time.h>
117 /* Returns the number of milliseconds from boot time: this should be monotonic */
118 /* Adapted from CoreCLR: https://github.com/dotnet/coreclr/blob/66d2738ea96fcce753dec1370e79a0c78f7b6adb/src/pal/src/misc/time.cpp */
119 gint64
120 mono_msec_boottime (void)
122 /* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */
123 #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)))
124 clockid_t clockType =
125 #if HAVE_CLOCK_MONOTONIC_COARSE
126 CLOCK_MONOTONIC_COARSE; /* good enough resolution, fastest speed */
127 #else
128 CLOCK_MONOTONIC;
129 #endif
130 struct timespec ts;
131 if (clock_gettime (clockType, &ts) != 0) {
132 g_error ("clock_gettime(CLOCK_MONOTONIC*) failed; errno is %d", errno, strerror (errno));
133 return 0;
135 return (ts.tv_sec * tccSecondsToMillieSeconds) + (ts.tv_nsec / tccMillieSecondsToNanoSeconds);
137 #elif HAVE_MACH_ABSOLUTE_TIME
138 static gboolean timebase_inited;
139 static mach_timebase_info_data_t s_TimebaseInfo;
141 if (!timebase_inited) {
142 kern_return_t machRet;
143 mach_timebase_info_data_t tmp;
144 machRet = mach_timebase_info (&tmp);
145 g_assert (machRet == KERN_SUCCESS);
146 /* Assume memcpy works correctly if ran concurrently */
147 memcpy (&s_TimebaseInfo, &tmp, sizeof (mach_timebase_info_data_t));
148 mono_memory_barrier ();
149 timebase_inited = TRUE;
150 } else {
151 // This barrier prevents reading s_TimebaseInfo before reading timebase_inited.
152 mono_memory_barrier ();
154 return (mach_absolute_time () * s_TimebaseInfo.numer / s_TimebaseInfo.denom) / tccMillieSecondsToNanoSeconds;
156 #elif HAVE_GETHRTIME
157 return (gint64)(gethrtime () / tccMillieSecondsToNanoSeconds);
159 #elif HAVE_READ_REAL_TIME
160 timebasestruct_t tb;
161 read_real_time (&tb, TIMEBASE_SZ);
162 if (time_base_to_time (&tb, TIMEBASE_SZ) != 0) {
163 g_error ("time_base_to_time() failed; errno is %d (%s)", errno, strerror (errno));
164 return 0;
166 return (tb.tb_high * tccSecondsToMillieSeconds) + (tb.tb_low / tccMillieSecondsToNanoSeconds);
168 #else
169 struct timeval tv;
170 if (gettimeofday (&tv, NULL) == -1) {
171 g_error ("gettimeofday() failed; errno is %d (%s)", errno, strerror (errno));
172 return 0;
174 return (tv.tv_sec * tccSecondsToMillieSeconds) + (tv.tv_usec / tccMillieSecondsToMicroSeconds);
176 #endif /* HAVE_CLOCK_MONOTONIC */
179 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
180 gint64
181 mono_100ns_ticks (void)
183 struct timeval tv;
184 #if defined(HOST_DARWIN)
185 /* http://developer.apple.com/library/mac/#qa/qa1398/_index.html */
186 static mach_timebase_info_data_t timebase;
187 guint64 now = mach_absolute_time ();
188 if (timebase.denom == 0) {
189 mach_timebase_info (&timebase);
190 timebase.denom *= 100; /* we return 100ns ticks */
192 return now * timebase.numer / timebase.denom;
193 #elif defined(CLOCK_MONOTONIC) && !defined(__PASE__)
194 /* !__PASE__ is defined because i 7.1 doesn't have clock_getres */
195 struct timespec tspec;
196 static struct timespec tspec_freq = {0};
197 static int can_use_clock = 0;
198 if (!tspec_freq.tv_nsec) {
199 can_use_clock = clock_getres (CLOCK_MONOTONIC, &tspec_freq) == 0;
200 /*printf ("resolution: %lu.%lu\n", tspec_freq.tv_sec, tspec_freq.tv_nsec);*/
202 if (can_use_clock) {
203 if (clock_gettime (CLOCK_MONOTONIC, &tspec) == 0) {
204 /*printf ("time: %lu.%lu\n", tspec.tv_sec, tspec.tv_nsec); */
205 return ((gint64)tspec.tv_sec * MTICKS_PER_SEC + tspec.tv_nsec / 100);
208 #endif
209 if (gettimeofday (&tv, NULL) == 0)
210 return ((gint64)tv.tv_sec * 1000000 + tv.tv_usec) * 10;
211 return 0;
215 * Magic number to convert unix epoch start to windows epoch start
216 * Jan 1, 1970 into a value which is relative to Jan 1, 1601.
218 #define EPOCH_ADJUST ((guint64)11644473600LL)
220 /* Returns the number of 100ns ticks since 1/1/1601, UTC timezone */
221 gint64
222 mono_100ns_datetime (void)
224 struct timeval tv;
225 if (gettimeofday (&tv, NULL) == 0)
226 return mono_100ns_datetime_from_timeval (tv);
227 return 0;
230 gint64
231 mono_100ns_datetime_from_timeval (struct timeval tv)
233 return (((gint64)tv.tv_sec + EPOCH_ADJUST) * 1000000 + tv.tv_usec) * 10;
236 #endif
238 #if defined(HOST_DARWIN)
240 void
241 mono_clock_init (mono_clock_id_t *clk_id)
243 kern_return_t ret;
245 do {
246 ret = host_get_clock_service (mach_host_self (), SYSTEM_CLOCK, clk_id);
247 } while (ret == KERN_ABORTED);
249 if (ret != KERN_SUCCESS)
250 g_error ("%s: host_get_clock_service () returned %d", __func__, ret);
253 void
254 mono_clock_cleanup (mono_clock_id_t clk_id)
256 kern_return_t ret;
258 do {
259 ret = mach_port_deallocate (mach_task_self (), clk_id);
260 } while (ret == KERN_ABORTED);
262 if (ret != KERN_SUCCESS)
263 g_error ("%s: mach_port_deallocate () returned %d", __func__, ret);
266 guint64
267 mono_clock_get_time_ns (mono_clock_id_t clk_id)
269 kern_return_t ret;
270 mach_timespec_t mach_ts;
272 do {
273 ret = clock_get_time (clk_id, &mach_ts);
274 } while (ret == KERN_ABORTED);
276 if (ret != KERN_SUCCESS)
277 g_error ("%s: clock_get_time () returned %d", __func__, ret);
279 return ((guint64) mach_ts.tv_sec * 1000000000) + (guint64) mach_ts.tv_nsec;
282 // TODO: Potentially make this the default?
283 // Can we assume clock_gettime exists on all modern POSIX systems? Maybe add a better check for it in configure.ac?
284 #elif defined(__linux__) || defined (TARGET_WASM)
286 void
287 mono_clock_init (mono_clock_id_t *clk_id)
289 #ifdef HAVE_CLOCK_MONOTONIC
290 *clk_id = CLOCK_MONOTONIC;
291 #endif
294 void
295 mono_clock_cleanup (mono_clock_id_t clk_id)
299 guint64
300 mono_clock_get_time_ns (mono_clock_id_t clk_id)
302 #ifdef HAVE_CLOCK_GETTIME
303 struct timespec ts;
305 if (clock_gettime (clk_id, &ts) == -1)
306 g_error ("%s: clock_gettime () returned -1, errno = %d", __func__, errno);
308 return ((guint64) ts.tv_sec * 1000000000) + (guint64) ts.tv_nsec;
309 #else
310 return 0;
311 #endif
314 #else
316 void
317 mono_clock_init (mono_clock_id_t *clk_id)
319 // TODO: need to implement this function for Windows
322 void
323 mono_clock_cleanup (mono_clock_id_t clk_id)
325 // TODO: need to implement this function for Windows
328 guint64
329 mono_clock_get_time_ns (mono_clock_id_t clk_id)
331 // TODO: need to implement time stamp function for Windows
332 return 0;
335 #endif