Przeglądaj źródła

Tried to make sense out of timer.c ... and failed

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11647 54d463be-8e91-2dee-dedb-b68131a5f0ec
ultramage 17 lat temu
rodzic
commit
59b9654397
8 zmienionych plików z 110 dodań i 89 usunięć
  1. 86 64
      src/common/timer.c
  2. 15 16
      src/common/timer.h
  3. 1 1
      src/map/chrif.c
  4. 1 1
      src/map/mercenary.h
  5. 1 1
      src/map/mob.c
  6. 3 3
      src/map/mob.h
  7. 2 2
      src/map/pc.h
  8. 1 1
      src/map/pet.h

+ 86 - 64
src/common/timer.c

@@ -17,12 +17,8 @@
 #include <sys/time.h> // 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;
 }
 

+ 15 - 16
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);
 

+ 1 - 1
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;

+ 1 - 1
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);

+ 1 - 1
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);
 

+ 3 - 3
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);

+ 2 - 2
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? \

+ 1 - 1
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);