/work/toxcore/mono_time.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2016-2023 The TokTok team. |
3 | | * Copyright © 2014 Tox project. |
4 | | */ |
5 | | #ifndef _XOPEN_SOURCE |
6 | | #define _XOPEN_SOURCE 600 |
7 | | #endif /* _XOPEN_SOURCE */ |
8 | | |
9 | | #if !defined(OS_WIN32) && (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) |
10 | | #define OS_WIN32 |
11 | | #endif /* WIN32 */ |
12 | | |
13 | | #include "mono_time.h" |
14 | | |
15 | | #ifdef OS_WIN32 |
16 | | #define WIN32_LEAN_AND_MEAN |
17 | | #include <windows.h> |
18 | | #endif /* OS_WIN32 */ |
19 | | |
20 | | #ifdef __APPLE__ |
21 | | #include <mach/clock.h> |
22 | | #include <mach/mach.h> |
23 | | #endif /* __APPLE__ */ |
24 | | |
25 | | #ifndef OS_WIN32 |
26 | | #include <sys/time.h> |
27 | | #endif /* OS_WIN32 */ |
28 | | |
29 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
30 | | #include <assert.h> |
31 | | #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ |
32 | | #include <pthread.h> |
33 | | #include <time.h> |
34 | | |
35 | | #include "ccompat.h" |
36 | | #include "mem.h" |
37 | | #include "util.h" |
38 | | |
39 | | /** don't call into system billions of times for no reason */ |
40 | | struct Mono_Time { |
41 | | uint64_t cur_time; |
42 | | uint64_t base_time; |
43 | | |
44 | | #ifndef ESP_PLATFORM |
45 | | /* protect `time` from concurrent access */ |
46 | | pthread_rwlock_t *time_update_lock; |
47 | | #endif /* ESP_PLATFORM */ |
48 | | |
49 | | mono_time_current_time_cb *current_time_callback; |
50 | | void *user_data; |
51 | | }; |
52 | | |
53 | | static uint64_t timespec_to_u64(struct timespec clock_mono) |
54 | 7.39M | { |
55 | 7.39M | return UINT64_C(1000) * clock_mono.tv_sec + (clock_mono.tv_nsec / UINT64_C(1000000)); |
56 | 7.39M | } |
57 | | |
58 | | #ifdef OS_WIN32 |
59 | | non_null() |
60 | | static uint64_t current_time_monotonic_default(void *user_data) |
61 | | { |
62 | | LARGE_INTEGER freq; |
63 | | LARGE_INTEGER count; |
64 | | if (!QueryPerformanceFrequency(&freq)) { |
65 | | return 0; |
66 | | } |
67 | | if (!QueryPerformanceCounter(&count)) { |
68 | | return 0; |
69 | | } |
70 | | struct timespec sp = {0}; |
71 | | sp.tv_sec = count.QuadPart / freq.QuadPart; |
72 | | if (freq.QuadPart < 1000000000) { |
73 | | sp.tv_nsec = (count.QuadPart % freq.QuadPart) * 1000000000 / freq.QuadPart; |
74 | | } else { |
75 | | sp.tv_nsec = (long)((count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart)); |
76 | | } |
77 | | return timespec_to_u64(sp); |
78 | | } |
79 | | #else |
80 | | #ifdef __APPLE__ |
81 | | non_null() |
82 | | static uint64_t current_time_monotonic_default(void *user_data) |
83 | | { |
84 | | struct timespec clock_mono; |
85 | | clock_serv_t muhclock; |
86 | | mach_timespec_t machtime; |
87 | | |
88 | | host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &muhclock); |
89 | | clock_get_time(muhclock, &machtime); |
90 | | mach_port_deallocate(mach_task_self(), muhclock); |
91 | | |
92 | | clock_mono.tv_sec = machtime.tv_sec; |
93 | | clock_mono.tv_nsec = machtime.tv_nsec; |
94 | | return timespec_to_u64(clock_mono); |
95 | | } |
96 | | #else // !__APPLE__ |
97 | | non_null() |
98 | | static uint64_t current_time_monotonic_default(void *user_data) |
99 | 0 | { |
100 | 0 | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
101 | | // This assert should always fail. If it does, the fuzzing harness didn't |
102 | | // override the mono time callback. |
103 | 0 | assert(user_data == nullptr); |
104 | 0 | #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ |
105 | 0 | struct timespec clock_mono; |
106 | 0 | clock_gettime(CLOCK_MONOTONIC, &clock_mono); |
107 | 0 | return timespec_to_u64(clock_mono); |
108 | 0 | } |
109 | | #endif /* !__APPLE__ */ |
110 | | #endif /* !OS_WIN32 */ |
111 | | |
112 | | |
113 | | Mono_Time *mono_time_new(const Memory *mem, mono_time_current_time_cb *current_time_callback, void *user_data) |
114 | 9.02k | { |
115 | 9.02k | Mono_Time *mono_time = (Mono_Time *)mem_alloc(mem, sizeof(Mono_Time)); |
116 | | |
117 | 9.02k | if (mono_time == nullptr) { |
118 | 26 | return nullptr; |
119 | 26 | } |
120 | | |
121 | 9.00k | #ifndef ESP_PLATFORM |
122 | 9.00k | pthread_rwlock_t *rwlock = (pthread_rwlock_t *)mem_alloc(mem, sizeof(pthread_rwlock_t)); |
123 | | |
124 | 9.00k | if (rwlock == nullptr) { |
125 | 26 | mem_delete(mem, mono_time); |
126 | 26 | return nullptr; |
127 | 26 | } |
128 | | |
129 | 8.97k | if (pthread_rwlock_init(rwlock, nullptr) != 0) { |
130 | 0 | mem_delete(mem, rwlock); |
131 | 0 | mem_delete(mem, mono_time); |
132 | 0 | return nullptr; |
133 | 0 | } |
134 | | |
135 | 8.97k | mono_time->time_update_lock = rwlock; |
136 | 8.97k | #endif /* ESP_PLATFORM */ |
137 | | |
138 | 8.97k | mono_time_set_current_time_callback(mono_time, current_time_callback, user_data); |
139 | | |
140 | 8.97k | mono_time->cur_time = 0; |
141 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
142 | | // Maximum reproducibility. Never return time = 0. |
143 | | mono_time->base_time = 1000000000; |
144 | | #else |
145 | | // Never return time = 0 in case time() returns 0 (e.g. on microcontrollers |
146 | | // without battery-powered RTC or ones where NTP didn't initialise it yet). |
147 | 4.48k | mono_time->base_time = max_u64(1, (uint64_t)time(nullptr)) * UINT64_C(1000) - current_time_monotonic(mono_time); |
148 | | #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ |
149 | | |
150 | 8.97k | mono_time_update(mono_time); |
151 | | |
152 | 8.97k | return mono_time; |
153 | 8.97k | } Line | Count | Source | 114 | 4.51k | { | 115 | 4.51k | Mono_Time *mono_time = (Mono_Time *)mem_alloc(mem, sizeof(Mono_Time)); | 116 | | | 117 | 4.51k | if (mono_time == nullptr) { | 118 | 13 | return nullptr; | 119 | 13 | } | 120 | | | 121 | 4.50k | #ifndef ESP_PLATFORM | 122 | 4.50k | pthread_rwlock_t *rwlock = (pthread_rwlock_t *)mem_alloc(mem, sizeof(pthread_rwlock_t)); | 123 | | | 124 | 4.50k | if (rwlock == nullptr) { | 125 | 13 | mem_delete(mem, mono_time); | 126 | 13 | return nullptr; | 127 | 13 | } | 128 | | | 129 | 4.48k | if (pthread_rwlock_init(rwlock, nullptr) != 0) { | 130 | 0 | mem_delete(mem, rwlock); | 131 | 0 | mem_delete(mem, mono_time); | 132 | 0 | return nullptr; | 133 | 0 | } | 134 | | | 135 | 4.48k | mono_time->time_update_lock = rwlock; | 136 | 4.48k | #endif /* ESP_PLATFORM */ | 137 | | | 138 | 4.48k | mono_time_set_current_time_callback(mono_time, current_time_callback, user_data); | 139 | | | 140 | 4.48k | mono_time->cur_time = 0; | 141 | 4.48k | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION | 142 | | // Maximum reproducibility. Never return time = 0. | 143 | 4.48k | mono_time->base_time = 1000000000; | 144 | | #else | 145 | | // Never return time = 0 in case time() returns 0 (e.g. on microcontrollers | 146 | | // without battery-powered RTC or ones where NTP didn't initialise it yet). | 147 | | mono_time->base_time = max_u64(1, (uint64_t)time(nullptr)) * UINT64_C(1000) - current_time_monotonic(mono_time); | 148 | | #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ | 149 | | | 150 | 4.48k | mono_time_update(mono_time); | 151 | | | 152 | 4.48k | return mono_time; | 153 | 4.48k | } |
Line | Count | Source | 114 | 4.51k | { | 115 | 4.51k | Mono_Time *mono_time = (Mono_Time *)mem_alloc(mem, sizeof(Mono_Time)); | 116 | | | 117 | 4.51k | if (mono_time == nullptr) { | 118 | 13 | return nullptr; | 119 | 13 | } | 120 | | | 121 | 4.50k | #ifndef ESP_PLATFORM | 122 | 4.50k | pthread_rwlock_t *rwlock = (pthread_rwlock_t *)mem_alloc(mem, sizeof(pthread_rwlock_t)); | 123 | | | 124 | 4.50k | if (rwlock == nullptr) { | 125 | 13 | mem_delete(mem, mono_time); | 126 | 13 | return nullptr; | 127 | 13 | } | 128 | | | 129 | 4.48k | if (pthread_rwlock_init(rwlock, nullptr) != 0) { | 130 | 0 | mem_delete(mem, rwlock); | 131 | 0 | mem_delete(mem, mono_time); | 132 | 0 | return nullptr; | 133 | 0 | } | 134 | | | 135 | 4.48k | mono_time->time_update_lock = rwlock; | 136 | 4.48k | #endif /* ESP_PLATFORM */ | 137 | | | 138 | 4.48k | mono_time_set_current_time_callback(mono_time, current_time_callback, user_data); | 139 | | | 140 | 4.48k | mono_time->cur_time = 0; | 141 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION | 142 | | // Maximum reproducibility. Never return time = 0. | 143 | | mono_time->base_time = 1000000000; | 144 | | #else | 145 | | // Never return time = 0 in case time() returns 0 (e.g. on microcontrollers | 146 | | // without battery-powered RTC or ones where NTP didn't initialise it yet). | 147 | 4.48k | mono_time->base_time = max_u64(1, (uint64_t)time(nullptr)) * UINT64_C(1000) - current_time_monotonic(mono_time); | 148 | 4.48k | #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ | 149 | | | 150 | 4.48k | mono_time_update(mono_time); | 151 | | | 152 | 4.48k | return mono_time; | 153 | 4.48k | } |
|
154 | | |
155 | | void mono_time_free(const Memory *mem, Mono_Time *mono_time) |
156 | 3.44k | { |
157 | 3.44k | if (mono_time == nullptr) { |
158 | 0 | return; |
159 | 0 | } |
160 | 3.44k | #ifndef ESP_PLATFORM |
161 | 3.44k | pthread_rwlock_destroy(mono_time->time_update_lock); |
162 | 3.44k | mem_delete(mem, mono_time->time_update_lock); |
163 | 3.44k | #endif /* ESP_PLATFORM */ |
164 | 3.44k | mem_delete(mem, mono_time); |
165 | 3.44k | } |
166 | | |
167 | | void mono_time_update(Mono_Time *mono_time) |
168 | 7.39M | { |
169 | 7.39M | const uint64_t cur_time = |
170 | 7.39M | mono_time->base_time + mono_time->current_time_callback(mono_time->user_data); |
171 | | |
172 | 7.39M | #ifndef ESP_PLATFORM |
173 | 7.39M | pthread_rwlock_wrlock(mono_time->time_update_lock); |
174 | 7.39M | #endif /* ESP_PLATFORM */ |
175 | 7.39M | mono_time->cur_time = cur_time; |
176 | 7.39M | #ifndef ESP_PLATFORM |
177 | 7.39M | pthread_rwlock_unlock(mono_time->time_update_lock); |
178 | 7.39M | #endif /* ESP_PLATFORM */ |
179 | 7.39M | } |
180 | | |
181 | | uint64_t mono_time_get_ms(const Mono_Time *mono_time) |
182 | 86.1M | { |
183 | | #if !defined(ESP_PLATFORM) && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) |
184 | | // Fuzzing is only single thread for now, no locking needed */ |
185 | | pthread_rwlock_rdlock(mono_time->time_update_lock); |
186 | | #endif /* !ESP_PLATFORM */ |
187 | 86.1M | const uint64_t cur_time = mono_time->cur_time; |
188 | | #if !defined(ESP_PLATFORM) && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) |
189 | | pthread_rwlock_unlock(mono_time->time_update_lock); |
190 | | #endif /* !ESP_PLATFORM */ |
191 | 86.1M | return cur_time; |
192 | 86.1M | } |
193 | | |
194 | | uint64_t mono_time_get(const Mono_Time *mono_time) |
195 | 86.1M | { |
196 | 86.1M | return mono_time_get_ms(mono_time) / UINT64_C(1000); |
197 | 86.1M | } |
198 | | |
199 | | bool mono_time_is_timeout(const Mono_Time *mono_time, uint64_t timestamp, uint64_t timeout) |
200 | 73.8M | { |
201 | 73.8M | return timestamp + timeout <= mono_time_get(mono_time); |
202 | 73.8M | } |
203 | | |
204 | | void mono_time_set_current_time_callback(Mono_Time *mono_time, |
205 | | mono_time_current_time_cb *current_time_callback, void *user_data) |
206 | 7.43k | { |
207 | 7.43k | if (current_time_callback == nullptr) { |
208 | 3.78k | mono_time->current_time_callback = current_time_monotonic_default; |
209 | 3.78k | mono_time->user_data = mono_time; |
210 | 3.78k | } else { |
211 | 3.65k | mono_time->current_time_callback = current_time_callback; |
212 | 3.65k | mono_time->user_data = user_data; |
213 | 3.65k | } |
214 | 7.43k | } |
215 | | |
216 | | /** @brief Return current monotonic time in milliseconds (ms). |
217 | | * |
218 | | * The starting point is unspecified and in particular is likely not comparable |
219 | | * to the return value of `mono_time_get_ms()`. |
220 | | */ |
221 | | uint64_t current_time_monotonic(Mono_Time *mono_time) |
222 | 590k | { |
223 | 590k | return mono_time->current_time_callback(mono_time->user_data); |
224 | 590k | } |