diff options
Diffstat (limited to 'toxcore/mono_time.c')
-rw-r--r-- | toxcore/mono_time.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/toxcore/mono_time.c b/toxcore/mono_time.c new file mode 100644 index 00000000..6f54731b --- /dev/null +++ b/toxcore/mono_time.c | |||
@@ -0,0 +1,157 @@ | |||
1 | #ifndef _XOPEN_SOURCE | ||
2 | #define _XOPEN_SOURCE 600 | ||
3 | #endif | ||
4 | |||
5 | #if !defined(OS_WIN32) && (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) | ||
6 | #define OS_WIN32 | ||
7 | #define WIN32_LEAN_AND_MEAN | ||
8 | #include <windows.h> | ||
9 | #endif | ||
10 | |||
11 | #ifdef __APPLE__ | ||
12 | #include <mach/clock.h> | ||
13 | #include <mach/mach.h> | ||
14 | #endif | ||
15 | |||
16 | #ifndef OS_WIN32 | ||
17 | #include <sys/time.h> | ||
18 | #endif | ||
19 | |||
20 | #include "mono_time.h" | ||
21 | |||
22 | #include <stdlib.h> | ||
23 | #include <time.h> | ||
24 | |||
25 | #include "ccompat.h" | ||
26 | |||
27 | /* don't call into system billions of times for no reason */ | ||
28 | struct Mono_Time { | ||
29 | uint64_t time; | ||
30 | uint64_t base_time; | ||
31 | }; | ||
32 | |||
33 | Mono_Time *mono_time_new(void) | ||
34 | { | ||
35 | Mono_Time *monotime = (Mono_Time *)malloc(sizeof(Mono_Time)); | ||
36 | |||
37 | if (monotime == nullptr) { | ||
38 | return nullptr; | ||
39 | } | ||
40 | |||
41 | monotime->time = 0; | ||
42 | monotime->base_time = 0; | ||
43 | |||
44 | return monotime; | ||
45 | } | ||
46 | |||
47 | void mono_time_free(Mono_Time *monotime) | ||
48 | { | ||
49 | free(monotime); | ||
50 | } | ||
51 | |||
52 | void mono_time_update(Mono_Time *monotime) | ||
53 | { | ||
54 | if (monotime->base_time == 0) { | ||
55 | monotime->base_time = ((uint64_t)time(nullptr) - (current_time_monotonic() / 1000ULL)); | ||
56 | } | ||
57 | |||
58 | monotime->time = (current_time_monotonic() / 1000ULL) + monotime->base_time; | ||
59 | } | ||
60 | |||
61 | uint64_t mono_time_get(const Mono_Time *monotime) | ||
62 | { | ||
63 | return monotime->time; | ||
64 | } | ||
65 | |||
66 | bool mono_time_is_timeout(const Mono_Time *monotime, uint64_t timestamp, uint64_t timeout) | ||
67 | { | ||
68 | return timestamp + timeout <= mono_time_get(monotime); | ||
69 | } | ||
70 | |||
71 | |||
72 | static Mono_Time global_time; | ||
73 | |||
74 | /* XXX: note that this is not thread-safe; if multiple threads call unix_time_update() concurrently, the return value of | ||
75 | * unix_time() may fail to increase monotonically with increasing time */ | ||
76 | void unix_time_update(void) | ||
77 | { | ||
78 | mono_time_update(&global_time); | ||
79 | } | ||
80 | uint64_t unix_time(void) | ||
81 | { | ||
82 | return mono_time_get(&global_time); | ||
83 | } | ||
84 | int is_timeout(uint64_t timestamp, uint64_t timeout) | ||
85 | { | ||
86 | return mono_time_is_timeout(&global_time, timestamp, timeout); | ||
87 | } | ||
88 | |||
89 | |||
90 | |||
91 | /* return current UNIX time in microseconds (us). */ | ||
92 | uint64_t current_time_actual(void) | ||
93 | { | ||
94 | uint64_t time; | ||
95 | #ifdef OS_WIN32 | ||
96 | /* This probably works fine */ | ||
97 | FILETIME ft; | ||
98 | GetSystemTimeAsFileTime(&ft); | ||
99 | time = ft.dwHighDateTime; | ||
100 | time <<= 32; | ||
101 | time |= ft.dwLowDateTime; | ||
102 | time -= 116444736000000000ULL; | ||
103 | return time / 10; | ||
104 | #else | ||
105 | struct timeval a; | ||
106 | gettimeofday(&a, nullptr); | ||
107 | time = 1000000ULL * a.tv_sec + a.tv_usec; | ||
108 | return time; | ||
109 | #endif | ||
110 | } | ||
111 | |||
112 | |||
113 | #ifdef OS_WIN32 | ||
114 | static uint64_t last_monotime; | ||
115 | static uint64_t add_monotime; | ||
116 | #endif | ||
117 | |||
118 | /* return current monotonic time in milliseconds (ms). */ | ||
119 | uint64_t current_time_monotonic(void) | ||
120 | { | ||
121 | uint64_t time; | ||
122 | #ifdef OS_WIN32 | ||
123 | uint64_t old_add_monotime = add_monotime; | ||
124 | time = (uint64_t)GetTickCount() + add_monotime; | ||
125 | |||
126 | /* Check if time has decreased because of 32 bit wrap from GetTickCount(), while avoiding false positives from race | ||
127 | * conditions when multiple threads call this function at once */ | ||
128 | if (time + 0x10000 < last_monotime) { | ||
129 | uint32_t add = ~0; | ||
130 | /* use old_add_monotime rather than simply incrementing add_monotime, to handle the case that many threads | ||
131 | * simultaneously detect an overflow */ | ||
132 | add_monotime = old_add_monotime + add; | ||
133 | time += add; | ||
134 | } | ||
135 | |||
136 | last_monotime = time; | ||
137 | #else | ||
138 | struct timespec monotime; | ||
139 | #if defined(__linux__) && defined(CLOCK_MONOTONIC_RAW) | ||
140 | clock_gettime(CLOCK_MONOTONIC_RAW, &monotime); | ||
141 | #elif defined(__APPLE__) | ||
142 | clock_serv_t muhclock; | ||
143 | mach_timespec_t machtime; | ||
144 | |||
145 | host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &muhclock); | ||
146 | clock_get_time(muhclock, &machtime); | ||
147 | mach_port_deallocate(mach_task_self(), muhclock); | ||
148 | |||
149 | monotime.tv_sec = machtime.tv_sec; | ||
150 | monotime.tv_nsec = machtime.tv_nsec; | ||
151 | #else | ||
152 | clock_gettime(CLOCK_MONOTONIC, &monotime); | ||
153 | #endif | ||
154 | time = 1000ULL * monotime.tv_sec + (monotime.tv_nsec / 1000000ULL); | ||
155 | #endif | ||
156 | return time; | ||
157 | } | ||