Merge pull request #231 from linquize/a853199c497bb0977970974303fac7e42080809d
[mono.git] / mono / utils / mono-time.c
1 /*
2  * Time utility functions.
3  * Author: Paolo Molaro (<lupus@ximian.com>)
4  * Copyright (C) 2008 Novell, Inc.
5  */
6
7 #include <utils/mono-time.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10
11 #define MTICKS_PER_SEC 10000000
12
13 #ifdef HOST_WIN32
14 #include <windows.h>
15
16 guint32
17 mono_msec_ticks (void)
18 {
19         /* GetTickCount () is reportedly monotonic */
20         return GetTickCount ();
21 }
22
23 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
24 gint64
25 mono_100ns_ticks (void)
26 {
27         static LARGE_INTEGER freq;
28         static UINT64 start_time;
29         UINT64 cur_time;
30         LARGE_INTEGER value;
31
32         if (!freq.QuadPart) {
33                 if (!QueryPerformanceFrequency (&freq))
34                         return mono_100ns_datetime ();
35                 QueryPerformanceCounter (&value);
36                 start_time = value.QuadPart;
37         }
38         QueryPerformanceCounter (&value);
39         cur_time = value.QuadPart;
40         /* we use unsigned numbers and return the difference to avoid overflows */
41         return (cur_time - start_time) * (double)MTICKS_PER_SEC / freq.QuadPart;
42 }
43
44 /*
45  * Magic number to convert FILETIME base Jan 1, 1601 to DateTime - base Jan, 1, 0001
46  */
47 #define FILETIME_ADJUST ((guint64)504911232000000000LL)
48
49 /* Returns the number of 100ns ticks since 1/1/1, UTC timezone */
50 gint64
51 mono_100ns_datetime (void)
52 {
53         ULARGE_INTEGER ft;
54
55         if (sizeof(ft) != sizeof(FILETIME))
56                 g_assert_not_reached ();
57
58         GetSystemTimeAsFileTime ((FILETIME*) &ft);
59         return FILETIME_ADJUST + ft.QuadPart;
60 }
61
62 #else
63
64 #ifdef HAVE_SYS_TIME_H
65 #include <sys/time.h>
66 #endif
67
68 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
69 #include <sys/param.h>
70 #include <sys/sysctl.h>
71 #endif
72
73 #if defined(PLATFORM_MACOSX)
74 #include <mach/mach.h>
75 #include <mach/mach_time.h>
76 #endif
77
78 #include <time.h>
79
80 static gint64
81 get_boot_time (void)
82 {
83 #if defined(PLATFORM_MACOSX) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
84         int mib [2];
85         size_t size;
86         time_t now;
87         struct timeval boottime;
88
89         (void)time(&now);
90
91         mib [0] = CTL_KERN;
92         mib [1] = KERN_BOOTTIME;
93
94         size = sizeof(boottime);
95
96         if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1)
97                 return (gint64)((now - boottime.tv_sec) * MTICKS_PER_SEC);
98 #else
99         FILE *uptime = fopen ("/proc/uptime", "r");
100         if (uptime) {
101                 double upt;
102                 if (fscanf (uptime, "%lf", &upt) == 1) {
103                         gint64 now = mono_100ns_ticks ();
104                         fclose (uptime);
105                         return now - (gint64)(upt * MTICKS_PER_SEC);
106                 }
107                 fclose (uptime);
108         }
109 #endif
110         /* a made up uptime of 300 seconds */
111         return (gint64)300 * MTICKS_PER_SEC;
112 }
113
114 /* Returns the number of milliseconds from boot time: this should be monotonic */
115 guint32
116 mono_msec_ticks (void)
117 {
118         static gint64 boot_time = 0;
119         gint64 now;
120         if (!boot_time)
121                 boot_time = get_boot_time ();
122         now = mono_100ns_ticks ();
123         /*printf ("now: %llu (boot: %llu) ticks: %llu\n", (gint64)now, (gint64)boot_time, (gint64)(now - boot_time));*/
124         return (now - boot_time)/10000;
125 }
126
127 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
128 gint64
129 mono_100ns_ticks (void)
130 {
131         struct timeval tv;
132 #ifdef CLOCK_MONOTONIC
133         struct timespec tspec;
134         static struct timespec tspec_freq = {0};
135         static int can_use_clock = 0;
136         if (!tspec_freq.tv_nsec) {
137                 can_use_clock = clock_getres (CLOCK_MONOTONIC, &tspec_freq) == 0;
138                 /*printf ("resolution: %lu.%lu\n", tspec_freq.tv_sec, tspec_freq.tv_nsec);*/
139         }
140         if (can_use_clock) {
141                 if (clock_gettime (CLOCK_MONOTONIC, &tspec) == 0) {
142                         /*printf ("time: %lu.%lu\n", tspec.tv_sec, tspec.tv_nsec); */
143                         return ((gint64)tspec.tv_sec * MTICKS_PER_SEC + tspec.tv_nsec / 100);
144                 }
145         }
146         
147 #elif defined(PLATFORM_MACOSX)
148         /* http://developer.apple.com/library/mac/#qa/qa1398/_index.html */
149         static mach_timebase_info_data_t timebase;
150         guint64 now = mach_absolute_time ();
151         if (timebase.denom == 0) {
152                 mach_timebase_info (&timebase);
153                 timebase.denom *= 100; /* we return 100ns ticks */
154         }
155         return now * timebase.numer / timebase.denom;
156 #endif
157         if (gettimeofday (&tv, NULL) == 0)
158                 return ((gint64)tv.tv_sec * 1000000 + tv.tv_usec) * 10;
159         return 0;
160 }
161
162 /*
163  * Magic number to convert a time which is relative to
164  * Jan 1, 1970 into a value which is relative to Jan 1, 0001.
165  */
166 #define EPOCH_ADJUST    ((guint64)62135596800LL)
167
168 /* Returns the number of 100ns ticks since 1/1/1, UTC timezone */
169 gint64
170 mono_100ns_datetime (void)
171 {
172         struct timeval tv;
173         if (gettimeofday (&tv, NULL) == 0)
174                 return (((gint64)tv.tv_sec + EPOCH_ADJUST) * 1000000 + tv.tv_usec) * 10;
175         return 0;
176 }
177
178 #endif
179