egg_timer.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. * Copyright (C) 1997 Robey Pointer
  3. * Copyright (C) 1999 - 2002 Eggheads Development Team
  4. * Copyright (C) 2002 - 2008 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_list_head = NULL;
  41. static int timer_next_id = 1;
  42. /* Based on TclpGetTime from Tcl 8.3.3 */
  43. int timer_get_time(egg_timeval_t *curtime)
  44. {
  45. 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. int timer_update_now(egg_timeval_t *_now)
  52. {
  53. timer_get_time(&now);
  54. if (_now) {
  55. _now->sec = now.sec;
  56. _now->usec = now.usec;
  57. }
  58. return(now.sec);
  59. }
  60. void timer_get_now(egg_timeval_t *_now)
  61. {
  62. _now->sec = now.sec;
  63. _now->usec = now.usec;
  64. }
  65. int timer_get_now_sec(int *sec)
  66. {
  67. if (sec) *sec = now.sec;
  68. return(now.sec);
  69. }
  70. /* Find difference between two timers. */
  71. int timer_diff(egg_timeval_t *from_time, egg_timeval_t *to_time, egg_timeval_t *diff)
  72. {
  73. diff->sec = to_time->sec - from_time->sec;
  74. if (diff->sec < 0) {
  75. diff->sec = 0;
  76. diff->usec = 0;
  77. return(1);
  78. }
  79. diff->usec = to_time->usec - from_time->usec;
  80. if (diff->usec < 0) {
  81. if (diff->sec == 0) {
  82. diff->usec = 0;
  83. return(1);
  84. }
  85. diff->sec -= 1;
  86. diff->usec += 1000000;
  87. }
  88. return(0);
  89. }
  90. static int timer_add_to_list(egg_timer_t *timer)
  91. {
  92. egg_timer_t *prev = NULL, *ptr = NULL;
  93. /* Find out where this should go in the list. */
  94. for (ptr = timer_list_head; ptr; ptr = ptr->next) {
  95. if (timer->trigger_time.sec < ptr->trigger_time.sec) break;
  96. if (timer->trigger_time.sec == ptr->trigger_time.sec && timer->trigger_time.usec < ptr->trigger_time.usec) break;
  97. prev = ptr;
  98. }
  99. /* Insert into timer list. */
  100. if (prev) {
  101. timer->next = prev->next;
  102. prev->next = timer;
  103. }
  104. else {
  105. timer->next = timer_list_head;
  106. timer_list_head = timer;
  107. }
  108. return(0);
  109. }
  110. int timer_create_secs(int secs, const char *name, Function callback)
  111. {
  112. egg_timeval_t howlong;
  113. howlong.sec = secs;
  114. howlong.usec = 0;
  115. return timer_create_repeater(&howlong, name, callback);
  116. }
  117. int timer_create_complex(egg_timeval_t *howlong, const char *name, Function callback, void *client_data, int flags)
  118. {
  119. egg_timer_t *timer = NULL;
  120. /* Fill out a new timer. */
  121. timer = (egg_timer_t *) my_calloc(1, sizeof(*timer));
  122. timer->id = timer_next_id++;
  123. if (name) timer->name = strdup(name);
  124. else timer->name = NULL;
  125. timer->callback = (TimerFunc) callback;
  126. timer->client_data = client_data;
  127. timer->flags = flags;
  128. timer->howlong.sec = howlong->sec;
  129. timer->howlong.usec = howlong->usec;
  130. timer->trigger_time.sec = now.sec + howlong->sec;
  131. timer->trigger_time.usec = now.usec + howlong->usec;
  132. timer->called = 0;
  133. timer_add_to_list(timer);
  134. return(timer->id);
  135. }
  136. /* Destroy a timer, given an id. */
  137. int timer_destroy(int timer_id)
  138. {
  139. egg_timer_t *prev = NULL, *timer = NULL;
  140. prev = NULL;
  141. for (timer = timer_list_head; timer; timer = timer->next) {
  142. if (timer->id == timer_id) break;
  143. prev = timer;
  144. }
  145. if (!timer) return(1); /* Not found! */
  146. /* Unlink it. */
  147. if (prev) prev->next = timer->next;
  148. else timer_list_head = timer->next;
  149. if (timer->name) free(timer->name);
  150. free(timer);
  151. return(0);
  152. }
  153. int timer_destroy_all()
  154. {
  155. egg_timer_t *timer = NULL, *next = NULL;
  156. for (timer = timer_list_head; timer; timer = next) {
  157. next = timer->next;
  158. }
  159. timer_list_head = NULL;
  160. return(0);
  161. }
  162. int timer_get_shortest(egg_timeval_t *howlong)
  163. {
  164. egg_timer_t *timer = timer_list_head;
  165. /* No timers? Boo. */
  166. if (!timer) return(1);
  167. timer_diff(&now, &timer->trigger_time, howlong);
  168. return(0);
  169. }
  170. int timer_run()
  171. {
  172. egg_timer_t *timer = NULL;
  173. TimerFunc callback;
  174. void *client_data = NULL;
  175. while (timer_list_head) {
  176. timer = timer_list_head;
  177. if (timer->trigger_time.sec > now.sec ||
  178. (timer->trigger_time.sec == now.sec && timer->trigger_time.usec > now.usec)) break;
  179. timer_list_head = timer_list_head->next;
  180. callback = timer->callback;
  181. client_data = timer->client_data;
  182. if (timer->flags & TIMER_REPEAT) {
  183. /* Update timer. */
  184. /* This used to be '+= howlong.sec' but, if the time changed say 3 years (happened), this function
  185. * would end up executing all timers for 3 years until it is caught up.
  186. */
  187. timer->trigger_time.sec = now.sec + timer->howlong.sec;
  188. timer->trigger_time.usec = now.usec + timer->howlong.usec;
  189. if (timer->trigger_time.usec >= 1000000) {
  190. timer->trigger_time.usec -= 1000000;
  191. timer->trigger_time.sec += 1;
  192. }
  193. /* Add it back into the list. */
  194. timer_add_to_list(timer);
  195. timer->called++;
  196. }
  197. else {
  198. if (timer->name) free(timer->name);
  199. free(timer);
  200. }
  201. callback(client_data);
  202. }
  203. return(0);
  204. }
  205. int timer_list(int **ids)
  206. {
  207. egg_timer_t *timer = NULL;
  208. int ntimers = 0;
  209. /* Count timers. */
  210. for (timer = timer_list_head; timer; timer = timer->next) ntimers++;
  211. /* Fill in array. */
  212. *ids = (int *) my_calloc(1, sizeof(int) * (ntimers+1));
  213. ntimers = 0;
  214. for (timer = timer_list_head; timer; timer = timer->next) {
  215. (*ids)[ntimers++] = timer->id;
  216. }
  217. return(ntimers);
  218. }
  219. int timer_info(int id, char **name, egg_timeval_t *initial_len, egg_timeval_t *trigger_time, int *called)
  220. {
  221. egg_timer_t *timer = NULL;
  222. for (timer = timer_list_head; timer; timer = timer->next) {
  223. if (timer->id == id) break;
  224. }
  225. if (!timer) return(-1);
  226. if (name) *name = timer->name;
  227. if (initial_len) memcpy(initial_len, &timer->howlong, sizeof(*initial_len));
  228. if (trigger_time) memcpy(trigger_time, &timer->trigger_time, sizeof(*trigger_time));
  229. if (called) *called = timer->called;
  230. return(0);
  231. }