summaryrefslogtreecommitdiff
path: root/toxcore/mono_time.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxcore/mono_time.c')
-rw-r--r--toxcore/mono_time.c157
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 */
28struct Mono_Time {
29 uint64_t time;
30 uint64_t base_time;
31};
32
33Mono_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
47void mono_time_free(Mono_Time *monotime)
48{
49 free(monotime);
50}
51
52void 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
61uint64_t mono_time_get(const Mono_Time *monotime)
62{
63 return monotime->time;
64}
65
66bool 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
72static 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 */
76void unix_time_update(void)
77{
78 mono_time_update(&global_time);
79}
80uint64_t unix_time(void)
81{
82 return mono_time_get(&global_time);
83}
84int 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). */
92uint64_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
114static uint64_t last_monotime;
115static uint64_t add_monotime;
116#endif
117
118/* return current monotonic time in milliseconds (ms). */
119uint64_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}