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.c57
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
128void mono_time_free(Mono_Time *mono_time) 139void 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
135void mono_time_update(Mono_Time *mono_time) 149void 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). */
170uint64_t current_time_monotonic(Mono_Time *mono_time) 195uint64_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}