diff options
author | Ben Longbons <b.r.longbons@gmail.com> | 2011-09-10 16:12:07 -0700 |
---|---|---|
committer | Ben Longbons <b.r.longbons@gmail.com> | 2011-09-10 16:12:07 -0700 |
commit | f841b6fdcc802e73d52da0e67ee192c0c2c1c7e1 (patch) | |
tree | d9b013ab252968ec1e90e721f7b2ab819af0acb0 /src/common/timer.c | |
parent | 5939e1bec75f2550d3ce109b9cd9a5d22c0626c2 (diff) | |
parent | 723fb5d3431b847526c433a13aa74485cfb564a3 (diff) | |
download | tmwa-f841b6fdcc802e73d52da0e67ee192c0c2c1c7e1.tar.gz tmwa-f841b6fdcc802e73d52da0e67ee192c0c2c1c7e1.tar.bz2 tmwa-f841b6fdcc802e73d52da0e67ee192c0c2c1c7e1.tar.xz tmwa-f841b6fdcc802e73d52da0e67ee192c0c2c1c7e1.zip |
Merge commit '723fb5d3431b847526c433a13aa74485cfb564a3'
Diffstat (limited to 'src/common/timer.c')
-rw-r--r-- | src/common/timer.c | 320 |
1 files changed, 112 insertions, 208 deletions
diff --git a/src/common/timer.c b/src/common/timer.c index fca6f42..f4be19b 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -1,184 +1,123 @@ -// $Id: timer.c,v 1.1.1.1 2004/09/10 17:44:49 MagicalTux Exp $ -// original : core.c 2003/02/26 18:03:12 Rev 1.7 - #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> -#ifdef LCCWIN32 -#include <winsock.h> -#else #include <sys/socket.h> #include <sys/time.h> -#endif #include "timer.h" #include "utils.h" -#ifdef MEMWATCH -#include "memwatch.h" -#endif - static struct TimerData *timer_data; -static int timer_data_max, timer_data_num; -static int *free_timer_list; -static int free_timer_list_max, free_timer_list_pos; - -static int timer_heap_max; -static int *timer_heap = NULL; - -// for debug -struct timer_func_list -{ - int (*func) (int, unsigned int, int, int); - struct timer_func_list *next; - char *name; -}; -static struct timer_func_list *tfl_root; - -#if defined(LCCWIN32) -void gettimeofday (struct timeval *t, struct timezone *dummy) -{ - DWORD millisec = GetTickCount (); - - t->tv_sec = (int) (millisec / 1000); - t->tv_usec = (millisec % 1000) * 1000; -} - -#endif - -// -int add_timer_func_list (int (*func) (int, unsigned int, int, int), - char *name) -{ - struct timer_func_list *tfl; - - CREATE (tfl, struct timer_func_list, 1); - CREATE (tfl->name, char, strlen (name) + 1); - - tfl->next = tfl_root; - tfl->func = func; - strcpy (tfl->name, name); - tfl_root = tfl; - - return 0; -} - -char *search_timer_func_list (int (*func) (int, unsigned int, int, int)) -{ - struct timer_func_list *tfl; - for (tfl = tfl_root; tfl; tfl = tfl->next) - { - if (func == tfl->func) - return tfl->name; - } - return "???"; -} - -/*---------------------------- - * Get tick time - *----------------------------*/ -static unsigned int gettick_cache; -static int gettick_count; -unsigned int gettick_nocache (void) +static uint32_t timer_data_max, timer_data_num; +static timer_id *free_timer_list; +static uint32_t free_timer_list_max, free_timer_list_pos; + +/// Okay, I think I understand this structure now: +/// the timer heap is a magic queue that allows inserting timers and then popping them in order +/// designed to copy only log2(N) entries instead of N +// timer_heap[0] is the size (greatest index into the heap) +// timer_heap[1] is the first actual element +// timer_heap_max increases 256 at a time and never decreases +static uint32_t timer_heap_max = 0; +/// FIXME: refactor the code to put the size in a separate variable +//nontrivial because indices get multiplied +static timer_id *timer_heap = NULL; + + +static uint32_t gettick_cache; +static uint8_t gettick_count = 0; + +uint32_t gettick_nocache (void) { struct timeval tval; + // BUG: This will cause strange behavior if the system clock is changed! + // it should be reimplemented in terms of clock_gettime(CLOCK_MONOTONIC, ) gettimeofday (&tval, NULL); - gettick_count = 256; + gettick_count = 255; return gettick_cache = tval.tv_sec * 1000 + tval.tv_usec / 1000; } -unsigned int gettick (void) +uint32_t gettick (void) { - gettick_count--; - if (gettick_count < 0) - return gettick_nocache (); - return gettick_cache; + if (gettick_count--) + return gettick_cache; + return gettick_nocache (); } -/*====================================== - * CORE : Timer Heap - *-------------------------------------- - */ -static void push_timer_heap (int index) +static void push_timer_heap (timer_id index) { - int i, h; - if (timer_heap == NULL || timer_heap[0] + 1 >= timer_heap_max) { - int first = timer_heap == NULL; - timer_heap_max += 256; RECREATE (timer_heap, int, timer_heap_max); - memset (timer_heap + (timer_heap_max - 256), 0, sizeof (int) * 256); - if (first) - timer_heap[0] = 0; + memset (timer_heap + (timer_heap_max - 256), 0, sizeof (timer_id) * 256); } - +// timer_heap[0] is the greatest index into the heap, which increases timer_heap[0]++; - for (h = timer_heap[0] - 1, i = (h - 1) / 2; - h > 0 && DIFF_TICK (timer_data[index].tick, - timer_data[timer_heap[i + 1]].tick) < 0; - i = (h - 1) / 2) + timer_id h = timer_heap[0]-1, i = (h - 1) / 2; + while (h) { + // avoid wraparound problems, it really means this: + // timer_data[index].tick >= timer_data[timer_heap[i+1]].tick + if ( DIFF_TICK(timer_data[index].tick, timer_data[timer_heap[i+1]].tick) >= 0) + break; timer_heap[h + 1] = timer_heap[i + 1]; h = i; + i = (h - 1) / 2; } timer_heap[h + 1] = index; } -static int top_timer_heap () +static timer_id top_timer_heap () { - if (timer_heap == NULL || timer_heap[0] <= 0) + if (!timer_heap || !timer_heap[0]) return -1; - return timer_heap[1]; } -static int pop_timer_heap () +static timer_id pop_timer_heap () { - int i, h, k; - int ret, last; - - if (timer_heap == NULL || timer_heap[0] <= 0) + if (!timer_heap || !timer_heap[0]) return -1; - ret = timer_heap[1]; - last = timer_heap[timer_heap[0]]; + timer_id ret = timer_heap[1]; + timer_id last = timer_heap[timer_heap[0]]; timer_heap[0]--; + uint32_t h, k; for (h = 0, k = 2; k < timer_heap[0]; k = k * 2 + 2) { - if (DIFF_TICK - (timer_data[timer_heap[k + 1]].tick, - timer_data[timer_heap[k]].tick) > 0) + if (DIFF_TICK(timer_data[timer_heap[k + 1]].tick, timer_data[timer_heap[k]].tick) > 0) k--; timer_heap[h + 1] = timer_heap[k + 1], h = k; } if (k == timer_heap[0]) timer_heap[h + 1] = timer_heap[k], h = k - 1; - for (i = (h - 1) / 2; - h > 0 - && DIFF_TICK (timer_data[timer_heap[i + 1]].tick, - timer_data[last].tick) > 0; i = (h - 1) / 2) + uint32_t i = (h - 1) / 2; + while (h) { - timer_heap[h + 1] = timer_heap[i + 1], h = i; + if (DIFF_TICK (timer_data[timer_heap[i + 1]].tick, timer_data[last].tick) <= 0) + break; + timer_heap[h + 1] = timer_heap[i + 1]; + h = i; + i = (h - 1) / 2; } timer_heap[h + 1] = last; return ret; } -int add_timer (unsigned int tick, int (*func) (int, unsigned int, int, int), - int id, int data) +timer_id add_timer (tick_t tick, timer_func func, custom_id_t id, custom_data_t data) { - struct TimerData *td; - int i; + timer_id i; if (free_timer_list_pos) { + // Retrieve a freed timer id instead of a new one + // I think it should be possible to avoid the loop somehow do { i = free_timer_list[--free_timer_list_pos]; @@ -187,12 +126,13 @@ int add_timer (unsigned int tick, int (*func) (int, unsigned int, int, int), } else i = timer_data_num; + + // I have no idea what this is doing if (i >= timer_data_num) - for (i = timer_data_num; i < timer_data_max && timer_data[i].type; - i++); + for (i = timer_data_num; i < timer_data_max && timer_data[i].type; i++) + ; if (i >= timer_data_num && i >= timer_data_max) { - int j; if (timer_data_max == 0) { timer_data_max = 256; @@ -202,143 +142,112 @@ int add_timer (unsigned int tick, int (*func) (int, unsigned int, int, int), { timer_data_max += 256; RECREATE (timer_data, struct TimerData, timer_data_max); - if (timer_data == NULL) - { - printf ("out of memory : add_timer timer_data\n"); - exit (1); - } memset (timer_data + (timer_data_max - 256), 0, sizeof (struct TimerData) * 256); } - for (j = timer_data_max - 256; j < timer_data_max; j++) - timer_data[j].type = 0; } - td = &timer_data[i]; - td->tick = tick; - td->func = func; - td->id = id; - td->data = data; - td->type = TIMER_ONCE_AUTODEL; - td->interval = 1000; + timer_data[i].tick = tick; + timer_data[i].func = func; + timer_data[i].id = id; + timer_data[i].data = data; + timer_data[i].type = TIMER_ONCE_AUTODEL; + timer_data[i].interval = 1000; push_timer_heap (i); if (i >= timer_data_num) timer_data_num = i + 1; return i; } -int add_timer_interval (unsigned int tick, - int (*func) (int, unsigned int, int, int), int id, - int data, int interval) +timer_id add_timer_interval (tick_t tick, timer_func func, custom_id_t id, + custom_data_t data, interval_t interval) { - int tid; - tid = add_timer (tick, func, id, data); + timer_id tid = add_timer (tick, func, id, data); timer_data[tid].type = TIMER_INTERVAL; timer_data[tid].interval = interval; return tid; } -int delete_timer (int id, int (*func) (int, unsigned int, int, int)) +void delete_timer (timer_id id, timer_func func) { - if (id <= 0 || id >= timer_data_num) + if (id == 0 || id >= timer_data_num) { - printf ("delete_timer error : no such timer %d\n", id); - return -1; + fprintf (stderr, "delete_timer error : no such timer %d\n", id); + abort (); } if (timer_data[id].func != func) { - printf - ("delete_timer error : function dismatch %08x(%s) != %08x(%s)\n", - (int) timer_data[id].func, - search_timer_func_list (timer_data[id].func), (int) func, - search_timer_func_list (func)); - return -2; + fprintf (stderr, "Timer mismatch\n"); + abort (); } - // そのうち消えるにまかせる + // "to let them disappear" - is this just in case? timer_data[id].func = NULL; timer_data[id].type = TIMER_ONCE_AUTODEL; timer_data[id].tick -= 60 * 60 * 1000; - return 0; } -int addtick_timer (int tid, unsigned int tick) +tick_t addtick_timer (timer_id tid, interval_t tick) { return timer_data[tid].tick += tick; } -struct TimerData *get_timer (int tid) +struct TimerData *get_timer (timer_id tid) { return &timer_data[tid]; } -int do_timer (unsigned int tick) +interval_t do_timer (tick_t tick) { - int i, nextmin = 1000; - -#if 0 - static int disp_tick = 0; - if (DIFF_TICK (disp_tick, tick) < -5000 - || DIFF_TICK (disp_tick, tick) > 5000) - { - printf ("timer %d(%d + %d)\n", timer_data_num, timer_heap[0], - free_timer_list_pos); - disp_tick = tick; - } -#endif + timer_id i; + /// Number of milliseconds until it calls this again + // this says to wait 1 sec if all timers get popped + interval_t nextmin = 1000; - while ((i = top_timer_heap ()) >= 0) + while ((i = top_timer_heap ()) != (timer_id)-1) { + // while the heap is not empty and if (DIFF_TICK (timer_data[i].tick, tick) > 0) { + /// Return the time until the next timer needs to goes off nextmin = DIFF_TICK (timer_data[i].tick, tick); break; } pop_timer_heap (); - timer_data[i].type |= TIMER_REMOVE_HEAP; if (timer_data[i].func) { if (DIFF_TICK (timer_data[i].tick, tick) < -1000) { - // 1秒以上の大幅な遅延が発生しているので、 - // timer処理タイミングを現在値とする事で - // 呼び出し時タイミング(引数のtick)相対で処理してる - // timer関数の次回処理タイミングを遅らせる - timer_data[i].func (i, tick, timer_data[i].id, - timer_data[i].data); + // If we are too far past the requested tick, call with the current tick instead to fix reregistering problems + timer_data[i].func (i, tick, timer_data[i].id, timer_data[i].data); } else { - timer_data[i].func (i, timer_data[i].tick, timer_data[i].id, - timer_data[i].data); + timer_data[i].func (i, timer_data[i].tick, timer_data[i].id, timer_data[i].data); } } - if (timer_data[i].type & TIMER_REMOVE_HEAP) + switch (timer_data[i].type) { - switch (timer_data[i].type & ~TIMER_REMOVE_HEAP) - { - case TIMER_ONCE_AUTODEL: - timer_data[i].type = 0; - if (free_timer_list_pos >= free_timer_list_max) - { - free_timer_list_max += 256; - RECREATE (free_timer_list, int, free_timer_list_max); - memset (free_timer_list + (free_timer_list_max - 256), - 0, 256 * sizeof (free_timer_list[0])); - } - free_timer_list[free_timer_list_pos++] = i; - break; - case TIMER_INTERVAL: - if (DIFF_TICK (timer_data[i].tick, tick) < -1000) - { - timer_data[i].tick = tick + timer_data[i].interval; - } - else - { - timer_data[i].tick += timer_data[i].interval; - } - timer_data[i].type &= ~TIMER_REMOVE_HEAP; - push_timer_heap (i); - break; - } + case TIMER_ONCE_AUTODEL: + timer_data[i].type = 0; + if (free_timer_list_pos >= free_timer_list_max) + { + free_timer_list_max += 256; + RECREATE (free_timer_list, uint32_t, free_timer_list_max); + memset (free_timer_list + (free_timer_list_max - 256), + 0, 256 * sizeof (uint32_t)); + } + free_timer_list[free_timer_list_pos++] = i; + break; + case TIMER_INTERVAL: + if (DIFF_TICK (timer_data[i].tick, tick) < -1000) + { + timer_data[i].tick = tick + timer_data[i].interval; + } + else + { + timer_data[i].tick += timer_data[i].interval; + } + push_timer_heap (i); + break; } } @@ -346,8 +255,3 @@ int do_timer (unsigned int tick) nextmin = 10; return nextmin; } - -void timer_final () -{ - free (timer_data); -} |