timer.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/cbasetypes.h"
  4. #include "../common/malloc.h"
  5. #include "../common/showmsg.h"
  6. #include "timer.h"
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <time.h>
  11. #ifdef WIN32
  12. #define WIN32_LEAN_AND_MEAN
  13. #include <windows.h> // GetTickCount()
  14. #else
  15. #include <unistd.h>
  16. #include <sys/time.h> // struct timeval, gettimeofday()
  17. #endif
  18. // If the server can't handle processing thousands of monsters
  19. // or many connected clients, please increase TIMER_MIN_INTERVAL.
  20. #define TIMER_MIN_INTERVAL 50
  21. #define TIMER_MAX_INTERVAL 60000
  22. // timers (array)
  23. static struct TimerData* timer_data = NULL;
  24. static int timer_data_max = 0;
  25. static int timer_data_num = 0;
  26. // free timers (array)
  27. static int* free_timer_list = NULL;
  28. static int free_timer_list_max = 0;
  29. static int free_timer_list_num = 0;
  30. // timer heap (binary min heap)
  31. static int* timer_heap = NULL;
  32. static int timer_heap_max = 0;
  33. static int timer_heap_num = 0;
  34. // server startup time
  35. time_t start_time;
  36. /*----------------------------
  37. * Timer debugging
  38. *----------------------------*/
  39. struct timer_func_list {
  40. struct timer_func_list* next;
  41. TimerFunc func;
  42. char* name;
  43. } *tfl_root = NULL;
  44. /// Sets the name of a timer function.
  45. int add_timer_func_list(TimerFunc func, char* name)
  46. {
  47. struct timer_func_list* tfl;
  48. if (name) {
  49. for( tfl=tfl_root; tfl != NULL; tfl=tfl->next )
  50. {// check suspicious cases
  51. if( func == tfl->func )
  52. ShowWarning("add_timer_func_list: duplicating function %08x(%s) as %s.\n",(int)tfl->func,tfl->name,name);
  53. else if( strcmp(name,tfl->name) == 0 )
  54. ShowWarning("add_timer_func_list: function %08X has the same name as %08X(%s)\n",(int)func,(int)tfl->func,tfl->name);
  55. }
  56. CREATE(tfl,struct timer_func_list,1);
  57. tfl->next = tfl_root;
  58. tfl->func = func;
  59. tfl->name = aStrdup(name);
  60. tfl_root = tfl;
  61. }
  62. return 0;
  63. }
  64. /// Returns the name of the timer function.
  65. char* search_timer_func_list(TimerFunc func)
  66. {
  67. struct timer_func_list* tfl;
  68. for( tfl=tfl_root; tfl != NULL; tfl=tfl->next )
  69. if (func == tfl->func)
  70. return tfl->name;
  71. return "unknown timer function";
  72. }
  73. /*----------------------------
  74. * Get tick time
  75. *----------------------------*/
  76. /// platform-abstracted tick retrieval
  77. static unsigned int tick(void)
  78. {
  79. #if defined(WIN32)
  80. return GetTickCount();
  81. #elif (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) /* posix compliant */) || (defined(__FreeBSD_cc_version) && __FreeBSD_cc_version >= 500005 /* FreeBSD >= 5.1.0 */)
  82. struct timespec tval;
  83. clock_gettime(CLOCK_MONOTONIC, &tval);
  84. return tval.tv_sec * 1000 + tval.tv_nsec / 1000000;
  85. #else
  86. struct timeval tval;
  87. gettimeofday(&tval, NULL);
  88. return tval.tv_sec * 1000 + tval.tv_usec / 1000;
  89. #endif
  90. }
  91. //////////////////////////////////////////////////////////////////////////
  92. #if defined(TICK_CACHE) && TICK_CACHE > 1
  93. //////////////////////////////////////////////////////////////////////////
  94. // tick is cached for TICK_CACHE calls
  95. static unsigned int gettick_cache;
  96. static int gettick_count = 1;
  97. unsigned int gettick_nocache(void)
  98. {
  99. gettick_count = TICK_CACHE;
  100. gettick_cache = tick();
  101. return gettick_cache;
  102. }
  103. unsigned int gettick(void)
  104. {
  105. return ( --gettick_count == 0 ) ? gettick_nocache() : gettick_cache;
  106. }
  107. //////////////////////////////
  108. #else
  109. //////////////////////////////
  110. // tick doesn't get cached
  111. unsigned int gettick_nocache(void)
  112. {
  113. return tick();
  114. }
  115. unsigned int gettick(void)
  116. {
  117. return tick();
  118. }
  119. //////////////////////////////////////////////////////////////////////////
  120. #endif
  121. //////////////////////////////////////////////////////////////////////////
  122. /*======================================
  123. * CORE : Timer Heap
  124. *--------------------------------------*/
  125. #define BHEAP_PARENT(pos) ( ((pos) - 1)/2 )
  126. #define BHEAP_LEFT(pos) ( (pos)*2 + 1 )
  127. #define BHEAP_RIGHT(pos) ( (pos)*2 + 2 )
  128. /// Adds a timer to the timer_heap
  129. static
  130. void push_timer_heap(int tid)
  131. {
  132. int pos;
  133. // check available space
  134. if( timer_heap_num >= timer_heap_max )
  135. {
  136. timer_heap_max += 256;
  137. if( timer_heap )
  138. RECREATE(timer_heap, int, timer_heap_max);
  139. else
  140. CREATE(timer_heap, int, timer_heap_max);
  141. memset(timer_heap + (timer_heap_max - 256), 0, sizeof(int)*256);
  142. }
  143. // add the timer
  144. pos = timer_heap_num++;
  145. timer_heap[pos] = tid;
  146. // restore binary heap properties
  147. while( pos > 0 )
  148. {
  149. int parent = BHEAP_PARENT(pos);
  150. if( DIFF_TICK(timer_data[tid].tick, timer_data[timer_heap[parent]].tick) > 0 )
  151. break;// done
  152. swap(timer_heap[pos], timer_heap[parent]);
  153. pos = parent;
  154. }
  155. }
  156. /// Removes a timer from the timer_heap
  157. static
  158. bool pop_timer_heap(int tid)
  159. {
  160. int pos;
  161. // find the timer
  162. pos = 0;
  163. while( pos < timer_heap_num )
  164. {// search in the order current-left-right
  165. int left = BHEAP_LEFT(pos);
  166. int right = BHEAP_RIGHT(pos);
  167. if( timer_heap[pos] == tid )
  168. break;// found the timer
  169. if( left < timer_heap_num && DIFF_TICK(timer_data[tid].tick, timer_data[timer_heap[left]].tick) >= 0 )
  170. {// try left child
  171. pos = left;
  172. continue;
  173. }
  174. if( right < timer_heap_num && DIFF_TICK(timer_data[tid].tick, timer_data[timer_heap[right]].tick) >= 0 )
  175. {// try right child
  176. pos = right;
  177. continue;
  178. }
  179. // back and right
  180. while( true )
  181. {
  182. int parent;
  183. if( pos == 0 )
  184. return false;// not found
  185. parent = BHEAP_PARENT(pos);
  186. right = BHEAP_RIGHT(parent);
  187. if( pos != right && right < timer_heap_num && DIFF_TICK(timer_data[tid].tick, timer_data[timer_heap[right]].tick) >= 0 )
  188. break;// try this right
  189. pos = parent;
  190. }
  191. pos = right;
  192. }
  193. if( pos >= timer_heap_num )
  194. return false;// not found
  195. // remove timer
  196. timer_heap[pos] = timer_heap[--timer_heap_num];
  197. // restore binary heap properties
  198. while( pos < timer_heap_num )
  199. {
  200. int left = BHEAP_LEFT(pos);
  201. int right = BHEAP_RIGHT(pos);
  202. if( left < timer_heap_num && DIFF_TICK(timer_data[timer_heap[pos]].tick, timer_data[timer_heap[left]].tick) > 0 )
  203. {
  204. if( right < timer_heap_num && DIFF_TICK(timer_data[timer_heap[left]].tick, timer_data[timer_heap[right]].tick) > 0 )
  205. {
  206. swap(timer_heap[pos], timer_heap[right]);
  207. pos = right;
  208. }
  209. else
  210. {
  211. swap(timer_heap[pos], timer_heap[left]);
  212. pos = left;
  213. }
  214. }
  215. else if( right < timer_heap_num && DIFF_TICK(timer_data[timer_heap[pos]].tick, timer_data[timer_heap[right]].tick) > 0 )
  216. {
  217. swap(timer_heap[pos], timer_heap[right]);
  218. pos = right;
  219. }
  220. else
  221. {
  222. break;// done
  223. }
  224. }
  225. return true;
  226. }
  227. /*==========================
  228. * Timer Management
  229. *--------------------------*/
  230. // diff_tick limits (2*24*60*60*1000 is 2 days ; 2*60*60*1000 is 2 hours)
  231. #define FUTURE_DIFF_TICK ( INT_MIN + 2*24*60*60*1000 )
  232. #define MAX_DIFF_TICK ( INT_MAX - 2*60*60*1000 )
  233. #define MIN_DIFF_TICK ( -2*60*60*1000 )
  234. #define PAST_DIFF_TICK ( -2*24*60*60*1000 )
  235. /// Adjusts the tick value to a valid tick_diff range.
  236. /// Returns false if the tick is invalid.
  237. static
  238. bool adjust_tick(unsigned int* tick)
  239. {
  240. int diff;
  241. if( tick == NULL )
  242. return false;
  243. diff = DIFF_TICK(*tick, gettick());
  244. if( diff <= FUTURE_DIFF_TICK || diff > MAX_DIFF_TICK )
  245. {
  246. ShowWarning("adjust_tick: tick diff too far in the future %d, adjusting to the maximum %d\n", diff, MAX_DIFF_TICK);
  247. *tick -= (diff - MAX_DIFF_TICK);
  248. }
  249. else if( diff < PAST_DIFF_TICK )
  250. {
  251. return false;
  252. }
  253. else if( diff < MIN_DIFF_TICK )
  254. {
  255. ShowWarning("adjust_tick: tick diff too far in the past %d, adjusting to the minimm %d\n", diff, MIN_DIFF_TICK);
  256. *tick += (diff - MAX_DIFF_TICK);
  257. }
  258. return true;
  259. }
  260. /// Releases a timer.
  261. static
  262. void release_timer(int tid)
  263. {
  264. if( timer_data[tid].type == 0 )
  265. return;// already released
  266. memset(&timer_data[tid], 0, sizeof(struct TimerData));
  267. if( free_timer_list_num >= free_timer_list_max )
  268. {
  269. free_timer_list_max += 256;
  270. if( free_timer_list )
  271. RECREATE(free_timer_list, int, free_timer_list_max);
  272. else
  273. CREATE(free_timer_list, int, free_timer_list_max);
  274. memset(free_timer_list + (free_timer_list_max - 256), 0, sizeof(int)*256);
  275. }
  276. free_timer_list[free_timer_list_num++] = tid;
  277. }
  278. /// Returns a free timer id.
  279. static int acquire_timer(void)
  280. {
  281. int tid;
  282. // select a free timer
  283. tid = timer_data_num;
  284. while( free_timer_list_num )
  285. {
  286. int pos = --free_timer_list_num;
  287. if( free_timer_list[pos] < timer_data_num )
  288. {
  289. tid = free_timer_list[pos];
  290. break;
  291. }
  292. }
  293. // check available space
  294. if( tid >= timer_data_max )
  295. {
  296. timer_data_max += 256;
  297. if( timer_data )
  298. RECREATE(timer_data, struct TimerData, timer_data_max);
  299. else
  300. CREATE(timer_data, struct TimerData, timer_data_max);
  301. memset(timer_data + (timer_data_max - 256), 0, sizeof(struct TimerData)*256);
  302. }
  303. if( tid >= timer_data_num )
  304. timer_data_num = tid + 1;
  305. return tid;
  306. }
  307. /// Starts a new timer that is deleted once it expires (single-use).
  308. /// Returns the timer's id.
  309. int add_timer(unsigned int tick, TimerFunc func, int id, intptr data)
  310. {
  311. int tid;
  312. if( !adjust_tick(&tick) )
  313. {
  314. ShowError("add_timer: tick out of range (tick=%u %08x[%s] id=%d data=%d diff_tick=%d)\n", tick, (int)func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick()));
  315. return INVALID_TIMER;
  316. }
  317. tid = acquire_timer();
  318. timer_data[tid].tick = tick;
  319. timer_data[tid].func = func;
  320. timer_data[tid].id = id;
  321. timer_data[tid].data = data;
  322. timer_data[tid].type = TIMER_ONCE_AUTODEL;
  323. timer_data[tid].interval = 1000;
  324. push_timer_heap(tid);
  325. return tid;
  326. }
  327. /// Starts a new timer that automatically restarts itself (infinite loop until manually removed).
  328. /// Returns the timer's id, or -1 if it fails.
  329. int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr data, int interval)
  330. {
  331. int tid;
  332. if( interval < 1 )
  333. {
  334. ShowError("add_timer_interval: invalid interval (tick=%u %08x[%s] id=%d data=%d diff_tick=%d)\n", tick, (int)func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick()));
  335. return INVALID_TIMER;
  336. }
  337. if( !adjust_tick(&tick) )
  338. {
  339. ShowError("add_timer_interval: tick out of range (tick=%u %08x[%s] id=%d data=%d diff_tick=%d)\n", tick, (int)func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick()));
  340. return INVALID_TIMER;
  341. }
  342. tid = acquire_timer();
  343. timer_data[tid].tick = tick;
  344. timer_data[tid].func = func;
  345. timer_data[tid].id = id;
  346. timer_data[tid].data = data;
  347. timer_data[tid].type = TIMER_INTERVAL;
  348. timer_data[tid].interval = interval;
  349. push_timer_heap(tid);
  350. return tid;
  351. }
  352. /// Retrieves internal timer data
  353. const struct TimerData* get_timer(int tid)
  354. {
  355. if( tid >= 0 && tid < timer_data_num && timer_data[tid].type != 0 )
  356. return &timer_data[tid];
  357. return NULL;
  358. }
  359. /// Marks a timer specified by 'id' for immediate deletion once it expires.
  360. /// Param 'func' is used for debug/verification purposes.
  361. /// Returns 0 on success, < 0 on failure.
  362. int delete_timer(int tid, TimerFunc func)
  363. {
  364. if( tid < 0 || tid >= timer_data_num || timer_data[tid].type == 0 )
  365. {
  366. ShowError("delete_timer error : no such timer %d (%08x(%s))\n", tid, (int)func, search_timer_func_list(func));
  367. return -1;
  368. }
  369. if( timer_data[tid].func != func )
  370. {
  371. 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));
  372. return -2;
  373. }
  374. if( timer_data[tid].type&TIMER_REMOVE_HEAP )
  375. // timer func being executed, make sure it's marked for removal when it ends
  376. timer_data[tid].type = TIMER_FORCE_REMOVE|TIMER_REMOVE_HEAP;
  377. else if( pop_timer_heap(tid) )
  378. release_timer(tid);
  379. return 0;
  380. }
  381. /// Adjusts a timer's expiration time.
  382. /// Returns the new tick value, or -1 if it fails.
  383. int addtick_timer(int tid, unsigned int tick)
  384. {
  385. return settick_timer(tid, timer_data[tid].tick+tick);
  386. }
  387. /// Modifies a timer's expiration time (an alternative to deleting a timer and starting a new one).
  388. /// Returns the new tick value, or -1 if it fails.
  389. int settick_timer(int tid, unsigned int tick)
  390. {
  391. if( tid < 0 || tid >= timer_data_num || timer_data[tid].type == 0 )
  392. {
  393. ShowError("settick_timer error : no such timer %d\n", tid);
  394. return -1;
  395. }
  396. if( timer_data[tid].tick == tick )
  397. return tick;
  398. if( !adjust_tick(&tick) )
  399. {
  400. ShowError("settick_timer: tick out of range, leaving timer unmodified (tid=%d tick=%u %08x[%s] diff_tick=%d)\n", tid, tick, (int)timer_data[tid].func, search_timer_func_list(timer_data[tid].func), DIFF_TICK(tick, gettick()));
  401. return -1;
  402. }
  403. pop_timer_heap(tid);
  404. if( tick == -1 )
  405. tick = 0;// -1 is reserved for error
  406. timer_data[tid].type &= ~TIMER_REMOVE_HEAP;
  407. timer_data[tid].tick = tick;
  408. push_timer_heap(tid);
  409. return tick;
  410. }
  411. /// Executes all expired timers.
  412. /// Returns the value of the smallest non-expired timer (or 1 second if there aren't any).
  413. int do_timer(unsigned int tick)
  414. {
  415. int diff = 1000; // return value
  416. // process all timers one by one
  417. while( timer_heap_num )
  418. {
  419. int tid = timer_heap[0]; // first element in heap (=>smallest)
  420. diff = DIFF_TICK(timer_data[tid].tick, tick);
  421. if( diff > 0 )
  422. break; // no more expired timers to process
  423. pop_timer_heap(tid);
  424. // mark timer as 'to be removed'
  425. timer_data[tid].type |= TIMER_REMOVE_HEAP;
  426. if( timer_data[tid].func )
  427. {
  428. if( diff < -1000 )
  429. // 1秒以上の大幅な遅延が発生しているので、
  430. // timer処理タイミングを現在値とする事で
  431. // 呼び出し時タイミング(引数のtick)相対で処理してる
  432. // timer関数の次回処理タイミングを遅らせる
  433. timer_data[tid].func(tid, tick, timer_data[tid].id, timer_data[tid].data);
  434. else
  435. timer_data[tid].func(tid, timer_data[tid].tick, timer_data[tid].id, timer_data[tid].data);
  436. }
  437. // in the case the function didn't change anything...
  438. if( timer_data[tid].type & TIMER_REMOVE_HEAP || timer_data[tid].type == TIMER_FORCE_REMOVE )
  439. {
  440. timer_data[tid].type &= ~TIMER_REMOVE_HEAP;
  441. switch( timer_data[tid].type )
  442. {
  443. case TIMER_FORCE_REMOVE:
  444. case TIMER_ONCE_AUTODEL:
  445. release_timer(tid);
  446. break;
  447. case TIMER_INTERVAL:
  448. if( DIFF_TICK(timer_data[tid].tick, tick) < -1000 )
  449. timer_data[tid].tick = tick + timer_data[tid].interval;
  450. else
  451. timer_data[tid].tick += timer_data[tid].interval;
  452. push_timer_heap(tid);
  453. break;
  454. }
  455. }
  456. }
  457. if( diff < TIMER_MIN_INTERVAL )
  458. return TIMER_MIN_INTERVAL;
  459. if( diff > TIMER_MAX_INTERVAL )
  460. return TIMER_MAX_INTERVAL;
  461. return diff;
  462. }
  463. unsigned long get_uptime(void)
  464. {
  465. return (unsigned long)difftime(time(NULL), start_time);
  466. }
  467. void timer_init(void)
  468. {
  469. time(&start_time);
  470. }
  471. void timer_final(void)
  472. {
  473. struct timer_func_list *tfl;
  474. struct timer_func_list *next;
  475. for( tfl=tfl_root; tfl != NULL; tfl = next ) {
  476. next = tfl->next; // copy next pointer
  477. aFree(tfl->name); // free structures
  478. aFree(tfl);
  479. }
  480. if (timer_data) aFree(timer_data);
  481. if (timer_heap) aFree(timer_heap);
  482. if (free_timer_list) aFree(free_timer_list);
  483. }