[runtime] Use HOST_ defines instead of PLATFORM_ defines. (#5362)
[mono.git] / mono / utils / mono-time.c
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  */
8
9 #include <config.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12
13 #ifdef HAVE_SYS_TIME_H
14 #include <sys/time.h>
15 #endif
16
17 #include <utils/mono-time.h>
18
19
20 #define MTICKS_PER_SEC (10 * 1000 * 1000)
21
22 gint64
23 mono_msec_ticks (void)
24 {
25         return mono_100ns_ticks () / 10 / 1000;
26 }
27
28 #ifdef HOST_WIN32
29 #include <windows.h>
30
31 #ifndef _MSC_VER
32 /* we get "error: implicit declaration of function 'GetTickCount64'" */
33 WINBASEAPI ULONGLONG WINAPI GetTickCount64(void);
34 #endif
35
36 gint64
37 mono_msec_boottime (void)
38 {
39         /* GetTickCount () is reportedly monotonic */
40         return GetTickCount64 ();
41 }
42
43 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
44 gint64
45 mono_100ns_ticks (void)
46 {
47         static LARGE_INTEGER freq;
48         static UINT64 start_time;
49         UINT64 cur_time;
50         LARGE_INTEGER value;
51
52         if (!freq.QuadPart) {
53                 if (!QueryPerformanceFrequency (&freq))
54                         return mono_100ns_datetime ();
55                 QueryPerformanceCounter (&value);
56                 start_time = value.QuadPart;
57         }
58         QueryPerformanceCounter (&value);
59         cur_time = value.QuadPart;
60         /* we use unsigned numbers and return the difference to avoid overflows */
61         return (cur_time - start_time) * (double)MTICKS_PER_SEC / freq.QuadPart;
62 }
63
64 /* Returns the number of 100ns ticks since Jan 1, 1601, UTC timezone */
65 gint64
66 mono_100ns_datetime (void)
67 {
68         ULARGE_INTEGER ft;
69
70         if (sizeof(ft) != sizeof(FILETIME))
71                 g_assert_not_reached ();
72
73         GetSystemTimeAsFileTime ((FILETIME*) &ft);
74         return ft.QuadPart;
75 }
76
77 #else
78
79
80 #if defined (HAVE_SYS_PARAM_H)
81 #include <sys/param.h>
82 #endif
83 #if defined(HAVE_SYS_SYSCTL_H)
84 #include <sys/sysctl.h>
85 #endif
86
87 #if defined(HOST_DARWIN)
88 #include <mach/mach.h>
89 #include <mach/mach_time.h>
90 #endif
91
92 #include <time.h>
93
94 static gint64
95 get_boot_time (void)
96 {
97 #if defined (HAVE_SYS_PARAM_H) && defined (KERN_BOOTTIME)
98         int mib [2];
99         size_t size;
100         time_t now;
101         struct timeval boottime;
102
103         (void)time(&now);
104
105         mib [0] = CTL_KERN;
106         mib [1] = KERN_BOOTTIME;
107
108         size = sizeof(boottime);
109
110         if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1)
111                 return (gint64)((now - boottime.tv_sec) * MTICKS_PER_SEC);
112 #else
113         FILE *uptime = fopen ("/proc/uptime", "r");
114         if (uptime) {
115                 double upt;
116                 if (fscanf (uptime, "%lf", &upt) == 1) {
117                         gint64 now = mono_100ns_datetime ();
118                         fclose (uptime);
119                         return now - (gint64)(upt * MTICKS_PER_SEC);
120                 }
121                 fclose (uptime);
122         }
123 #endif
124         /* a made up uptime of 300 seconds */
125         return (gint64)300 * MTICKS_PER_SEC;
126 }
127
128 /* Returns the number of milliseconds from boot time: this should be monotonic */
129 gint64
130 mono_msec_boottime (void)
131 {
132         static gint64 boot_time = 0;
133         gint64 now;
134         if (!boot_time)
135                 boot_time = get_boot_time ();
136         now = mono_100ns_datetime ();
137         /*printf ("now: %llu (boot: %llu) ticks: %llu\n", (gint64)now, (gint64)boot_time, (gint64)(now - boot_time));*/
138         return (now - boot_time)/10000;
139 }
140
141 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
142 gint64
143 mono_100ns_ticks (void)
144 {
145         struct timeval tv;
146 #if defined(HOST_DARWIN)
147         /* http://developer.apple.com/library/mac/#qa/qa1398/_index.html */
148         static mach_timebase_info_data_t timebase;
149         guint64 now = mach_absolute_time ();
150         if (timebase.denom == 0) {
151                 mach_timebase_info (&timebase);
152                 timebase.denom *= 100; /* we return 100ns ticks */
153         }
154         return now * timebase.numer / timebase.denom;
155 #elif defined(CLOCK_MONOTONIC)
156         struct timespec tspec;
157         static struct timespec tspec_freq = {0};
158         static int can_use_clock = 0;
159         if (!tspec_freq.tv_nsec) {
160                 can_use_clock = clock_getres (CLOCK_MONOTONIC, &tspec_freq) == 0;
161                 /*printf ("resolution: %lu.%lu\n", tspec_freq.tv_sec, tspec_freq.tv_nsec);*/
162         }
163         if (can_use_clock) {
164                 if (clock_gettime (CLOCK_MONOTONIC, &tspec) == 0) {
165                         /*printf ("time: %lu.%lu\n", tspec.tv_sec, tspec.tv_nsec); */
166                         return ((gint64)tspec.tv_sec * MTICKS_PER_SEC + tspec.tv_nsec / 100);
167                 }
168         }
169 #endif
170         if (gettimeofday (&tv, NULL) == 0)
171                 return ((gint64)tv.tv_sec * 1000000 + tv.tv_usec) * 10;
172         return 0;
173 }
174
175 /*
176  * Magic number to convert unix epoch start to windows epoch start
177  * Jan 1, 1970 into a value which is relative to Jan 1, 1601.
178  */
179 #define EPOCH_ADJUST    ((guint64)11644473600LL)
180
181 /* Returns the number of 100ns ticks since 1/1/1601, UTC timezone */
182 gint64
183 mono_100ns_datetime (void)
184 {
185         struct timeval tv;
186         if (gettimeofday (&tv, NULL) == 0)
187                 return mono_100ns_datetime_from_timeval (tv);
188         return 0;
189 }
190
191 gint64
192 mono_100ns_datetime_from_timeval (struct timeval tv)
193 {
194         return (((gint64)tv.tv_sec + EPOCH_ADJUST) * 1000000 + tv.tv_usec) * 10;
195 }
196
197 #endif
198