diff options
Diffstat (limited to 'toxcore/mono_time.c')
-rw-r--r-- | toxcore/mono_time.c | 57 |
1 files changed, 46 insertions, 11 deletions
diff --git a/toxcore/mono_time.c b/toxcore/mono_time.c index a8dae350..6325ed3d 100644 --- a/toxcore/mono_time.c +++ b/toxcore/mono_time.c | |||
@@ -30,10 +30,13 @@ struct Mono_Time { | |||
30 | uint64_t time; | 30 | uint64_t time; |
31 | uint64_t base_time; | 31 | uint64_t base_time; |
32 | #ifdef OS_WIN32 | 32 | #ifdef OS_WIN32 |
33 | /* protect `last_clock_update` and `last_clock_mono` from concurrent access */ | ||
34 | pthread_mutex_t last_clock_lock; | ||
33 | uint32_t last_clock_mono; | 35 | uint32_t last_clock_mono; |
36 | bool last_clock_update; | ||
34 | #endif | 37 | #endif |
35 | 38 | ||
36 | /* protect `time` and `last_clock_mono` from concurrent access */ | 39 | /* protect `time` from concurrent access */ |
37 | pthread_rwlock_t *time_update_lock; | 40 | pthread_rwlock_t *time_update_lock; |
38 | 41 | ||
39 | mono_time_current_time_cb *current_time_callback; | 42 | mono_time_current_time_cb *current_time_callback; |
@@ -44,16 +47,15 @@ static uint64_t current_time_monotonic_default(Mono_Time *mono_time, void *user_ | |||
44 | { | 47 | { |
45 | uint64_t time = 0; | 48 | uint64_t time = 0; |
46 | #ifdef OS_WIN32 | 49 | #ifdef OS_WIN32 |
47 | /* let only one thread at a time check for overflow */ | 50 | /* Must hold mono_time->last_clock_lock here */ |
48 | pthread_rwlock_wrlock(mono_time->time_update_lock); | ||
49 | 51 | ||
50 | /* GetTickCount provides only a 32 bit counter, but we can't use | 52 | /* GetTickCount provides only a 32 bit counter, but we can't use |
51 | * GetTickCount64 for backwards compatibility, so we handle wraparound | 53 | * GetTickCount64 for backwards compatibility, so we handle wraparound |
52 | * ourselfes. | 54 | * ourselves. |
53 | */ | 55 | */ |
54 | uint32_t ticks = GetTickCount(); | 56 | uint32_t ticks = GetTickCount(); |
55 | 57 | ||
56 | /* the higher 32 bits count the amount of overflows */ | 58 | /* the higher 32 bits count the number of wrap arounds */ |
57 | uint64_t old_ovf = mono_time->time & ~((uint64_t)UINT32_MAX); | 59 | uint64_t old_ovf = mono_time->time & ~((uint64_t)UINT32_MAX); |
58 | 60 | ||
59 | /* Check if time has decreased because of 32 bit wrap from GetTickCount() */ | 61 | /* Check if time has decreased because of 32 bit wrap from GetTickCount() */ |
@@ -62,12 +64,13 @@ static uint64_t current_time_monotonic_default(Mono_Time *mono_time, void *user_ | |||
62 | old_ovf += UINT32_MAX + UINT64_C(1); | 64 | old_ovf += UINT32_MAX + UINT64_C(1); |
63 | } | 65 | } |
64 | 66 | ||
65 | mono_time->last_clock_mono = ticks; | 67 | if (mono_time->last_clock_update) { |
68 | mono_time->last_clock_mono = ticks; | ||
69 | mono_time->last_clock_update = false; | ||
70 | } | ||
66 | 71 | ||
67 | /* splice the low and high bits back together */ | 72 | /* splice the low and high bits back together */ |
68 | time = old_ovf + ticks; | 73 | time = old_ovf + ticks; |
69 | |||
70 | pthread_rwlock_unlock(mono_time->time_update_lock); | ||
71 | #else | 74 | #else |
72 | struct timespec clock_mono; | 75 | struct timespec clock_mono; |
73 | #if defined(__APPLE__) | 76 | #if defined(__APPLE__) |
@@ -113,13 +116,21 @@ Mono_Time *mono_time_new(void) | |||
113 | mono_time->user_data = nullptr; | 116 | mono_time->user_data = nullptr; |
114 | 117 | ||
115 | #ifdef OS_WIN32 | 118 | #ifdef OS_WIN32 |
119 | |||
116 | mono_time->last_clock_mono = 0; | 120 | mono_time->last_clock_mono = 0; |
121 | mono_time->last_clock_update = false; | ||
122 | |||
123 | if (pthread_mutex_init(&mono_time->last_clock_lock, nullptr) < 0) { | ||
124 | free(mono_time->time_update_lock); | ||
125 | free(mono_time); | ||
126 | return nullptr; | ||
127 | } | ||
128 | |||
117 | #endif | 129 | #endif |
118 | 130 | ||
119 | mono_time->time = 0; | 131 | mono_time->time = 0; |
120 | mono_time->base_time = (uint64_t)time(nullptr) - (current_time_monotonic(mono_time) / 1000ULL); | 132 | mono_time->base_time = (uint64_t)time(nullptr) - (current_time_monotonic(mono_time) / 1000ULL); |
121 | 133 | ||
122 | |||
123 | mono_time_update(mono_time); | 134 | mono_time_update(mono_time); |
124 | 135 | ||
125 | return mono_time; | 136 | return mono_time; |
@@ -127,6 +138,9 @@ Mono_Time *mono_time_new(void) | |||
127 | 138 | ||
128 | void mono_time_free(Mono_Time *mono_time) | 139 | void mono_time_free(Mono_Time *mono_time) |
129 | { | 140 | { |
141 | #ifdef OS_WIN32 | ||
142 | pthread_mutex_destroy(&mono_time->last_clock_lock, nullptr); | ||
143 | #endif | ||
130 | pthread_rwlock_destroy(mono_time->time_update_lock); | 144 | pthread_rwlock_destroy(mono_time->time_update_lock); |
131 | free(mono_time->time_update_lock); | 145 | free(mono_time->time_update_lock); |
132 | free(mono_time); | 146 | free(mono_time); |
@@ -134,7 +148,18 @@ void mono_time_free(Mono_Time *mono_time) | |||
134 | 148 | ||
135 | void mono_time_update(Mono_Time *mono_time) | 149 | void mono_time_update(Mono_Time *mono_time) |
136 | { | 150 | { |
137 | uint64_t time = (current_time_monotonic(mono_time) / 1000ULL) + mono_time->base_time; | 151 | uint64_t time = 0; |
152 | #ifdef OS_WIN32 | ||
153 | /* we actually want to update the overflow state of mono_time here */ | ||
154 | pthread_mutex_lock(&mono_time->last_clock_lock); | ||
155 | mono_time->last_clock_update = true; | ||
156 | #endif | ||
157 | time = mono_time->current_time_callback(mono_time, mono_time->user_data) / 1000ULL; | ||
158 | time += mono_time->base_time; | ||
159 | #ifdef OS_WIN32 | ||
160 | pthread_mutex_unlock(&mono_time->last_clock_lock); | ||
161 | #endif | ||
162 | |||
138 | pthread_rwlock_wrlock(mono_time->time_update_lock); | 163 | pthread_rwlock_wrlock(mono_time->time_update_lock); |
139 | mono_time->time = time; | 164 | mono_time->time = time; |
140 | pthread_rwlock_unlock(mono_time->time_update_lock); | 165 | pthread_rwlock_unlock(mono_time->time_update_lock); |
@@ -169,5 +194,15 @@ void mono_time_set_current_time_callback(Mono_Time *mono_time, | |||
169 | /* return current monotonic time in milliseconds (ms). */ | 194 | /* return current monotonic time in milliseconds (ms). */ |
170 | uint64_t current_time_monotonic(Mono_Time *mono_time) | 195 | uint64_t current_time_monotonic(Mono_Time *mono_time) |
171 | { | 196 | { |
172 | return mono_time->current_time_callback(mono_time, mono_time->user_data); | 197 | /* For WIN32 we don't want to change overflow state of mono_time here */ |
198 | #ifdef OS_WIN32 | ||
199 | /* We don't want to update the overflow state of mono_time here, | ||
200 | * but must protect against other threads */ | ||
201 | pthread_mutex_lock(&mono_time->last_clock_lock); | ||
202 | #endif | ||
203 | uint64_t time = mono_time->current_time_callback(mono_time, mono_time->user_data); | ||
204 | #ifdef OS_WIN32 | ||
205 | pthread_mutex_unlock(&mono_time->last_clock_lock); | ||
206 | #endif | ||
207 | return time; | ||
173 | } | 208 | } |