/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-2025 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 "attributes.h" |
36 | | #include "ccompat.h" |
37 | | #include "mem.h" |
38 | | #include "util.h" |
39 | | |
40 | | /** don't call into system billions of times for no reason */ |
41 | | struct Mono_Time { |
42 | | uint64_t cur_time; |
43 | | uint64_t base_time; |
44 | | |
45 | | #ifndef ESP_PLATFORM |
46 | | /* protect `time` from concurrent access */ |
47 | | pthread_rwlock_t *time_update_lock; |
48 | | #endif /* ESP_PLATFORM */ |
49 | | |
50 | | mono_time_current_time_cb *current_time_callback; |
51 | | void *user_data; |
52 | | }; |
53 | | |
54 | | static uint64_t timespec_to_u64(struct timespec clock_mono) |
55 | 6.06M | { |
56 | 6.06M | return UINT64_C(1000) * clock_mono.tv_sec + (clock_mono.tv_nsec / UINT64_C(1000000)); |
57 | 6.06M | } |
58 | | |
59 | | #ifdef OS_WIN32 |
60 | | static uint64_t current_time_monotonic_default(void *_Nonnull 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 | | static uint64_t current_time_monotonic_default(void *_Nonnull user_data) |
82 | | { |
83 | | struct timespec clock_mono; |
84 | | clock_serv_t muhclock; |
85 | | mach_timespec_t machtime; |
86 | | |
87 | | host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &muhclock); |
88 | | clock_get_time(muhclock, &machtime); |
89 | | mach_port_deallocate(mach_task_self(), muhclock); |
90 | | |
91 | | clock_mono.tv_sec = machtime.tv_sec; |
92 | | clock_mono.tv_nsec = machtime.tv_nsec; |
93 | | return timespec_to_u64(clock_mono); |
94 | | } |
95 | | #else // !__APPLE__ |
96 | | static uint64_t current_time_monotonic_default(void *_Nonnull user_data) |
97 | 0 | { |
98 | 0 | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
99 | | // This assert should always fail. If it does, the fuzzing harness didn't |
100 | | // override the mono time callback. |
101 | 0 | assert(user_data == nullptr); |
102 | 0 | #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ |
103 | 0 | struct timespec clock_mono; |
104 | 0 | clock_gettime(CLOCK_MONOTONIC, &clock_mono); |
105 | 0 | return timespec_to_u64(clock_mono); |
106 | 0 | } |
107 | | #endif /* !__APPLE__ */ |
108 | | #endif /* !OS_WIN32 */ |
109 | | |
110 | | Mono_Time *mono_time_new(const Memory *mem, mono_time_current_time_cb *current_time_callback, void *user_data) |
111 | 7.08k | { |
112 | 7.08k | Mono_Time *mono_time = (Mono_Time *)mem_alloc(mem, sizeof(Mono_Time)); |
113 | | |
114 | 7.08k | if (mono_time == nullptr) { |
115 | 22 | return nullptr; |
116 | 22 | } |
117 | | |
118 | 7.06k | #ifndef ESP_PLATFORM |
119 | 7.06k | pthread_rwlock_t *rwlock = (pthread_rwlock_t *)mem_alloc(mem, sizeof(pthread_rwlock_t)); |
120 | | |
121 | 7.06k | if (rwlock == nullptr) { |
122 | 22 | mem_delete(mem, mono_time); |
123 | 22 | return nullptr; |
124 | 22 | } |
125 | | |
126 | 7.03k | if (pthread_rwlock_init(rwlock, nullptr) != 0) { |
127 | 0 | mem_delete(mem, rwlock); |
128 | 0 | mem_delete(mem, mono_time); |
129 | 0 | return nullptr; |
130 | 0 | } |
131 | | |
132 | 7.03k | mono_time->time_update_lock = rwlock; |
133 | 7.03k | #endif /* ESP_PLATFORM */ |
134 | | |
135 | 7.03k | mono_time_set_current_time_callback(mono_time, current_time_callback, user_data); |
136 | | |
137 | 7.03k | mono_time->cur_time = 0; |
138 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
139 | | // Maximum reproducibility. Never return time = 0. |
140 | | mono_time->base_time = 1000000000; |
141 | | #else |
142 | | // Never return time = 0 in case time() returns 0 (e.g. on microcontrollers |
143 | | // without battery-powered RTC or ones where NTP didn't initialise it yet). |
144 | 3.51k | mono_time->base_time = max_u64(1, (uint64_t)time(nullptr)) * UINT64_C(1000) - current_time_monotonic(mono_time); |
145 | | #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ |
146 | | |
147 | 7.03k | mono_time_update(mono_time); |
148 | | |
149 | 7.03k | return mono_time; |
150 | 7.03k | } Line | Count | Source | 111 | 3.54k | { | 112 | 3.54k | Mono_Time *mono_time = (Mono_Time *)mem_alloc(mem, sizeof(Mono_Time)); | 113 | | | 114 | 3.54k | if (mono_time == nullptr) { | 115 | 11 | return nullptr; | 116 | 11 | } | 117 | | | 118 | 3.53k | #ifndef ESP_PLATFORM | 119 | 3.53k | pthread_rwlock_t *rwlock = (pthread_rwlock_t *)mem_alloc(mem, sizeof(pthread_rwlock_t)); | 120 | | | 121 | 3.53k | if (rwlock == nullptr) { | 122 | 11 | mem_delete(mem, mono_time); | 123 | 11 | return nullptr; | 124 | 11 | } | 125 | | | 126 | 3.51k | if (pthread_rwlock_init(rwlock, nullptr) != 0) { | 127 | 0 | mem_delete(mem, rwlock); | 128 | 0 | mem_delete(mem, mono_time); | 129 | 0 | return nullptr; | 130 | 0 | } | 131 | | | 132 | 3.51k | mono_time->time_update_lock = rwlock; | 133 | 3.51k | #endif /* ESP_PLATFORM */ | 134 | | | 135 | 3.51k | mono_time_set_current_time_callback(mono_time, current_time_callback, user_data); | 136 | | | 137 | 3.51k | mono_time->cur_time = 0; | 138 | 3.51k | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION | 139 | | // Maximum reproducibility. Never return time = 0. | 140 | 3.51k | mono_time->base_time = 1000000000; | 141 | | #else | 142 | | // Never return time = 0 in case time() returns 0 (e.g. on microcontrollers | 143 | | // without battery-powered RTC or ones where NTP didn't initialise it yet). | 144 | | mono_time->base_time = max_u64(1, (uint64_t)time(nullptr)) * UINT64_C(1000) - current_time_monotonic(mono_time); | 145 | | #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ | 146 | | | 147 | 3.51k | mono_time_update(mono_time); | 148 | | | 149 | 3.51k | return mono_time; | 150 | 3.51k | } |
Line | Count | Source | 111 | 3.54k | { | 112 | 3.54k | Mono_Time *mono_time = (Mono_Time *)mem_alloc(mem, sizeof(Mono_Time)); | 113 | | | 114 | 3.54k | if (mono_time == nullptr) { | 115 | 11 | return nullptr; | 116 | 11 | } | 117 | | | 118 | 3.53k | #ifndef ESP_PLATFORM | 119 | 3.53k | pthread_rwlock_t *rwlock = (pthread_rwlock_t *)mem_alloc(mem, sizeof(pthread_rwlock_t)); | 120 | | | 121 | 3.53k | if (rwlock == nullptr) { | 122 | 11 | mem_delete(mem, mono_time); | 123 | 11 | return nullptr; | 124 | 11 | } | 125 | | | 126 | 3.51k | if (pthread_rwlock_init(rwlock, nullptr) != 0) { | 127 | 0 | mem_delete(mem, rwlock); | 128 | 0 | mem_delete(mem, mono_time); | 129 | 0 | return nullptr; | 130 | 0 | } | 131 | | | 132 | 3.51k | mono_time->time_update_lock = rwlock; | 133 | 3.51k | #endif /* ESP_PLATFORM */ | 134 | | | 135 | 3.51k | mono_time_set_current_time_callback(mono_time, current_time_callback, user_data); | 136 | | | 137 | 3.51k | mono_time->cur_time = 0; | 138 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION | 139 | | // Maximum reproducibility. Never return time = 0. | 140 | | mono_time->base_time = 1000000000; | 141 | | #else | 142 | | // Never return time = 0 in case time() returns 0 (e.g. on microcontrollers | 143 | | // without battery-powered RTC or ones where NTP didn't initialise it yet). | 144 | 3.51k | mono_time->base_time = max_u64(1, (uint64_t)time(nullptr)) * UINT64_C(1000) - current_time_monotonic(mono_time); | 145 | 3.51k | #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ | 146 | | | 147 | 3.51k | mono_time_update(mono_time); | 148 | | | 149 | 3.51k | return mono_time; | 150 | 3.51k | } |
|
151 | | |
152 | | void mono_time_free(const Memory *mem, Mono_Time *mono_time) |
153 | 2.64k | { |
154 | 2.64k | if (mono_time == nullptr) { |
155 | 0 | return; |
156 | 0 | } |
157 | 2.64k | #ifndef ESP_PLATFORM |
158 | 2.64k | pthread_rwlock_destroy(mono_time->time_update_lock); |
159 | 2.64k | mem_delete(mem, mono_time->time_update_lock); |
160 | 2.64k | #endif /* ESP_PLATFORM */ |
161 | 2.64k | mem_delete(mem, mono_time); |
162 | 2.64k | } |
163 | | |
164 | | void mono_time_update(Mono_Time *mono_time) |
165 | 5.99M | { |
166 | 5.99M | const uint64_t cur_time = |
167 | 5.99M | mono_time->base_time + mono_time->current_time_callback(mono_time->user_data); |
168 | | |
169 | 5.99M | #ifndef ESP_PLATFORM |
170 | 5.99M | pthread_rwlock_wrlock(mono_time->time_update_lock); |
171 | 5.99M | #endif /* ESP_PLATFORM */ |
172 | 5.99M | mono_time->cur_time = cur_time; |
173 | 5.99M | #ifndef ESP_PLATFORM |
174 | 5.99M | pthread_rwlock_unlock(mono_time->time_update_lock); |
175 | 5.99M | #endif /* ESP_PLATFORM */ |
176 | 5.99M | } |
177 | | |
178 | | uint64_t mono_time_get_ms(const Mono_Time *mono_time) |
179 | 75.0M | { |
180 | | #if !defined(ESP_PLATFORM) && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) |
181 | | // Fuzzing is only single thread for now, no locking needed */ |
182 | | pthread_rwlock_rdlock(mono_time->time_update_lock); |
183 | | #endif /* !ESP_PLATFORM */ |
184 | 75.0M | const uint64_t cur_time = mono_time->cur_time; |
185 | | #if !defined(ESP_PLATFORM) && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) |
186 | | pthread_rwlock_unlock(mono_time->time_update_lock); |
187 | | #endif /* !ESP_PLATFORM */ |
188 | 75.0M | return cur_time; |
189 | 75.0M | } |
190 | | |
191 | | uint64_t mono_time_get(const Mono_Time *mono_time) |
192 | 75.0M | { |
193 | 75.0M | return mono_time_get_ms(mono_time) / UINT64_C(1000); |
194 | 75.0M | } |
195 | | |
196 | | bool mono_time_is_timeout(const Mono_Time *mono_time, uint64_t timestamp, uint64_t timeout) |
197 | 64.7M | { |
198 | 64.7M | return timestamp + timeout <= mono_time_get(mono_time); |
199 | 64.7M | } |
200 | | |
201 | | void mono_time_set_current_time_callback(Mono_Time *mono_time, |
202 | | mono_time_current_time_cb *current_time_callback, void *user_data) |
203 | 5.72k | { |
204 | 5.72k | if (current_time_callback == nullptr) { |
205 | 2.95k | mono_time->current_time_callback = current_time_monotonic_default; |
206 | 2.95k | mono_time->user_data = mono_time; |
207 | 2.95k | } else { |
208 | 2.76k | mono_time->current_time_callback = current_time_callback; |
209 | 2.76k | mono_time->user_data = user_data; |
210 | 2.76k | } |
211 | 5.72k | } |
212 | | |
213 | | /** @brief Return current monotonic time in milliseconds (ms). |
214 | | * |
215 | | * The starting point is unspecified and in particular is likely not comparable |
216 | | * to the return value of `mono_time_get_ms()`. |
217 | | */ |
218 | | uint64_t current_time_monotonic(const Mono_Time *mono_time) |
219 | 515k | { |
220 | 515k | return mono_time->current_time_callback(mono_time->user_data); |
221 | 515k | } |