From a2306446c86b3333e69b082e41ae76ba71a42d9d Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Thu, 24 Mar 2011 13:57:13 -0700 Subject: Optimize common objects, and adjust other objects accordingly. Major changes still need to be made to each of the servers. --- src/common/timer.c | 328 +++++++++++++++++++---------------------------------- 1 file changed, 118 insertions(+), 210 deletions(-) (limited to 'src/common/timer.c') diff --git a/src/common/timer.c b/src/common/timer.c index fca6f42..bf21c8e 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -1,184 +1,127 @@ -// $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 #include #include #include -#ifdef LCCWIN32 -#include -#else #include #include -#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 = 256; +/// 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) + if (timer_heap == NULL) { - 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; + CREATE (timer_heap, timer_id, timer_heap_max); } - +// timer_heap[0] is the greatest index into the heap, which increases timer_heap[0]++; + if (timer_heap[0] >= timer_heap_max) + { + timer_heap_max += 256; + RECREATE (timer_heap, timer_id, timer_heap_max); + memset (timer_heap + (timer_heap_max - 256), 0, 4 * 256); + } - 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) + 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 +130,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 +146,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, interdb_val_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, interdb_val_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) +interdb_val_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 + interdb_val_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 (timer_id)); + } + 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 +259,3 @@ int do_timer (unsigned int tick) nextmin = 10; return nextmin; } - -void timer_final () -{ - free (timer_data); -} -- cgit v1.2.3-70-g09d2 From ef740ac0479a5a4f4240db63b84531599a26a983 Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Thu, 24 Mar 2011 20:24:47 -0700 Subject: Fix timer bugs in previous version The most visible effect of this was that the map-server would never actually connect with the char-server --- src/char/char.c | 1 - src/common/timer.c | 20 ++++++++------------ src/common/timer.h | 19 ++++++------------- src/map/map.c | 1 - src/map/npc.c | 2 ++ 5 files changed, 16 insertions(+), 27 deletions(-) (limited to 'src/common/timer.c') diff --git a/src/char/char.c b/src/char/char.c index d340f1d..dc77c31 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -2337,7 +2337,6 @@ void parse_tologin (int fd) //-------------------------------- // Map-server anti-freeze system //-------------------------------- -typedef void (*timer_func) (timer_id, tick_t, custom_id_t, custom_data_t); void map_anti_freeze_system (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) { int i; diff --git a/src/common/timer.c b/src/common/timer.c index bf21c8e..915aeb4 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -20,7 +20,7 @@ static uint32_t free_timer_list_max, free_timer_list_pos; // 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 = 256; +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; @@ -48,19 +48,14 @@ uint32_t gettick (void) static void push_timer_heap (timer_id index) { - if (timer_heap == NULL) + if (timer_heap == NULL || timer_heap[0] + 1 >= timer_heap_max) { timer_heap_max += 256; - CREATE (timer_heap, timer_id, timer_heap_max); + RECREATE (timer_heap, int, timer_heap_max); + 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]++; - if (timer_heap[0] >= timer_heap_max) - { - timer_heap_max += 256; - RECREATE (timer_heap, timer_id, timer_heap_max); - memset (timer_heap + (timer_heap_max - 256), 0, 4 * 256); - } timer_id h = timer_heap[0]-1, i = (h - 1) / 2; while (h) @@ -104,7 +99,8 @@ static timer_id pop_timer_heap () uint32_t i = (h - 1) / 2; while (h) { - if (DIFF_TICK(timer_data[timer_heap[i + 1]].tick, timer_data[last].tick) <= 0) + 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; @@ -152,7 +148,7 @@ timer_id add_timer (tick_t tick, timer_func func, custom_id_t id, custom_data_t } timer_data[i].tick = tick; timer_data[i].func = func; - timer_data[i].id = id; + timer_data[i].id = id; timer_data[i].data = data; timer_data[i].type = TIMER_ONCE_AUTODEL; timer_data[i].interval = 1000; @@ -237,7 +233,7 @@ interdb_val_t do_timer (tick_t tick) 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 (timer_id)); + 0, 256 * sizeof (uint32_t)); } free_timer_list[free_timer_list_pos++] = i; break; diff --git a/src/common/timer.h b/src/common/timer.h index 4fa5db8..2a38e04 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -3,7 +3,8 @@ # include "sanity.h" -enum TIMER_TYPE { +enum TIMER_TYPE +{ TIMER_ONCE_AUTODEL = 1, TIMER_INTERVAL = 2, }; @@ -32,7 +33,7 @@ struct TimerData /// Type of timer - 0 initially enum TIMER_TYPE type; /// Repeat rate - uint32_t interval; + interdb_val_t interval; }; /// Server time, in milliseconds, since the epoch, @@ -44,24 +45,16 @@ tick_t gettick_nocache (void); /// the next 255 times tick_t gettick (void); -timer_id add_timer (tick_t tick, timer_func func, custom_id_t id, - custom_data_t data); -timer_id add_timer_interval (tick_t tick, timer_func func, custom_id_t id, - custom_data_t data, interdb_val_t interval); +timer_id add_timer (tick_t, timer_func, custom_id_t, custom_data_t); +timer_id add_timer_interval (tick_t, timer_func, custom_id_t, custom_data_t, interdb_val_t); void delete_timer (timer_id, timer_func); -tick_t addtick_timer (timer_id tid, interdb_val_t tick); +tick_t addtick_timer (timer_id, interdb_val_t); struct TimerData *get_timer (timer_id tid); /// Do all timers scheduled before tick, and return the number of milliseconds until the next timer happens interdb_val_t do_timer (tick_t tick); -// debugging -static void add_timer_func_list (timer_func, char *) __attribute__((deprecated)); -static inline void add_timer_func_list (timer_func UNUSED, char *UNUSED) {} -// used to just call free(), which doesn't matter when we're exiting -static void timer_final () __attribute__((deprecated)); -static inline void timer_final() {}; #endif // TIMER_H diff --git a/src/map/map.c b/src/map/map.c index 8261e49..7730b94 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -2113,7 +2113,6 @@ void do_final (void) delete_session (i); map_removenpc (); - timer_final (); numdb_final (id_db, NULL); strdb_final (map_db, NULL); diff --git a/src/map/npc.c b/src/map/npc.c index 54b13d8..85ac6e9 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -2236,6 +2236,8 @@ int do_final_npc (void) if (ev_db) strdb_final (ev_db, ev_db_final); + if (npcname_db) + strdb_final (npcname_db, NULL); for (i = START_NPC_NUM; i < npc_id; i++) { -- cgit v1.2.3-70-g09d2 From deec3c27f91a97d35aaf912422d1249ec609da05 Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Thu, 24 Mar 2011 22:57:06 -0700 Subject: Fix accidentally-named interdb_val_t --- src/common/timer.c | 8 ++++---- src/common/timer.h | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/common/timer.c') diff --git a/src/common/timer.c b/src/common/timer.c index 915aeb4..f4be19b 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -159,7 +159,7 @@ timer_id add_timer (tick_t tick, timer_func func, custom_id_t id, custom_data_t } timer_id add_timer_interval (tick_t tick, timer_func func, custom_id_t id, - custom_data_t data, interdb_val_t interval) + custom_data_t data, interval_t interval) { timer_id tid = add_timer (tick, func, id, data); timer_data[tid].type = TIMER_INTERVAL; @@ -185,7 +185,7 @@ void delete_timer (timer_id id, timer_func func) timer_data[id].tick -= 60 * 60 * 1000; } -tick_t addtick_timer (timer_id tid, interdb_val_t tick) +tick_t addtick_timer (timer_id tid, interval_t tick) { return timer_data[tid].tick += tick; } @@ -195,12 +195,12 @@ struct TimerData *get_timer (timer_id tid) return &timer_data[tid]; } -interdb_val_t do_timer (tick_t tick) +interval_t do_timer (tick_t tick) { timer_id i; /// Number of milliseconds until it calls this again // this says to wait 1 sec if all timers get popped - interdb_val_t nextmin = 1000; + interval_t nextmin = 1000; while ((i = top_timer_heap ()) != (timer_id)-1) { diff --git a/src/common/timer.h b/src/common/timer.h index 2a38e04..e363a56 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -13,7 +13,7 @@ enum TIMER_TYPE // TODO replace with signed 64-bit to make code more clear and protect from the future typedef uint32_t tick_t; -typedef uint32_t interdb_val_t; +typedef uint32_t interval_t; typedef uint32_t timer_id; // BUG: pointers are stored in here typedef int32_t custom_id_t; @@ -33,7 +33,7 @@ struct TimerData /// Type of timer - 0 initially enum TIMER_TYPE type; /// Repeat rate - interdb_val_t interval; + interval_t interval; }; /// Server time, in milliseconds, since the epoch, @@ -46,14 +46,14 @@ tick_t gettick_nocache (void); tick_t gettick (void); timer_id add_timer (tick_t, timer_func, custom_id_t, custom_data_t); -timer_id add_timer_interval (tick_t, timer_func, custom_id_t, custom_data_t, interdb_val_t); +timer_id add_timer_interval (tick_t, timer_func, custom_id_t, custom_data_t, interval_t); void delete_timer (timer_id, timer_func); -tick_t addtick_timer (timer_id, interdb_val_t); +tick_t addtick_timer (timer_id, interval_t); struct TimerData *get_timer (timer_id tid); /// Do all timers scheduled before tick, and return the number of milliseconds until the next timer happens -interdb_val_t do_timer (tick_t tick); +interval_t do_timer (tick_t tick); -- cgit v1.2.3-70-g09d2