all repos — tint2 @ 0911dcaed1cbe60c8706f0692159cae3cf670726

fork of the tint2 desktop panel for my custom setup - only minimized windows across all desktops for the taskbar

Timer: new implementation (needs merge)
o9000 mrovi9000@gmail.com
commit

0911dcaed1cbe60c8706f0692159cae3cf670726

parent

c41d75e54e946078eb840043180d9d81d8f7c9c6

2 files changed, 424 insertions(+), 576 deletions(-)

jump to
M src/util/timer.csrc/util/timer.c

@@ -21,71 +21,134 @@ #include <stdlib.h>

#include <stdio.h> #include <string.h> +#include "colors.h" #include "timer.h" #include "test.h" -GSList *timeout_list; -struct timeval next_timeout; -GHashTable *multi_timeouts; +// All active timers +static GList *timers = NULL; -// functions and structs for multi timeouts -typedef struct { - int current_count; - int count_to_expiration; -} multi_timeout; +void default_timers() +{ + timers = NULL; +} -typedef struct { - GSList *timeout_list; - timeout *parent_timeout; -} multi_timeout_handler; +void cleanup_timers() +{ + g_list_free(timers); + timers = NULL; +} -struct _timeout { - int interval_msec; - struct timespec timeout_expires; - void (*_callback)(void *); - void *arg; - multi_timeout *multi_timeout; - timeout **self; - gboolean expired; - // timer has been restarted from its own callback function - gboolean reactivated; -}; +void init_timer(Timer *timer, const char *name) +{ + if (g_list_find(timers, timer)) { + fprintf(stderr, RED "tint2: Attempt to init the same timer twice: %s" RESET "\n", timer->name_); + return; + } + bzero(timer, sizeof(*timer)); + strncpy(timer->name_, name, sizeof(timer->name_)); + timers = g_list_append(timers, timer); +} -void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout *t); -gint compare_timeouts(gconstpointer t1, gconstpointer t2); -int timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y); +void destroy_timer(Timer *timer) +{ + if (!g_list_find(timers, timer)) { + fprintf(stderr, RED "tint2: Attempt to destroy unexisting timer: %s" RESET "\n", timer->name_); + return; + } + timers = g_list_remove(timers, timer); +} -int align_with_existing_timeouts(timeout *t); -void create_multi_timeout(timeout *t1, timeout *t2); -void append_multi_timeout(timeout *t1, timeout *t2); -int calc_multi_timeout_interval(multi_timeout_handler *mth); -void update_multi_timeout_values(multi_timeout_handler *mth); -void callback_multi_timeout(void *mth); -void remove_from_multi_timeout(timeout *t); -void stop_multi_timeout(timeout *t); +void change_timer(Timer *timer, bool enabled, int delay_ms, int period_ms, TimerCallback *callback, void *arg) +{ + if (!g_list_find(timers, timer)) { + fprintf(stderr, RED "tint2: Attempt to change unexisting timer: %s" RESET "\n", timer->name_); + return; + } + timer->enabled_ = enabled; + timer->expiration_time_ = get_time() + delay_ms / 1000.; + timer->period_ms_ = period_ms; + timer->callback_ = callback; + timer->arg_ = arg; +} -void default_timeout() +void stop_timer(Timer *timer) { - timeout_list = NULL; - multi_timeouts = NULL; + change_timer(timer, false, 0, 0, NULL, NULL); } -void cleanup_timeout() +struct timeval *get_duration_to_next_timer_expiration() { - while (timeout_list) { - timeout *t = timeout_list->data; - if (t->multi_timeout) - stop_multi_timeout(t); - if (t->self) - *t->self = NULL; - free(t); - timeout_list = g_slist_remove(timeout_list, t); + static struct timeval result = {0, 0}; + double min_expiration_time = -1; + for (GList *it = timers; it; it = it->next) { + Timer *timer = (Timer *)it->data; + if (!timer->enabled_) + continue; + if (min_expiration_time < 0 || timer->expiration_time_ < min_expiration_time) + min_expiration_time = timer->expiration_time_; } - if (multi_timeouts) { - g_hash_table_destroy(multi_timeouts); - multi_timeouts = NULL; + if (min_expiration_time < 0) + return NULL; + double duration = min_expiration_time - get_time(); + result.tv_sec = (long long) duration; + result.tv_usec = (long long)(1.0e6 * (duration - result.tv_sec)); + return &result; +} + +void handle_expired_timers() +{ + double now = get_time(); + bool expired_timers = false; + for (GList *it = timers; it; it = it->next) { + Timer *timer = (Timer *)it->data; + if (timer->enabled_ && timer->callback_ && timer->expiration_time_ <= now) + expired_timers = true; } + if (!expired_timers) + return; + + // We make a copy of the timer list, as the callbacks may create new timers, + // which we don't want to trigger in this event loop iteration, + // to prevent infinite loops. + GList *current_timers = g_list_copy(timers); + + // Mark all timers as not handled. + // This is to ensure not triggering a timer more than once per event loop iteration, + // in case it is modified from a callback. + for (GList *it = current_timers; it; it = it->next) { + Timer *timer = (Timer *)it->data; + timer->handled_ = false; + } + + bool triggered = false; + do { + for (GList *it = current_timers; it; it = it->next) { + Timer *timer = (Timer *)it->data; + // Check that it is still registered. + if (!g_list_find(timers, timer)) + continue; + if (!timer->enabled_ || timer->handled_ || !timer->callback_ || timer->expiration_time_ > now) + continue; + timer->handled_ = true; + if (timer->period_ms_ == 0) { + // One shot timer, turn it off. + timer->enabled_ = false; + } else { + // Periodic timer, reschedule. + timer->expiration_time_ = now + timer->period_ms_ / 1000.; + } + timer->callback_(timer->arg_); + // The callback may have modified timers, so start from scratch + triggered = true; + break; + } + } while (triggered); + + g_list_free(current_timers); } + +// Time helper functions static struct timespec mock_time = { 0, 0 }; void set_mock_time(struct timespec *tp)

@@ -115,132 +178,6 @@ return clock_gettime(CLOCK_MONOTONIC, tp);

#endif } -// Implementation notes for timeouts -// -// The timeouts are kept in a GSList sorted by their expiration time. -// That means that update_next_timeout() only have to consider the first timeout in the list, -// and callback_timeout_expired() only have to consider the timeouts as long as the expiration time -// is in the past to the current time. -// As time measurement we use clock_gettime(CLOCK_MONOTONIC) because this refers to a timer, which -// reference point lies somewhere in the past and cannot be changed, but just queried. -// If a single shot timer is installed it will be automatically deleted. I.e. the returned value -// of add_timeout will not be valid anymore. You do not need to call stop_timeout for these timeouts, -// however it's save to call it. - -timeout *add_timeout(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout **self) -{ - if (self && *self && !(*self)->expired) - return *self; - timeout *t = calloc(1, sizeof(timeout)); - t->self = self; - add_timeout_intern(value_msec, interval_msec, _callback, arg, t); - return t; -} - -void change_timeout(timeout **t, int value_msec, int interval_msec, void (*_callback)(), void *arg) -{ - if (!((timeout_list && g_slist_find(timeout_list, *t)) || - (multi_timeouts && g_hash_table_lookup(multi_timeouts, *t)))) - *t = add_timeout(value_msec, interval_msec, _callback, arg, t); - else { - if ((*t)->multi_timeout) - remove_from_multi_timeout(*t); - else - timeout_list = g_slist_remove(timeout_list, *t); - add_timeout_intern(value_msec, interval_msec, _callback, arg, *t); - } -} - -struct timeval *get_next_timeout() -{ - if (timeout_list) { - timeout *t = timeout_list->data; - struct timespec cur_time; - struct timespec next_timeout2 = {.tv_sec = next_timeout.tv_sec, .tv_nsec = next_timeout.tv_usec * 1000}; - gettime(&cur_time); - if (timespec_subtract(&next_timeout2, &t->timeout_expires, &cur_time)) { - next_timeout.tv_sec = 0; - next_timeout.tv_usec = 0; - } else { - next_timeout.tv_sec = next_timeout2.tv_sec; - next_timeout.tv_usec = next_timeout2.tv_nsec / 1000; - } - } else - next_timeout.tv_sec = -1; - return (next_timeout.tv_sec >= 0 && next_timeout.tv_usec >= 0) ? &next_timeout : NULL; -} - -void handle_expired_timers() -{ - struct timespec cur_time; - timeout *t; - while (timeout_list) { - gettime(&cur_time); - t = timeout_list->data; - if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) { - // it's time for the callback function - t->expired = t->interval_msec == 0; - t->reactivated = FALSE; - t->_callback(t->arg); - // If _callback() calls stop_timeout(t) the timer 't' was freed and is not in the timeout_list - if (g_slist_find(timeout_list, t)) { - // Timer still exists - if (!t->reactivated) { - timeout_list = g_slist_remove(timeout_list, t); - if (t->interval_msec > 0) { - add_timeout_intern(t->interval_msec, t->interval_msec, t->_callback, t->arg, t); - } else { - // Destroy single-shot timer - if (t->self) - *t->self = NULL; - free(t); - } - } - } - } else { - return; - } - } -} - -void stop_timeout(timeout *t) -{ - if (!t) - return; - // if not in the list, it was deleted in callback_timeout_expired - if ((timeout_list && g_slist_find(timeout_list, t)) || (multi_timeouts && g_hash_table_lookup(multi_timeouts, t))) { - if (multi_timeouts && t->multi_timeout) - remove_from_multi_timeout(t); - if (timeout_list) - timeout_list = g_slist_remove(timeout_list, t); - if (t->self) - *t->self = NULL; - free(t); - } -} - -void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(), void *arg, timeout *t) -{ - t->interval_msec = interval_msec; - t->_callback = _callback; - t->arg = arg; - struct timespec cur_time; - gettime(&cur_time); - t->timeout_expires = add_msec_to_timespec(cur_time, value_msec); - - int can_align = 0; - if (interval_msec > 0 && !t->multi_timeout) - can_align = align_with_existing_timeouts(t); - if (!can_align) - timeout_list = g_slist_insert_sorted(timeout_list, t, compare_timeouts); - t->reactivated = TRUE; -} - -gint compare_timeouts(gconstpointer t1, gconstpointer t2) -{ - return compare_timespecs(&((const timeout *)t1)->timeout_expires, &((const timeout *)t2)->timeout_expires); -} - gint compare_timespecs(const struct timespec *t1, const struct timespec *t2) { if (t1->tv_sec < t2->tv_sec)

@@ -256,28 +193,6 @@ } else

return 1; } -int timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y) -{ - /* Perform the carry for the later subtraction by updating y. */ - if (x->tv_nsec < y->tv_nsec) { - int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1; - y->tv_nsec -= 1000000000 * nsec; - y->tv_sec += nsec; - } - if (x->tv_nsec - y->tv_nsec > 1000000000) { - int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000; - y->tv_nsec += 1000000000 * nsec; - y->tv_sec -= nsec; - } - - /* Compute the time remaining to wait. tv_nsec is certainly positive. */ - result->tv_sec = x->tv_sec - y->tv_sec; - result->tv_nsec = x->tv_nsec - y->tv_nsec; - - /* Return 1 if result is negative. */ - return x->tv_sec < y->tv_sec; -} - struct timespec add_msec_to_timespec(struct timespec ts, int msec) { ts.tv_sec += msec / 1000;

@@ -289,191 +204,7 @@ }

return ts; } -int align_with_existing_timeouts(timeout *t) -{ - GSList *it = timeout_list; - while (it) { - timeout *t2 = it->data; - if (t2->interval_msec > 0) { - if (t->interval_msec % t2->interval_msec == 0 || t2->interval_msec % t->interval_msec == 0) { - if (!multi_timeouts) - multi_timeouts = g_hash_table_new(0, 0); - if (!t->multi_timeout && !t2->multi_timeout) { - // both timeouts can be aligned, but there is no multi timeout for them - create_multi_timeout(t, t2); - } else { - // there is already a multi timeout, so we append the new timeout to the multi timeout - append_multi_timeout(t, t2); - } - return 1; - } - } - it = it->next; - } - return 0; -} - -int calc_multi_timeout_interval(multi_timeout_handler *mth) -{ - GSList *it = mth->timeout_list; - timeout *t = it->data; - int min_interval = t->interval_msec; - it = it->next; - while (it) { - t = it->data; - if (t->interval_msec < min_interval) - min_interval = t->interval_msec; - it = it->next; - } - return min_interval; -} - -void create_multi_timeout(timeout *t1, timeout *t2) -{ - multi_timeout *mt1 = calloc(1, sizeof(multi_timeout)); - multi_timeout *mt2 = calloc(1, sizeof(multi_timeout)); - multi_timeout_handler *mth = calloc(1, sizeof(multi_timeout_handler)); - timeout *real_timeout = calloc(1, sizeof(timeout)); - - mth->timeout_list = 0; - mth->timeout_list = g_slist_prepend(mth->timeout_list, t1); - mth->timeout_list = g_slist_prepend(mth->timeout_list, t2); - mth->parent_timeout = real_timeout; - - g_hash_table_insert(multi_timeouts, t1, mth); - g_hash_table_insert(multi_timeouts, t2, mth); - g_hash_table_insert(multi_timeouts, real_timeout, mth); - - t1->multi_timeout = mt1; - t2->multi_timeout = mt2; - // set real_timeout->multi_timeout to something, such that we see in add_timeout_intern that - // it is already a multi_timeout (we never use it, except of checking for 0 ptr) - real_timeout->multi_timeout = (void *)real_timeout; - - timeout_list = g_slist_remove(timeout_list, t1); - timeout_list = g_slist_remove(timeout_list, t2); - - update_multi_timeout_values(mth); -} - -void append_multi_timeout(timeout *t1, timeout *t2) -{ - if (t2->multi_timeout) { - // swap t1 and t2 such that t1 is the multi timeout - timeout *tmp = t2; - t2 = t1; - t1 = tmp; - } - - multi_timeout *mt = calloc(1, sizeof(multi_timeout)); - multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t1); - - mth->timeout_list = g_slist_prepend(mth->timeout_list, t2); - g_hash_table_insert(multi_timeouts, t2, mth); - - t2->multi_timeout = mt; - - update_multi_timeout_values(mth); -} - -void update_multi_timeout_values(multi_timeout_handler *mth) -{ - int interval = calc_multi_timeout_interval(mth); - int next_timeout_msec = interval; - - struct timespec cur_time; - gettime(&cur_time); - - GSList *it = mth->timeout_list; - struct timespec diff_time; - while (it) { - timeout *t = it->data; - t->multi_timeout->count_to_expiration = t->interval_msec / interval; - timespec_subtract(&diff_time, &t->timeout_expires, &cur_time); - int msec_to_expiration = diff_time.tv_sec * 1000 + diff_time.tv_nsec / 1000000; - int count_left = msec_to_expiration / interval + (msec_to_expiration % interval != 0); - t->multi_timeout->current_count = t->multi_timeout->count_to_expiration - count_left; - if (msec_to_expiration < next_timeout_msec) - next_timeout_msec = msec_to_expiration; - it = it->next; - } - - mth->parent_timeout->interval_msec = interval; - timeout_list = g_slist_remove(timeout_list, mth->parent_timeout); - add_timeout_intern(next_timeout_msec, interval, callback_multi_timeout, mth, mth->parent_timeout); -} - -void callback_multi_timeout(void *arg) -{ - multi_timeout_handler *mth = arg; - struct timespec cur_time; - gettime(&cur_time); - GSList *it = mth->timeout_list; - while (it) { - GSList *next = it->next; - timeout *t = it->data; - if (t->multi_timeout && ++t->multi_timeout->current_count >= t->multi_timeout->count_to_expiration) { - t->_callback(t->arg); - if (multi_timeouts && g_hash_table_lookup(multi_timeouts, t)) { - // Timer still exists - t->multi_timeout->current_count = 0; - t->timeout_expires = add_msec_to_timespec(cur_time, t->interval_msec); - } else { - return; - } - } - it = next; - } -} - -void remove_from_multi_timeout(timeout *t) -{ - multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t); - g_hash_table_remove(multi_timeouts, t); - - mth->timeout_list = g_slist_remove(mth->timeout_list, t); - free(t->multi_timeout); - t->multi_timeout = 0; - - if (g_slist_length(mth->timeout_list) == 1) { - timeout *last_timeout = mth->timeout_list->data; - mth->timeout_list = g_slist_remove(mth->timeout_list, last_timeout); - free(last_timeout->multi_timeout); - last_timeout->multi_timeout = 0; - g_hash_table_remove(multi_timeouts, last_timeout); - g_hash_table_remove(multi_timeouts, mth->parent_timeout); - mth->parent_timeout->multi_timeout = 0; - stop_timeout(mth->parent_timeout); - free(mth); - - struct timespec cur_time, diff_time; - gettime(&cur_time); - timespec_subtract(&diff_time, &t->timeout_expires, &cur_time); - int msec_to_expiration = diff_time.tv_sec * 1000 + diff_time.tv_nsec / 1000000; - add_timeout_intern(msec_to_expiration, - last_timeout->interval_msec, - last_timeout->_callback, - last_timeout->arg, - last_timeout); - } else - update_multi_timeout_values(mth); -} - -void stop_multi_timeout(timeout *t) -{ - multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t); - g_hash_table_remove(multi_timeouts, mth->parent_timeout); - while (mth->timeout_list) { - timeout *t1 = mth->timeout_list->data; - mth->timeout_list = g_slist_remove(mth->timeout_list, t1); - g_hash_table_remove(multi_timeouts, t1); - free(t1->multi_timeout); - free(t1); - } - free(mth); -} - -double profiling_get_time_old_time = 0; +static double profiling_get_time_old_time = 0; double get_time() {

@@ -485,57 +216,31 @@

double profiling_get_time() { double t = get_time(); - if (profiling_get_time_old_time == 0) + if (profiling_get_time_old_time <= 0) profiling_get_time_old_time = t; double delta = t - profiling_get_time_old_time; profiling_get_time_old_time = t; return delta; } -TEST(mock_time) { - struct timespec t1 = {1000, 2}; - struct timespec t2 = {0, 0}; - struct timespec t3 = {2000, 3}; - int ret; - set_mock_time(&t1); - ret = gettime(&t2); - ASSERT_EQUAL(ret, 0); - ASSERT_EQUAL(t1.tv_sec, t2.tv_sec); - ASSERT_EQUAL(t1.tv_nsec, t2.tv_nsec); +/////////////////////////////////////////////////////////////////////////////// +// Tests start here - set_mock_time(&t3); - ret = gettime(&t2); - ASSERT_EQUAL(ret, 0); - ASSERT_EQUAL(t3.tv_sec, t2.tv_sec); - ASSERT_EQUAL(t3.tv_nsec, t2.tv_nsec); -} - -TEST(mock_time_ms) { - struct timespec t1 = {1000, 2 * 1000 * 1000}; - struct timespec t2 = {0, 0}; - struct timespec t3 = {2000, 3 * 1000 * 1000}; - int ret; - set_mock_time_ms(1000 * 1000 + 2); - ret = gettime(&t2); - ASSERT_EQUAL(ret, 0); - ASSERT_EQUAL(t1.tv_sec, t2.tv_sec); - ASSERT_EQUAL(t1.tv_nsec, t2.tv_nsec); - - set_mock_time_ms(2000 * 1000 + 3); - ret = gettime(&t2); - ASSERT_EQUAL(ret, 0); - ASSERT_EQUAL(t3.tv_sec, t2.tv_sec); - ASSERT_EQUAL(t3.tv_nsec, t2.tv_nsec); +static int64_t timeval_to_ms(struct timeval *v) +{ + if (!v) + return -1; + return (int64_t)(v->tv_sec * 1000 + v->tv_usec / 1000); } -void trigger_callback(void *arg) +static void trigger_callback(void *arg) { int *triggered = (int*) arg; *triggered += 1; } typedef struct { - timeout *timeout; + Timer *timer; int triggered; bool stop; bool change;

@@ -548,37 +253,78 @@ bool stop_other;

bool change_other; int change_other_value_ms; int change_other_interval_ms; - timeout *other; + Timer *other; } TimeoutContainer; -void container_callback(void *arg) { +static void container_callback(void *arg) { TimeoutContainer *container = (TimeoutContainer *)arg; container->triggered += 1; if (container->stop) - stop_timeout(container->timeout); + stop_timer(container->timer); else if (container->change) { - change_timeout(&container->timeout, container->change_value_ms, container->change_interval_ms, container_callback, arg); + change_timer(container->timer, true, container->change_value_ms, container->change_interval_ms, container_callback, arg); if (container->change_interval_ms) container->change = false; } if (container->add) { - add_timeout(container->add_value_ms, container->add_interval_ms, container_callback, arg, NULL); + Timer *timer = calloc(1, sizeof(Timer)); + init_timer(timer, "container_callback"); + change_timer(timer, true, container->add_value_ms, container->add_interval_ms, container_callback, arg); container->add = false; } if (container->stop_other) - stop_timeout(container->other); + stop_timer(container->other); else if (container->change_other) { - change_timeout(&container->other, container->change_other_value_ms, container->change_other_interval_ms, container_callback, arg); + change_timer(container->other, true, container->change_other_value_ms, container->change_other_interval_ms, container_callback, arg); container->change_other = false; } } -TEST(add_timeout_simple) { + +TEST(mock_time) { + struct timespec t1 = {1000, 2}; + struct timespec t2 = {0, 0}; + struct timespec t3 = {2000, 3}; + int ret; + set_mock_time(&t1); + ret = gettime(&t2); + ASSERT_EQUAL(ret, 0); + ASSERT_EQUAL(t1.tv_sec, t2.tv_sec); + ASSERT_EQUAL(t1.tv_nsec, t2.tv_nsec); + + set_mock_time(&t3); + ret = gettime(&t2); + ASSERT_EQUAL(ret, 0); + ASSERT_EQUAL(t3.tv_sec, t2.tv_sec); + ASSERT_EQUAL(t3.tv_nsec, t2.tv_nsec); +} + +TEST(mock_time_ms) { + struct timespec t1 = {1000, 2 * 1000 * 1000}; + struct timespec t2 = {0, 0}; + struct timespec t3 = {2000, 3 * 1000 * 1000}; + int ret; + set_mock_time_ms(1000 * 1000 + 2); + ret = gettime(&t2); + ASSERT_EQUAL(ret, 0); + ASSERT_EQUAL(t1.tv_sec, t2.tv_sec); + ASSERT_EQUAL(t1.tv_nsec, t2.tv_nsec); + + set_mock_time_ms(2000 * 1000 + 3); + ret = gettime(&t2); + ASSERT_EQUAL(ret, 0); + ASSERT_EQUAL(t3.tv_sec, t2.tv_sec); + ASSERT_EQUAL(t3.tv_nsec, t2.tv_nsec); +} + +TEST(change_timer_simple) { u_int64_t origin = 2134523; int triggered = 0; + Timer timer; + init_timer(&timer, __FUNCTION__); set_mock_time_ms(origin + 0); - add_timeout(200, 0, trigger_callback, &triggered, NULL); + change_timer(&timer, true, 200, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -603,13 +349,17 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 1); } -TEST(add_timeout_simple_two) { +TEST(change_timer_simple_two) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); set_mock_time_ms(origin + 0); - add_timeout(100, 0, trigger_callback, &triggered, NULL); - add_timeout(200, 0, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 0, trigger_callback, &triggered); + change_timer(&t2, true, 200, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -638,13 +388,17 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 2); } -TEST(add_timeout_simple_two_reversed) { +TEST(change_timer_simple_two_reversed) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); set_mock_time_ms(origin + 0); - add_timeout(200, 0, trigger_callback, &triggered, NULL); - add_timeout(100, 0, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 200, 0, trigger_callback, &triggered); + change_timer(&t2, true, 100, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -673,13 +427,17 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 2); } -TEST(add_timeout_simple_two_overlap) { +TEST(change_timer_simple_two_overlap) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); set_mock_time_ms(origin + 0); - add_timeout(100, 0, trigger_callback, &triggered, NULL); - add_timeout(100, 0, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 0, trigger_callback, &triggered); + change_timer(&t2, true, 100, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -700,16 +458,19 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 2); } -TEST(add_timeout_simple_inside_callback) { +TEST(change_timer_simple_inside_callback) { u_int64_t origin = 2134523; TimeoutContainer container; bzero(&container, sizeof(container)); + Timer timer; + init_timer(&timer, __FUNCTION__); set_mock_time_ms(origin + 0); container.add = true; container.add_value_ms = 100; - container.timeout = add_timeout(200, 0, container_callback, &container, NULL); + container.timer = &timer; + change_timer(container.timer, true, 200, 0, container_callback, &container); handle_expired_timers(); ASSERT_EQUAL(container.triggered, 0);

@@ -734,12 +495,14 @@ handle_expired_timers();

ASSERT_EQUAL(container.triggered, 2); } -TEST(add_timeout_multi) { +TEST(change_timer_multi) { u_int64_t origin = 2134523; int triggered = 0; + Timer timer; + init_timer(&timer, __FUNCTION__); set_mock_time_ms(origin + 0); - add_timeout(200, 100, trigger_callback, &triggered, NULL); + change_timer(&timer, true, 200, 100, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -772,13 +535,17 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 4); } -TEST(add_timeout_multi_two) { +TEST(change_timer_multi_two) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); set_mock_time_ms(origin + 0); - add_timeout(100, 100, trigger_callback, &triggered, NULL); - add_timeout(200, 200, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 100, trigger_callback, &triggered); + change_timer(&t2, true, 200, 200, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -803,13 +570,17 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 6); } -TEST(add_timeout_multi_two_overlap) { +TEST(change_timer_multi_two_overlap) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); set_mock_time_ms(origin + 0); - add_timeout(100, 100, trigger_callback, &triggered, NULL); - add_timeout(100, 100, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 100, trigger_callback, &triggered); + change_timer(&t2, true, 100, 100, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -838,13 +609,17 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 8); } -TEST(add_timeout_simple_multi_two) { +TEST(change_timer_simple_multi_two) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); set_mock_time_ms(origin + 0); - add_timeout(100, 100, trigger_callback, &triggered, NULL); - add_timeout(200, 0, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 100, trigger_callback, &triggered); + change_timer(&t2, true, 200, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -873,13 +648,17 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 5); } -TEST(add_timeout_simple_multi_two_overlap) { +TEST(change_timer_simple_multi_two_overlap) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); set_mock_time_ms(origin + 0); - add_timeout(100, 100, trigger_callback, &triggered, NULL); - add_timeout(100, 0, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 100, trigger_callback, &triggered); + change_timer(&t2, true, 100, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -908,13 +687,17 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 5); } -TEST(stop_timeout_simple_two) { +TEST(stop_timer_simple_two) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); set_mock_time_ms(origin + 0); - timeout *t1 = add_timeout(100, 0, trigger_callback, &triggered, NULL); - add_timeout(200, 0, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 0, trigger_callback, &triggered); + change_timer(&t2, true, 200, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -922,7 +705,7 @@ set_mock_time_ms(origin + 50);

handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - stop_timeout(t1); + stop_timer(&t1); set_mock_time_ms(origin + 100); handle_expired_timers();

@@ -945,13 +728,17 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 1); } -TEST(stop_timeout_simple_two_reversed) { +TEST(stop_timer_simple_two_reversed) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); set_mock_time_ms(origin + 0); - add_timeout(100, 0, trigger_callback, &triggered, NULL); - timeout *t2 = add_timeout(200, 0, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 0, trigger_callback, &triggered); + change_timer(&t2, true, 200, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -959,7 +746,7 @@ set_mock_time_ms(origin + 50);

handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - stop_timeout(t2); + stop_timer(&t2); set_mock_time_ms(origin + 100); handle_expired_timers();

@@ -982,15 +769,18 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 1); } -TEST(stop_timeout_simple_inside_callback) { +TEST(stop_timer_simple_inside_callback) { u_int64_t origin = 2134523; TimeoutContainer container; bzero(&container, sizeof(container)); + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0); container.stop = true; - container.timeout = add_timeout(200, 0, container_callback, &container, NULL); + container.timer = &t1; + change_timer(&t1, true, 200, 0, container_callback, &container); handle_expired_timers(); ASSERT_EQUAL(container.triggered, 0);

@@ -1015,17 +805,23 @@ handle_expired_timers();

ASSERT_EQUAL(container.triggered, 1); } -TEST(stop_timeout_simple_other_inside_callback) { +TEST(stop_timer_simple_other_inside_callback) { u_int64_t origin = 2134523; TimeoutContainer container; bzero(&container, sizeof(container)); + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t1, "t2"); int triggered_other = 0; set_mock_time_ms(origin + 0); container.stop_other = true; - container.timeout = add_timeout(100, 0, container_callback, &container, NULL); - container.other = add_timeout(200, 0, trigger_callback, &triggered_other, NULL); + container.timer = &t1; + change_timer(&t1, true, 100, 0, container_callback, &container); + container.other = &t2; + change_timer(&t2, true, 200, 0, trigger_callback, &triggered_other); handle_expired_timers(); ASSERT_EQUAL(container.triggered, 0); ASSERT_EQUAL(triggered_other, 0);

@@ -1046,12 +842,14 @@ ASSERT_EQUAL(container.triggered, 1);

ASSERT_EQUAL(triggered_other, 0); } -TEST(stop_timeout_multi) { +TEST(stop_timer_multi) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0); - timeout *t1 = add_timeout(100, 100, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 100, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -1071,7 +869,7 @@ set_mock_time_ms(origin + 200);

handle_expired_timers(); ASSERT_EQUAL(triggered, 2); - stop_timeout(t1); + stop_timer(&t1); set_mock_time_ms(origin + 300); handle_expired_timers();

@@ -1082,13 +880,17 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 2); } -TEST(stop_timeout_multi_two) { +TEST(stop_timer_multi_two) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); set_mock_time_ms(origin + 0); - timeout *t1 = add_timeout(100, 100, trigger_callback, &triggered, NULL); - add_timeout(100, 100, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 100, trigger_callback, &triggered); + change_timer(&t2, true, 100, 100, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -1108,7 +910,7 @@ set_mock_time_ms(origin + 200);

handle_expired_timers(); ASSERT_EQUAL(triggered, 4); - stop_timeout(t1); + stop_timer(&t1); set_mock_time_ms(origin + 300); handle_expired_timers();

@@ -1119,15 +921,18 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 6); } -TEST(stop_timeout_multi_inside_callback) { +TEST(stop_timer_multi_inside_callback) { u_int64_t origin = 2134523; TimeoutContainer container; bzero(&container, sizeof(container)); + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0); container.stop = true; - container.timeout = add_timeout(100, 100, container_callback, &container, NULL); + container.timer = &t1; + change_timer(&t1, true, 100, 100, container_callback, &container); handle_expired_timers(); ASSERT_EQUAL(container.triggered, 0);

@@ -1152,17 +957,23 @@ handle_expired_timers();

ASSERT_EQUAL(container.triggered, 1); } -TEST(stop_timeout_multi_other_inside_callback) { +TEST(stop_timer_multi_other_inside_callback) { u_int64_t origin = 2134523; TimeoutContainer container; bzero(&container, sizeof(container)); + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); int triggered_other = 0; set_mock_time_ms(origin + 0); container.stop_other = true; - container.timeout = add_timeout(100, 100, container_callback, &container, NULL); - container.other = add_timeout(200, 10, trigger_callback, &triggered_other, NULL); + container.timer = &t1; + change_timer(&t1, true, 100, 100, container_callback, &container); + container.other = &t2; + change_timer(&t2, true, 200, 10, trigger_callback, &triggered_other); handle_expired_timers(); ASSERT_EQUAL(container.triggered, 0); ASSERT_EQUAL(triggered_other, 0);

@@ -1183,12 +994,14 @@ ASSERT_EQUAL(container.triggered, 1);

ASSERT_EQUAL(triggered_other, 0); } -TEST(change_timeout_simple) { +TEST(change_timer_simple_again) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0); - timeout *t1 = add_timeout(200, 0, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 200, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -1196,7 +1009,7 @@ set_mock_time_ms(origin + 100);

handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - change_timeout(&t1, 200, 0, trigger_callback, &triggered); + change_timer(&t1, true, 200, 0, trigger_callback, &triggered); set_mock_time_ms(origin + 200); handle_expired_timers();

@@ -1215,13 +1028,17 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 1); } -TEST(change_timeout_simple_two) { +TEST(change_timer_simple_two_again) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); set_mock_time_ms(origin + 0); - timeout *t1 = add_timeout(200, 0, trigger_callback, &triggered, NULL); - add_timeout(250, 0, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 200, 0, trigger_callback, &triggered); + change_timer(&t2, true, 250, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -1229,7 +1046,7 @@ set_mock_time_ms(origin + 100);

handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - change_timeout(&t1, 200, 0, trigger_callback, &triggered); + change_timer(&t1, true, 200, 0, trigger_callback, &triggered); set_mock_time_ms(origin + 200); handle_expired_timers();

@@ -1248,16 +1065,19 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 2); } -TEST(change_timeout_simple_inside_callback) { +TEST(change_timer_simple_inside_callback_again) { u_int64_t origin = 2134523; TimeoutContainer container; bzero(&container, sizeof(container)); + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0); container.change = true; container.change_value_ms = 100; - container.timeout = add_timeout(200, 0, container_callback, &container, NULL); + container.timer = &t1; + change_timer(&t1, true, 200, 0, container_callback, &container); handle_expired_timers(); ASSERT_EQUAL(container.triggered, 0);

@@ -1286,18 +1106,24 @@ handle_expired_timers();

ASSERT_EQUAL(container.triggered, 3); } -TEST(change_timeout_simple_other_inside_callback) { +TEST(change_timer_simple_other_inside_callback) { u_int64_t origin = 2134523; TimeoutContainer container; bzero(&container, sizeof(container)); + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); int triggered_other = 0; set_mock_time_ms(origin + 0); container.change_other = true; container.change_other_value_ms = 100; - container.timeout = add_timeout(100, 0, container_callback, &container, NULL); - container.other = add_timeout(1000, 0, trigger_callback, &triggered_other, NULL); + container.timer = &t1; + change_timer(&t1, true, 100, 0, container_callback, &container); + container.other = &t2; + change_timer(&t2, true, 1000, 0, trigger_callback, &triggered_other); handle_expired_timers(); ASSERT_EQUAL(container.triggered, 0); ASSERT_EQUAL(triggered_other, 0);

@@ -1322,6 +1148,8 @@ TEST(add_change_two_timeout_simple_inside_callback) {

u_int64_t origin = 2134523; TimeoutContainer container; bzero(&container, sizeof(container)); + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0);

@@ -1329,7 +1157,8 @@ container.add = true;

container.add_value_ms = 100; container.change = true; container.change_value_ms = 100; - container.timeout = add_timeout(200, 0, container_callback, &container, NULL); + container.timer = &t1; + change_timer(&t1, true, 200, 0, container_callback, &container); handle_expired_timers(); ASSERT_EQUAL(container.triggered, 0);

@@ -1360,12 +1189,14 @@ handle_expired_timers();

ASSERT_EQUAL(container.triggered, 4); } -TEST(change_timeout_multi) { +TEST(change_timer_multi_again) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0); - timeout *t1 = add_timeout(100, 50, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 50, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -1381,7 +1212,7 @@ set_mock_time_ms(origin + 200);

handle_expired_timers(); ASSERT_EQUAL(triggered, 3); - change_timeout(&t1, 100, 100, trigger_callback, &triggered); + change_timer(&t1, true, 100, 100, trigger_callback, &triggered); set_mock_time_ms(origin + 250); handle_expired_timers();

@@ -1400,12 +1231,14 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 5); } -TEST(change_timeout_simple_multi) { +TEST(change_timer_simple_multi) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0); - timeout *t1 = add_timeout(100, 0, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -1413,7 +1246,7 @@ set_mock_time_ms(origin + 50);

handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - change_timeout(&t1, 100, 100, trigger_callback, &triggered); + change_timer(&t1, true, 100, 100, trigger_callback, &triggered); set_mock_time_ms(origin + 100); handle_expired_timers();

@@ -1431,7 +1264,7 @@ set_mock_time_ms(origin + 250);

handle_expired_timers(); ASSERT_EQUAL(triggered, 2); - change_timeout(&t1, 50, 0, trigger_callback, &triggered); + change_timer(&t1, true, 50, 0, trigger_callback, &triggered); set_mock_time_ms(origin + 300); handle_expired_timers();

@@ -1446,17 +1279,20 @@ handle_expired_timers();

ASSERT_EQUAL(triggered, 3); } -TEST(change_timeout_multi_inside_callback) { +TEST(change_timer_multi_inside_callback) { u_int64_t origin = 2134523; TimeoutContainer container; bzero(&container, sizeof(container)); + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0); container.change = true; container.change_value_ms = 100; container.change_interval_ms = 100; - container.timeout = add_timeout(200, 200, container_callback, &container, NULL); + container.timer = &t1; + change_timer(&t1, true, 200, 200, container_callback, &container); handle_expired_timers(); ASSERT_EQUAL(container.triggered, 0);

@@ -1485,10 +1321,14 @@ handle_expired_timers();

ASSERT_EQUAL(container.triggered, 3); } -TEST(change_timeout_multi_other_inside_callback) { +TEST(change_timer_multi_other_inside_callback) { u_int64_t origin = 2134523; TimeoutContainer container; bzero(&container, sizeof(container)); + Timer t1; + init_timer(&t1, "t1"); + Timer t2; + init_timer(&t2, "t2"); int triggered_other = 0; set_mock_time_ms(origin + 0);

@@ -1496,8 +1336,10 @@

container.change_other = true; container.change_other_value_ms = 100; container.change_other_interval_ms = 100; - container.timeout = add_timeout(100, 0, container_callback, &container, NULL); - container.other = add_timeout(1000, 0, trigger_callback, &triggered_other, NULL); + container.timer = &t1; + change_timer(&t1, true, 100, 0, container_callback, &container); + container.other = &t2; + change_timer(&t2, true, 1000, 0, trigger_callback, &triggered_other); handle_expired_timers(); ASSERT_EQUAL(container.triggered, 0); ASSERT_EQUAL(triggered_other, 0);

@@ -1522,6 +1364,8 @@ TEST(add_change_two_timeout_multi_inside_callback) {

u_int64_t origin = 2134523; TimeoutContainer container; bzero(&container, sizeof(container)); + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0);

@@ -1531,7 +1375,8 @@ container.add_interval_ms = 100;

container.change = true; container.change_value_ms = 100; container.change_interval_ms = 100; - container.timeout = add_timeout(200, 200, container_callback, &container, NULL); + container.timer = &t1; + change_timer(&t1, true, 200, 200, container_callback, &container); handle_expired_timers(); ASSERT_EQUAL(container.triggered, 0);

@@ -1562,153 +1407,154 @@ handle_expired_timers();

ASSERT_EQUAL(container.triggered, 5); } -int64_t timeval_to_ms(struct timeval *v) -{ - if (!v) - return -1; - return (int64_t)(v->tv_sec * 1000 + v->tv_usec / 1000); -} - -TEST(get_next_timeout_simple) { +TEST(get_duration_to_next_timer_expiration_simple) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0); - timeout *t1 = add_timeout(200, 0, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 200, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 200); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 200); set_mock_time_ms(origin + 100); handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 100); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 100); - change_timeout(&t1, 200, 0, trigger_callback, &triggered); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 200); + change_timer(&t1, true, 200, 0, trigger_callback, &triggered); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 200); set_mock_time_ms(origin + 200); handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 100); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 100); set_mock_time_ms(origin + 250); handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 50); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 50); set_mock_time_ms(origin + 300); handle_expired_timers(); ASSERT_EQUAL(triggered, 1); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), -1); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), -1); set_mock_time_ms(origin + 500); handle_expired_timers(); ASSERT_EQUAL(triggered, 1); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), -1); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), -1); } -TEST(get_next_timeout_multi) { +TEST(get_duration_to_next_timer_expiration_multi) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0); - timeout *t1 = add_timeout(100, 200, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 200, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 100); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 100); set_mock_time_ms(origin + 50); handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 50); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 50); set_mock_time_ms(origin + 100); handle_expired_timers(); ASSERT_EQUAL(triggered, 1); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 200); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 200); set_mock_time_ms(origin + 200); handle_expired_timers(); ASSERT_EQUAL(triggered, 1); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 100); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 100); set_mock_time_ms(origin + 300); handle_expired_timers(); ASSERT_EQUAL(triggered, 2); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 200); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 200); - change_timeout(&t1, 100, 0, trigger_callback, &triggered); + change_timer(&t1, true, 100, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 2); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 100); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 100); - change_timeout(&t1, 100, 300, trigger_callback, &triggered); + change_timer(&t1, true, 100, 300, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 2); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 100); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 100); set_mock_time_ms(origin + 400); handle_expired_timers(); ASSERT_EQUAL(triggered, 3); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 300); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 300); set_mock_time_ms(origin + 700); handle_expired_timers(); ASSERT_EQUAL(triggered, 4); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 300); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 300); } -TEST(get_next_timeout_simple_multi) { +TEST(get_duration_to_next_timer_expiration_simple_multi) { u_int64_t origin = 2134523; + Timer t1; + init_timer(&t1, "t1"); int triggered = 0; set_mock_time_ms(origin + 0); - timeout *t1 = add_timeout(100, 0, trigger_callback, &triggered, NULL); - add_timeout(200, 50, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 0, trigger_callback, &triggered); + change_timer(&t1, true, 200, 50, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 100); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 100); set_mock_time_ms(origin + 50); handle_expired_timers(); ASSERT_EQUAL(triggered, 0); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 50); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 50); set_mock_time_ms(origin + 100); handle_expired_timers(); ASSERT_EQUAL(triggered, 1); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 100); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 100); set_mock_time_ms(origin + 200); handle_expired_timers(); ASSERT_EQUAL(triggered, 2); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 50); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 50); set_mock_time_ms(origin + 250); handle_expired_timers(); ASSERT_EQUAL(triggered, 3); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 50); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 50); - change_timeout(&t1, 10, 0, trigger_callback, &triggered); + change_timer(&t1, true, 10, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 3); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 10); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 10); set_mock_time_ms(origin + 260); handle_expired_timers(); ASSERT_EQUAL(triggered, 4); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), 40); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), 40); } TEST(cleanup_timeout_simple) { u_int64_t origin = 2134523; int triggered = 0; + Timer t1; + init_timer(&t1, "t1"); set_mock_time_ms(origin + 0); - add_timeout(100, 0, trigger_callback, &triggered, NULL); - add_timeout(200, 0, trigger_callback, &triggered, NULL); - add_timeout(300, 0, trigger_callback, &triggered, NULL); + change_timer(&t1, true, 100, 0, trigger_callback, &triggered); + change_timer(&t1, true, 200, 0, trigger_callback, &triggered); + change_timer(&t1, true, 300, 0, trigger_callback, &triggered); handle_expired_timers(); ASSERT_EQUAL(triggered, 0);

@@ -1724,8 +1570,8 @@ set_mock_time_ms(origin + 150);

handle_expired_timers(); ASSERT_EQUAL(triggered, 1); - cleanup_timeout(); - ASSERT_EQUAL(timeval_to_ms(get_next_timeout()), -1); + cleanup_timers(); + ASSERT_EQUAL(timeval_to_ms(get_duration_to_next_timer_expiration()), -1); set_mock_time_ms(origin + 200); handle_expired_timers();
M src/util/timer.hsrc/util/timer.h

@@ -21,44 +21,45 @@

#include <glib.h> #include <time.h> #include <sys/time.h> +#include "bool.h" -// Single shot timers (i.e. timers with interval_msec == 0) are deleted automatically as soon as they expire, -// i.e. you do not need to stop them, however it is safe to call stop_timeout for these timers. -// You can pass the address of the variable storing the pointer to the timer as 'self' in add_timeout, in which -// case it is used to clear the pointer if the timer is destroyed automatically. This enforces the timeout pointers -// to be either valid or NULL. -// Periodic timeouts are aligned to each other whenever possible, i.e. one interval_msec is an -// integral multiple of the other. +typedef void TimerCallback(void *arg); -typedef struct _timeout timeout; +typedef struct { + char name_[64]; + bool enabled_; + double expiration_time_; + int period_ms_; + TimerCallback *callback_; + void *arg_; + bool handled_; +} Timer; -// Initializes default global data. -void default_timeout(); +// Initialize the timer module. +void default_timers(); -// Cleans up: stops all timers and frees memory. -void cleanup_timeout(); +// Destroy the timer module. +void cleanup_timers(); -// Installs a timer with the first timeout after 'value_msec' and then an optional periodic timeout every -// 'interval_msec' (set it to 0 to prevent periodic timeouts). -// '_callback' is the function called when the timer reaches the timeout. -// 'arg' is the argument passed to the callback function. -// 'self' is an optional pointer to a timeout* variable. If non-NULL, the variable is set to NULL when the timer -// is destroyed (with stop_timeout, cleanup_timeout or when the timer expires and it is single-shot). -// Returns a pointer to the timer, which is needed for stopping/changing it. -timeout *add_timeout(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout **self); +// Initialize a timer. Caller keeps ownership. +void init_timer(Timer *timer, const char *name); -// Changes timer 't'. If it does not exist, a new timer is created, with self set to 't'. -void change_timeout(timeout **t, int value_msec, int interval_msec, void (*_callback)(void *), void *arg); +// Destroy a timer. Does not free() the pointer. +void destroy_timer(Timer *timer); -// Stops the timer 't' -void stop_timeout(timeout *t); +// Modify a timer. +void change_timer(Timer *timer, bool enabled, int delay_ms, int period_ms, TimerCallback *callback, void *arg); -// Get the time when the next installed timer will expire, or NULL if there is no timer. -// Do not free the pointer; but it is safe to change its contents. -struct timeval *get_next_timeout(); +void stop_timer(Timer *timer); + +// Get the time duration to the next expiration time, or NULL if there is no active timer. +// Do not free the pointer; it is harmless to change its contents. +struct timeval *get_duration_to_next_timer_expiration(); // Callback of all expired timeouts void handle_expired_timers(); + +// Time helper functions. // Returns -1 if t1 < t2, 0 if t1 == t2, 1 if t1 > t2 gint compare_timespecs(const struct timespec *t1, const struct timespec *t2);

@@ -69,6 +70,7 @@ // Returns the time difference in seconds between the current time and the last time this function was called.

// At the first call returns zero. double profiling_get_time(); +// Get current time in seconds, from an unspecified origin. double get_time(); #endif // TIMER_H