egg_timer.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * Copyright (C) 1997 Robey Pointer
  3. * Copyright (C) 1999 - 2002 Eggheads Development Team
  4. * Copyright (C) 2002 - 2014 Bryan Drewery
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. #include <stdio.h> /* For NULL */
  21. #include <sys/time.h> /* For gettimeofday() */
  22. #include "common.h"
  23. #include "egg_timer.h"
  24. typedef int (*TimerFunc) (void *);
  25. /* From main.c */
  26. static egg_timeval_t now;
  27. /* Internal use only. */
  28. typedef struct egg_timer_b {
  29. struct egg_timer_b *next;
  30. int id;
  31. char *name;
  32. TimerFunc callback;
  33. void *client_data;
  34. egg_timeval_t howlong;
  35. egg_timeval_t trigger_time;
  36. int flags;
  37. int called;
  38. } egg_timer_t;
  39. /* We keep a sorted list of active timers. */
  40. static egg_timer_t *timer_repeat_head = NULL, *timer_once_head = NULL;
  41. static int timer_next_id = 1;
  42. /* Based on TclpGetTime from Tcl 8.3.3 */
  43. static inline int timer_get_time(egg_timeval_t *curtime)
  44. {
  45. static struct timeval tv;
  46. (void) gettimeofday(&tv, NULL);
  47. curtime->sec = tv.tv_sec;
  48. curtime->usec = tv.tv_usec;
  49. return(0);
  50. }
  51. void timer_update_now(egg_timeval_t *_now)
  52. {
  53. timer_get_time(&now);
  54. if (_now) timer_get_now(_now);
  55. }
  56. void timer_get_now(egg_timeval_t *_now)
  57. {
  58. _now->sec = now.sec;
  59. _now->usec = now.usec;
  60. }
  61. int timer_get_now_sec(int *sec)
  62. {
  63. if (sec) *sec = now.sec;
  64. return(now.sec);
  65. }
  66. /* Find difference between two timers. */
  67. int timer_diff(egg_timeval_t *from_time, egg_timeval_t *to_time, egg_timeval_t *diff)
  68. {
  69. diff->sec = to_time->sec - from_time->sec;
  70. if (diff->sec < 0) {
  71. diff->sec = 0;
  72. diff->usec = 0;
  73. return(1);
  74. }
  75. diff->usec = to_time->usec - from_time->usec;
  76. if (diff->usec < 0) {
  77. if (diff->sec == 0) {
  78. diff->usec = 0;
  79. return(1);
  80. }
  81. --(diff->sec);
  82. diff->usec += 1000000;
  83. }
  84. return(0);
  85. }
  86. /*
  87. * Return milliseconds difference between two timevals
  88. */
  89. long timeval_diff(const egg_timeval_t *tv1, const egg_timeval_t *tv2)
  90. {
  91. long secs = tv1->sec - tv2->sec, usecs = tv1->usec - tv2->usec;
  92. if (usecs < 0) {
  93. usecs += 1000000;
  94. --secs;
  95. }
  96. usecs = (usecs / 1000) + (secs * 1000);
  97. return usecs;
  98. }
  99. static int timer_add_to_list(egg_timer_t* &timer_list, egg_timer_t *timer)
  100. {
  101. egg_timer_t *prev = NULL, *ptr = NULL;
  102. /* Find out where this should go in the list. */
  103. for (ptr = timer_list; ptr; ptr = ptr->next) {
  104. if (timer->trigger_time.sec < ptr->trigger_time.sec) break;
  105. if (timer->trigger_time.sec == ptr->trigger_time.sec && timer->trigger_time.usec < ptr->trigger_time.usec) break;
  106. prev = ptr;
  107. }
  108. /* Insert into timer list. */
  109. if (prev) {
  110. timer->next = prev->next;
  111. prev->next = timer;
  112. }
  113. else {
  114. timer->next = timer_list;
  115. timer_list = timer;
  116. }
  117. return(0);
  118. }
  119. int timer_create_secs(int secs, const char *name, Function callback)
  120. {
  121. egg_timeval_t howlong;
  122. howlong.sec = secs;
  123. howlong.usec = 0;
  124. return timer_create_repeater(&howlong, name, callback);
  125. }
  126. int timer_create_complex(egg_timeval_t *howlong, const char *name, Function callback, void *client_data, int flags)
  127. {
  128. egg_timer_t *timer = NULL;
  129. /* Fill out a new timer. */
  130. timer = (egg_timer_t *) my_calloc(1, sizeof(*timer));
  131. timer->id = timer_next_id++;
  132. if (name) timer->name = strdup(name);
  133. else timer->name = NULL;
  134. timer->callback = (TimerFunc) callback;
  135. timer->client_data = client_data;
  136. timer->flags = flags;
  137. timer->howlong.sec = howlong->sec;
  138. timer->howlong.usec = howlong->usec;
  139. timer->trigger_time.sec = now.sec + howlong->sec;
  140. timer->trigger_time.usec = now.usec + howlong->usec;
  141. timer->called = 0;
  142. if (timer->flags & TIMER_REPEAT)
  143. timer_add_to_list(timer_repeat_head, timer);
  144. else
  145. timer_add_to_list(timer_once_head, timer);
  146. return(timer->id);
  147. }
  148. static int timer_destroy_list(egg_timer_t* &timer_list, int timer_id)
  149. {
  150. egg_timer_t *prev = NULL, *timer = NULL;
  151. prev = NULL;
  152. for (timer = timer_list; timer; timer = timer->next) {
  153. if (timer->id == timer_id) break;
  154. prev = timer;
  155. }
  156. if (!timer) return(1); /* Not found! */
  157. /* Unlink it. */
  158. if (prev) prev->next = timer->next;
  159. else timer_list = timer->next;
  160. if (timer->name)
  161. free(timer->name);
  162. free(timer);
  163. return(0);
  164. }
  165. /* Destroy a timer, given an id. */
  166. int timer_destroy(int timer_id)
  167. {
  168. if (timer_destroy_list(timer_repeat_head, timer_id))
  169. if (timer_destroy_list(timer_once_head, timer_id))
  170. return 1;
  171. return 0;
  172. }
  173. #ifdef not_used
  174. int timer_destroy_all()
  175. {
  176. egg_timer_t *timer = NULL, *next = NULL;
  177. for (timer = timer_list_head; timer; timer = next) {
  178. next = timer->next;
  179. }
  180. timer_list_head = NULL;
  181. return(0);
  182. }
  183. #endif
  184. int timer_get_shortest(egg_timeval_t *howlong)
  185. {
  186. egg_timer_t *timer = timer_repeat_head;
  187. /* No timers? Boo. */
  188. if (!timer) return(1);
  189. timer_diff(&now, &timer->trigger_time, howlong);
  190. return(0);
  191. }
  192. static bool process_timer(egg_timer_t* timer) {
  193. TimerFunc callback = timer->callback;
  194. void *client_data = timer->client_data;
  195. bool deleted = 0;
  196. if (timer->flags & TIMER_REPEAT) {
  197. /* Update timer. */
  198. /* This used to be '+= howlong.sec' but, if the time changed say 3 years (happened), this function
  199. * would end up executing all timers for 3 years until it is caught up.
  200. */
  201. timer->trigger_time.sec = now.sec + timer->howlong.sec;
  202. timer->trigger_time.usec = now.usec + timer->howlong.usec;
  203. if (timer->trigger_time.usec >= 1000000) {
  204. timer->trigger_time.usec -= 1000000;
  205. ++(timer->trigger_time.sec);
  206. }
  207. ++(timer->called);
  208. } else {
  209. deleted = 1;
  210. }
  211. if (timer->name)
  212. ContextNote("Timer", timer->name);
  213. callback(client_data);
  214. return deleted;
  215. }
  216. static void process_timer_list(egg_timer_t* &timer_list) {
  217. egg_timer_t *timer = NULL, *prev = NULL, *next = timer_list;
  218. while (next) {
  219. timer = next;
  220. // Timers are sorted by lowest->highest, so if the current one isn't ready to trigger, the rest are not either
  221. if (timer->trigger_time.sec > now.sec || (timer->trigger_time.sec == now.sec && timer->trigger_time.usec > now.usec))
  222. break;
  223. next = timer->next;
  224. if (process_timer(timer)) {
  225. // Deleted, need to shift the queue
  226. if (prev) prev->next = timer->next;
  227. else timer_list = timer->next;
  228. if (timer->name)
  229. free(timer->name);
  230. free(timer);
  231. } else
  232. prev = timer;
  233. }
  234. }
  235. void timer_run()
  236. {
  237. process_timer_list(timer_once_head);
  238. process_timer_list(timer_repeat_head);
  239. }
  240. int timer_list(int **ids)
  241. {
  242. egg_timer_t *timer = NULL;
  243. int ntimers = 0;
  244. /* Count timers. */
  245. for (timer = timer_repeat_head; timer; timer = timer->next) ntimers++;
  246. /* Fill in array. */
  247. *ids = (int *) my_calloc(1, sizeof(int) * (ntimers+1));
  248. ntimers = 0;
  249. for (timer = timer_repeat_head; timer; timer = timer->next) {
  250. (*ids)[ntimers++] = timer->id;
  251. }
  252. return(ntimers);
  253. }
  254. int timer_info(int id, char **name, egg_timeval_t *initial_len, egg_timeval_t *trigger_time, int *called)
  255. {
  256. egg_timer_t *timer = NULL;
  257. for (timer = timer_repeat_head; timer; timer = timer->next) {
  258. if (timer->id == id) break;
  259. }
  260. if (!timer) return(-1);
  261. if (name) *name = timer->name;
  262. if (initial_len) memcpy(initial_len, &timer->howlong, sizeof(*initial_len));
  263. if (trigger_time) memcpy(trigger_time, &timer->trigger_time, sizeof(*trigger_time));
  264. if (called) *called = timer->called;
  265. return(0);
  266. }
  267. /* vim: set sts=0 sw=8 ts=8 noet: */