timer.c 15 KB

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