diff --git a/toxcore/mono_time.c b/toxcore/mono_time.c index 5130ee6d..7fdf2d7e 100644 --- a/toxcore/mono_time.c +++ b/toxcore/mono_time.c @@ -28,8 +28,13 @@ struct Mono_Time { uint64_t time; uint64_t base_time; + + mono_time_current_time_cb *current_time_callback; + void *user_data; }; +static mono_time_current_time_cb current_time_monotonic_default; + Mono_Time *mono_time_new(void) { Mono_Time *mono_time = (Mono_Time *)malloc(sizeof(Mono_Time)); @@ -38,6 +43,9 @@ Mono_Time *mono_time_new(void) return nullptr; } + mono_time->current_time_callback = current_time_monotonic_default; + mono_time->user_data = nullptr; + mono_time->time = 0; mono_time->base_time = (uint64_t)time(nullptr) - (current_time_monotonic(mono_time) / 1000ULL); @@ -66,6 +74,24 @@ bool mono_time_is_timeout(const Mono_Time *mono_time, uint64_t timestamp, uint64 return timestamp + timeout <= mono_time_get(mono_time); } +void mono_time_set_current_time_callback(Mono_Time *mono_time, + mono_time_current_time_cb *current_time_callback, void *user_data) +{ + if (current_time_callback == nullptr) { + mono_time->current_time_callback = current_time_monotonic_default; + mono_time->user_data = nullptr; + } else { + mono_time->current_time_callback = current_time_callback; + mono_time->user_data = user_data; + } +} + +/* return current monotonic time in milliseconds (ms). */ +uint64_t current_time_monotonic(const Mono_Time *mono_time) +{ + return mono_time->current_time_callback(mono_time->user_data); +} + //!TOKSTYLE- // No global mutable state in Tokstyle. #ifdef OS_WIN32 @@ -74,8 +100,7 @@ static uint64_t add_clock_mono; #endif //!TOKSTYLE+ -/* return current monotonic time in milliseconds (ms). */ -uint64_t current_time_monotonic(const Mono_Time *mono_time) +static uint64_t current_time_monotonic_default(void *user_data) { uint64_t time; #ifdef OS_WIN32 diff --git a/toxcore/mono_time.h b/toxcore/mono_time.h index ed69e3b0..b735f2c3 100644 --- a/toxcore/mono_time.h +++ b/toxcore/mono_time.h @@ -52,6 +52,16 @@ bool mono_time_is_timeout(const Mono_Time *mono_time, uint64_t timestamp, uint64 /* return current monotonic time in milliseconds (ms). */ uint64_t current_time_monotonic(const Mono_Time *mono_time); +typedef uint64_t mono_time_current_time_cb(void *user_data); + +/* Override implementation of current_time_monotonic() (for tests). + * + * The caller is obligated to ensure that current_time_monotonic() continues + * to increase monotonically. + */ +void mono_time_set_current_time_callback(Mono_Time *mono_time, + mono_time_current_time_cb *current_time_callback, void *user_data); + #ifdef __cplusplus } #endif diff --git a/toxcore/mono_time_test.cc b/toxcore/mono_time_test.cc index 4ed59406..6e81ac7e 100644 --- a/toxcore/mono_time_test.cc +++ b/toxcore/mono_time_test.cc @@ -35,4 +35,28 @@ TEST(MonoTime, IsTimeout) { mono_time_free(mono_time); } +static uint64_t test_current_time_callback(void *user_data) { return *(uint64_t *)user_data; } + +TEST(MonoTime, CustomTime) { + Mono_Time *mono_time = mono_time_new(); + + uint64_t test_time = current_time_monotonic(mono_time) + 42137; + + mono_time_set_current_time_callback(mono_time, test_current_time_callback, &test_time); + mono_time_update(mono_time); + + EXPECT_EQ(current_time_monotonic(mono_time), test_time); + + uint64_t const start = mono_time_get(mono_time); + + test_time += 7000; + + mono_time_update(mono_time); + EXPECT_EQ(mono_time_get(mono_time) - start, 7); + + EXPECT_EQ(current_time_monotonic(mono_time), test_time); + + mono_time_free(mono_time); +} + } // namespace