From cf9b4b50d677a0846c6213acb6bd58fc6ff0d0bb Mon Sep 17 00:00:00 2001 From: ultramage Date: Sat, 3 Nov 2007 12:35:34 +0000 Subject: Tried to make sense out of timer.c ... and failed git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11647 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/common/timer.c | 150 ++++++++++++++++++++++++++++++---------------------- src/common/timer.h | 31 ++++++----- src/map/chrif.c | 2 +- src/map/mercenary.h | 2 +- src/map/mob.c | 2 +- src/map/mob.h | 6 +-- src/map/pc.h | 4 +- src/map/pet.h | 2 +- 8 files changed, 110 insertions(+), 89 deletions(-) (limited to 'src') diff --git a/src/common/timer.c b/src/common/timer.c index 36087ccb2..a2be88876 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -17,12 +17,8 @@ #include // struct timeval, gettimeofday() #endif -// タイマー間隔の最小値。モンスターの大量召還時、多数のクライアント接続時に -// サーバーが反応しなくなる場合は、TIMER_MIN_INTERVAL を増やしてください。 - -// If the server shows no reaction when processing thousands of monsters -// or connected by many clients, please increase TIMER_MIN_INTERVAL. - +// If the server can't handle processing thousands of monsters +// or many connected clients, please increase TIMER_MIN_INTERVAL. #define TIMER_MIN_INTERVAL 50 // timers @@ -41,16 +37,18 @@ static int timer_heap_num = 0; static int timer_heap_max = 0; static int* timer_heap = NULL; -// for debug +// server startup time +time_t start_time; + + +/*---------------------------- + * Timer debugging + *----------------------------*/ struct timer_func_list { struct timer_func_list* next; TimerFunc func; char* name; -}; -static struct timer_func_list* tfl_root = NULL; - -// server startup time -time_t start_time; +} *tfl_root = NULL; /// Sets the name of a timer function. int add_timer_func_list(TimerFunc func, char* name) @@ -227,71 +225,83 @@ static int acquire_timer(void) return tid; } -int add_timer(unsigned int tick,TimerFunc func, int id, int data) +/// Starts a new timer that is deleted once it expires (single-use). +/// Returns the timer's id. +int add_timer(unsigned int tick, TimerFunc func, int id, int data) { - int tid = acquire_timer(); - - timer_data[tid].tick = tick; - timer_data[tid].func = func; - timer_data[tid].id = id; - timer_data[tid].data = data; - timer_data[tid].type = TIMER_ONCE_AUTODEL; + int tid; + + tid = acquire_timer(); + timer_data[tid].tick = tick; + timer_data[tid].func = func; + timer_data[tid].id = id; + timer_data[tid].data = data; + timer_data[tid].type = TIMER_ONCE_AUTODEL; timer_data[tid].interval = 1000; push_timer_heap(tid); return tid; } +/// Starts a new timer that automatically restarts itself (infinite loop until manually removed). +/// Returns the timer's id, or -1 if it fails. int add_timer_interval(unsigned int tick, TimerFunc func, int id, int data, int interval) { int tid; - if (interval < 1) { - ShowError("add_timer_interval : function %08x(%s) has invalid interval %d!\n", - (int)func, search_timer_func_list(func), interval); + if( interval < 1 ) { + ShowError("add_timer_interval : function %08x(%s) has invalid interval %d!\n", (int)func, search_timer_func_list(func), interval); return -1; } tid = acquire_timer(); - timer_data[tid].tick = tick; - timer_data[tid].func = func; - timer_data[tid].id = id; - timer_data[tid].data = data; - timer_data[tid].type = TIMER_INTERVAL; + timer_data[tid].tick = tick; + timer_data[tid].func = func; + timer_data[tid].id = id; + timer_data[tid].data = data; + timer_data[tid].type = TIMER_INTERVAL; timer_data[tid].interval = interval; push_timer_heap(tid); return tid; } -int delete_timer(int id, TimerFunc func) +/// Retrieves internal timer data +//FIXME: for safety, the return value should be 'const' +struct TimerData* get_timer(int tid) +{ + return &timer_data[tid]; +} + +/// Marks a timer specified by 'id' for immediate deletion once it expires. +/// Param 'func' is used for debug/verification purposes. +/// Returns 0 on success, < 0 on failure. +int delete_timer(int tid, TimerFunc func) { - if (id <= 0 || id >= timer_data_num) { - ShowError("delete_timer error : no such timer %d (%08x(%s))\n", id, (int)func, search_timer_func_list(func)); + if( tid <= 0 || tid >= timer_data_num ) { + ShowError("delete_timer error : no such timer %d (%08x(%s))\n", tid, (int)func, search_timer_func_list(func)); return -1; } - if (timer_data[id].func != func) { - ShowError("delete_timer error : function mismatch %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)); + if( timer_data[tid].func != func ) { + ShowError("delete_timer error : function mismatch %08x(%s) != %08x(%s)\n", (int)timer_data[tid].func, search_timer_func_list(timer_data[tid].func), (int)func, search_timer_func_list(func)); return -2; } - // そのうち消えるにまかせる - timer_data[id].func = NULL; - timer_data[id].type = TIMER_ONCE_AUTODEL; + + timer_data[tid].func = NULL; + timer_data[tid].type = TIMER_ONCE_AUTODEL; return 0; } +/// Adjusts a timer's expiration time. +/// Returns the new tick value, or -1 if it fails. int addtick_timer(int tid, unsigned int tick) { - // Doesn't adjust the timer position. Might be the root of the FIXME in settick_timer. [FlavioJS] - //return timer_data[tid].tick += tick; return settick_timer(tid, timer_data[tid].tick+tick); } -//Sets the tick at which the timer triggers directly (meant as a replacement of delete_timer + add_timer) [Skotlex] -//FIXME: DON'T use this function yet, it is not correctly reorganizing the timer stack causing unexpected problems later on! +/// Modifies a timer's expiration time (an alternative to deleting a timer and starting a new one). +/// Returns the new tick value, or -1 if it fails. int settick_timer(int tid, unsigned int tick) { int old_pos,pos; @@ -305,7 +315,7 @@ int settick_timer(int tid, unsigned int tick) HEAP_SEARCH(old_tick,0,timer_heap_num-1,old_pos); while( timer_heap[old_pos] != tid ) {// skip timers with the same tick - if( DIFF_TICK(old_tick,timer_data[timer_heap[old_pos]].tick) != 0 ) + if( old_tick != timer_data[timer_heap[old_pos]].tick ) { ShowError("settick_timer: no such timer %d (%08x(%s))\n", tid, (int)timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); return -1; @@ -334,14 +344,11 @@ int settick_timer(int tid, unsigned int tick) memmove(&timer_heap[pos+1], &timer_heap[pos], (old_pos-pos)*sizeof(int)); } } + timer_heap[pos] = tid; timer_data[tid].tick = tick; - return tick; -} -struct TimerData* get_timer(int tid) -{ - return &timer_data[tid]; + return tick; } //Correcting the heap when the tick overflows is an idea taken from jA to @@ -367,37 +374,51 @@ static void fix_timer_heap(unsigned int tick) } } +/// Executes all expired timers. +/// Returns the value of the smallest non-expired timer (or 1 second if there aren't any). int do_timer(unsigned int tick) { + int nextmin = 1000; // return value static int fix_heap_flag = 0; //Flag for fixing the stack only once per tick loop. May not be the best way, but it's all I can think of currently :X [Skotlex] - int i, nextmin = 1000; + int i; - if (tick < 0x010000 && fix_heap_flag) + if( tick < 0x010000 && fix_heap_flag ) { fix_timer_heap(tick); fix_heap_flag = 0; } - while(timer_heap_num) { - i = timer_heap[timer_heap_num - 1]; // next shorter element - if ((nextmin = DIFF_TICK(timer_data[i].tick, tick)) > 0) - break; + // process all timers one by one + while( timer_heap_num ) + { + i = timer_heap[timer_heap_num - 1]; // last element in heap (=>smallest) + if( (nextmin = DIFF_TICK(timer_data[i].tick, tick)) > 0 ) + break; // no more expired timers to process --timer_heap_num; // suppress the actual element from the table + + // mark timer as 'to be removed' timer_data[i].type |= TIMER_REMOVE_HEAP; - if (timer_data[i].func) { - if (nextmin < -1000) { + + if( timer_data[i].func ) + { + if( nextmin < -1000 ) // 1秒以上の大幅な遅延が発生しているので、 // timer処理タイミングを現在値とする事で // 呼び出し時タイミング(引数のtick)相対で処理してる // timer関数の次回処理タイミングを遅らせる timer_data[i].func(i, tick, timer_data[i].id, timer_data[i].data); - } else { + else 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 & ~TIMER_REMOVE_HEAP) { + + // in the case the function didn't change anything... + if( timer_data[i].type & TIMER_REMOVE_HEAP ) + { + timer_data[i].type &= ~TIMER_REMOVE_HEAP; + + switch( timer_data[i].type ) + { case TIMER_ONCE_AUTODEL: timer_data[i].type = 0; if (free_timer_list_pos >= free_timer_list_max) { @@ -406,7 +427,7 @@ int do_timer(unsigned int tick) memset(free_timer_list + (free_timer_list_max - 256), 0, 256 * sizeof(int)); } free_timer_list[free_timer_list_pos++] = i; - break; + break; case TIMER_INTERVAL: if (DIFF_TICK(timer_data[i].tick , tick) < -1000) { timer_data[i].tick = tick + timer_data[i].interval; @@ -415,16 +436,17 @@ int do_timer(unsigned int tick) } timer_data[i].type &= ~TIMER_REMOVE_HEAP; push_timer_heap(i); - break; + break; } } } - if (nextmin < TIMER_MIN_INTERVAL) + if( nextmin < TIMER_MIN_INTERVAL ) nextmin = TIMER_MIN_INTERVAL; - if (UINT_MAX - nextmin < tick) //Tick will loop, rearrange the heap on the next iteration. + if( UINT_MAX - nextmin < tick ) //Tick will loop, rearrange the heap on the next iteration. fix_heap_flag = 1; + return nextmin; } diff --git a/src/common/timer.h b/src/common/timer.h index e007e9611..4fa4a3c2d 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -8,28 +8,29 @@ #include "../common/cbasetypes.h" #endif -#define BASE_TICK 5 +#define DIFF_TICK(a,b) ((int)((a)-(b))) + +#define INVALID_TIMER -1 +// timer flags #define TIMER_ONCE_AUTODEL 0x01 #define TIMER_INTERVAL 0x02 #define TIMER_REMOVE_HEAP 0x10 -#define DIFF_TICK(a,b) ((int)((a)-(b))) - -#define INVALID_TIMER -1 - // Struct declaration -typedef int (*TimerFunc)(int,unsigned int,int,int); +typedef int (*TimerFunc)(int tid, unsigned int tick, int id, int data); struct TimerData { unsigned int tick; TimerFunc func; - int id; - int data; int type; int interval; int heap_pos; + + // general-purpose storage + int id; + int data; }; // Function prototype declaration @@ -37,21 +38,19 @@ struct TimerData { unsigned int gettick(void); unsigned int gettick_nocache(void); -int add_timer(unsigned int,TimerFunc f,int,int); +int add_timer(unsigned int tick, TimerFunc func, int id, int data); int add_timer_interval(unsigned int tick, TimerFunc func, int id, int data, int interval); -int delete_timer(int,TimerFunc f); - -int addtick_timer(int tid,unsigned int tick); -int settick_timer(int tid,unsigned int tick); -struct TimerData *get_timer(int tid); +struct TimerData* get_timer(int tid); +int delete_timer(int tid, TimerFunc func); -int do_timer(unsigned int tick); +int addtick_timer(int tid, unsigned int tick); +int settick_timer(int tid, unsigned int tick); int add_timer_func_list(TimerFunc func, char* name); -char* search_timer_func_list(TimerFunc f); unsigned long get_uptime(void); +int do_timer(); void timer_init(void); void timer_final(void); diff --git a/src/map/chrif.c b/src/map/chrif.c index a29987a6d..0ea1e06a9 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -1019,7 +1019,7 @@ int chrif_save_scdata(struct map_session_data *sd) int i, count=0; unsigned int tick; struct status_change_data data; - struct TimerData *timer; + const struct TimerData *timer; if (sd->state.finalsave) //Character was already saved? return -1; diff --git a/src/map/mercenary.h b/src/map/mercenary.h index 06378d8f9..ba5db0ba8 100644 --- a/src/map/mercenary.h +++ b/src/map/mercenary.h @@ -54,7 +54,7 @@ int merc_hom_food(struct map_session_data *sd, struct homun_data *hd); int merc_hom_hungry_timer_delete(struct homun_data *hd); int merc_hom_change_name(struct map_session_data *sd,char *name); int merc_hom_change_name_ack(struct map_session_data *sd, char* name, int flag); -#define merc_stop_walking(hd, type) { if((hd)->ud.walktimer != -1) unit_stop_walking(&(hd)->bl, type); } +#define merc_stop_walking(hd, type) unit_stop_walking(&(hd)->bl, type) #define merc_stop_attack(hd) { if((hd)->ud.attacktimer != -1) unit_stop_attack(&(hd)->bl); hd->ud.target = 0; } int merc_hom_increase_intimacy(struct homun_data * hd, unsigned int value); int merc_hom_decrease_intimacy(struct homun_data * hd, unsigned int value); diff --git a/src/map/mob.c b/src/map/mob.c index 88fad163f..ed25d4198 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -995,7 +995,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick) * when trying to pick new targets when the current chosen target is * unreachable. *------------------------------------------*/ -int mob_unlocktarget(struct mob_data *md,int tick) +int mob_unlocktarget(struct mob_data *md, unsigned int tick) { nullpo_retr(0, md); diff --git a/src/map/mob.h b/src/map/mob.h index 5d2296d47..a731df847 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -166,7 +166,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap); //Change Guardia int mob_randomwalk(struct mob_data *md,unsigned int tick); int mob_warpchase(struct mob_data *md, struct block_list *target); int mob_target(struct mob_data *md,struct block_list *bl,int dist); -int mob_unlocktarget(struct mob_data *md,int tick); +int mob_unlocktarget(struct mob_data *md, unsigned int tick); struct mob_data* mob_spawn_dataset(struct spawn_data *data); int mob_spawn(struct mob_data *md); int mob_setdelayspawn(struct mob_data *md); @@ -177,8 +177,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type); void mob_revive(struct mob_data *md, unsigned int hp); void mob_heal(struct mob_data *md,unsigned int heal); -#define mob_stop_walking(md, type) { if (md->ud.walktimer != -1) unit_stop_walking(&md->bl, type); } -#define mob_stop_attack(md) { if (md->ud.attacktimer != -1) unit_stop_attack(&md->bl); } +#define mob_stop_walking(md, type) unit_stop_walking(&(md)->bl, type) +#define mob_stop_attack(md) { if((md)->ud.attacktimer != -1) unit_stop_attack(&(md)->bl); } void mob_clear_spawninfo(); int do_init_mob(void); diff --git a/src/map/pc.h b/src/map/pc.h index 59bfbea53..de220d54c 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -110,8 +110,8 @@ enum { #define pc_is90overweight(sd) ( (sd)->weight*10 >= (sd)->max_weight*9 ) #define pc_maxparameter(sd) ( (sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter ) -#define pc_stop_attack(sd) { if( (sd)->ud.attacktimer != -1 ) { unit_stop_attack(&(sd)->bl); (sd)->ud.target = 0; } } -#define pc_stop_walking(sd, type) { if( (sd)->ud.walktimer != -1 ) unit_stop_walking(&(sd)->bl, type); } +#define pc_stop_walking(sd, type) unit_stop_walking(&(sd)->bl, type) +#define pc_stop_attack(sd) { if((sd)->ud.attacktimer != -1) { unit_stop_attack(&(sd)->bl); (sd)->ud.target = 0; } } //Weapon check considering dual wielding. #define pc_check_weapontype(sd, type) ((type)&((sd)->status.weapon < MAX_WEAPON_TYPE? \ diff --git a/src/map/pet.h b/src/map/pet.h index c1c27b105..835d8a04d 100644 --- a/src/map/pet.h +++ b/src/map/pet.h @@ -58,7 +58,7 @@ int pet_skill_bonus_timer(int tid,unsigned int tick,int id,int data); // [Valari int pet_recovery_timer(int tid,unsigned int tick,int id,int data); // [Valaris] int pet_heal_timer(int tid,unsigned int tick,int id,int data); // [Valaris] -#define pet_stop_walking(pd, type) { if((pd)->ud.walktimer != -1) unit_stop_walking(&(pd)->bl, type); } +#define pet_stop_walking(pd, type) unit_stop_walking(&(pd)->bl, type) #define pet_stop_attack(pd) { if((pd)->ud.attacktimer != -1) unit_stop_attack(&(pd)->bl); } int read_petdb(void); -- cgit v1.2.3-60-g2f50