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