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; clock_gettime(CLOCK_MONOTONIC, &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); }
timeout* add_timeout(int value_msec, int interval_msec, void (*_callback)(void*), void* arg) { timeout* t = malloc(sizeof(timeout)); t->multi_timeout = 0; add_timeout_intern(value_msec, interval_msec, _callback, arg, t); return t; }
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; clock_gettime(CLOCK_MONOTONIC, &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_timeout_expired() { struct timespec cur_time; timeout* t; while (timeout_list) { clock_gettime(CLOCK_MONOTONIC, &cur_time); t = timeout_list->data; if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) { // it's time for the callback function 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 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; } } }
timeout* add_timeout(int value_msec, int interval_msec, void (*_callback)(void*), void* arg, timeout **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 (g_slist_find(timeout_list, t) == 0 && g_hash_table_lookup(multi_timeouts, t) == 0) printf("programming error: timeout already deleted..."); else { if (t->multi_timeout) remove_from_multi_timeout((timeout*)t); else timeout_list = g_slist_remove(timeout_list, t); add_timeout_intern(value_msec, interval_msec, _callback, arg, (timeout*)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); } }
void callback_timeout_expired() { struct timespec cur_time; timeout* t; while (timeout_list) { clock_gettime(CLOCK_MONOTONIC, &cur_time); t = timeout_list->data; if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) { // it's time for the callback function t->_callback(t->arg); if (g_slist_find(timeout_list, t)) { // if _callback() calls stop_timeout(t) the timeout 't' was freed and is // not in the timeout_list 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 free(t); } } else return; } }