local_timer.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2007 iptelorg GmbH
  5. *
  6. * This file is part of ser, a free SIP server.
  7. *
  8. * ser is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version
  12. *
  13. * For a license to use the ser software under conditions
  14. * other than those described here, or to purchase support for this
  15. * software, please contact iptel.org by e-mail at the following addresses:
  16. * [email protected]
  17. *
  18. * ser is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program; if not, write to the Free Software
  25. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  26. */
  27. /* local, per process timer routines
  28. * WARNING: this should be used only within the same process, the timers
  29. * are not multi-process safe or multi-thread safe
  30. * (there are no locks)
  31. *
  32. * History:
  33. * --------
  34. * 2006-02-03 created by andrei
  35. */
  36. #include "timer.h"
  37. #include "timer_funcs.h"
  38. #include "dprint.h"
  39. #include "tcp_conn.h"
  40. #include "mem/mem.h"
  41. #include "compiler_opt.h"
  42. #include "local_timer.h"
  43. /* init a local_timer handle
  44. * returns 0 on success, -1 on error */
  45. int init_local_timer(struct local_timer *t, ticks_t crt_ticks)
  46. {
  47. int r;
  48. /* initial values */
  49. memset(t, 0, sizeof(*t));
  50. t->prev_ticks=crt_ticks;
  51. /* init timer structures */
  52. for (r=0; r<H0_ENTRIES; r++)
  53. _timer_init_list(&t->timer_lst.h0[r]);
  54. for (r=0; r<H1_ENTRIES; r++)
  55. _timer_init_list(&t->timer_lst.h1[r]);
  56. for (r=0; r<H2_ENTRIES; r++)
  57. _timer_init_list(&t->timer_lst.h2[r]);
  58. _timer_init_list(&t->timer_lst.expired);
  59. DBG("init_local_timer: timer_list between %p and %p\n",
  60. &t->timer_lst.h0[0], &t->timer_lst.h2[H2_ENTRIES]);
  61. return 0;
  62. }
  63. void destroy_local_timer(struct local_timer* lt)
  64. {
  65. }
  66. /* generic add timer entry to the timer lists function (see _timer_add)
  67. * tl->expire must be set previously, delta is the difference in ticks
  68. * from current time to the timer desired expire (should be tl->expire-*tick)
  69. * If you don't know delta, you probably want to call _timer_add instead.
  70. */
  71. static inline int _local_timer_dist_tl(struct local_timer* h,
  72. struct timer_ln* tl, ticks_t delta)
  73. {
  74. if (likely(delta<H0_ENTRIES)){
  75. if (unlikely(delta==0)){
  76. LOG(L_WARN, "WARNING: local_timer: add_timeout: 0 expire timer"
  77. " added\n");
  78. _timer_add_list(&h->timer_lst.expired, tl);
  79. }else{
  80. _timer_add_list( &h->timer_lst.h0[tl->expire & H0_MASK], tl);
  81. }
  82. }else if (likely(delta<(H0_ENTRIES*H1_ENTRIES))){
  83. _timer_add_list(&h->timer_lst.h1[(tl->expire & H1_H0_MASK)>>H0_BITS],
  84. tl);
  85. }else{
  86. _timer_add_list(&h->timer_lst.h2[tl->expire>>(H1_BITS+H0_BITS)], tl);
  87. }
  88. return 0;
  89. }
  90. static inline void local_timer_redist(struct local_timer* l,
  91. ticks_t t, struct timer_head *h)
  92. {
  93. struct timer_ln* tl;
  94. struct timer_ln* tmp;
  95. timer_foreach_safe(tl, tmp, h){
  96. _local_timer_dist_tl(l, tl, tl->expire-t);
  97. }
  98. /* clear the current list */
  99. _timer_init_list(h);
  100. }
  101. /* local timer add function (no lock, not multithread or multiprocess safe,
  102. * designed for local process use only)
  103. * t = current ticks
  104. * tl must be filled (the intial_timeout and flags must be set)
  105. * returns -1 on error, 0 on success */
  106. static inline int _local_timer_add(struct local_timer *h, ticks_t t,
  107. struct timer_ln* tl)
  108. {
  109. ticks_t delta;
  110. delta=tl->initial_timeout;
  111. tl->expire=t+delta;
  112. return _local_timer_dist_tl(h, tl, delta);
  113. }
  114. /* "public", safe timer add functions (local process use only)
  115. * adds a timer at delta ticks from the current time
  116. * returns -1 on error, 0 on success
  117. * WARNING: to re-add a deleted or expired timer you must call
  118. * timer_reinit(tl) prior to timer_add
  119. * The default behaviour allows timer_add to add a timer only if it
  120. * has never been added before.*/
  121. int local_timer_add(struct local_timer* h, struct timer_ln* tl, ticks_t delta,
  122. ticks_t crt_ticks)
  123. {
  124. int ret;
  125. if (unlikely(tl->flags & F_TIMER_ACTIVE)){
  126. DBG("timer_add called on an active timer %p (%p, %p),"
  127. " flags %x\n", tl, tl->next, tl->prev, tl->flags);
  128. ret=-1; /* refusing to add active or non-reinit. timer */
  129. goto error;
  130. }
  131. tl->initial_timeout=delta;
  132. if (unlikely((tl->next!=0) || (tl->prev!=0))){
  133. LOG(L_CRIT, "BUG: tcp_timer_add: called with linked timer:"
  134. " %p (%p, %p)\n", tl, tl->next, tl->prev);
  135. ret=-1;
  136. goto error;
  137. }
  138. tl->flags|=F_TIMER_ACTIVE;
  139. ret=_local_timer_add(h, crt_ticks, tl);
  140. error:
  141. return ret;
  142. }
  143. /* safe timer delete
  144. * deletes tl and inits the list pointer to 0
  145. * WARNING: to be able to reuse a deleted timer you must call
  146. * timer_reinit(tl) on it
  147. *
  148. */
  149. void local_timer_del(struct local_timer* h, struct timer_ln* tl)
  150. {
  151. /* quick exit if timer inactive */
  152. if (unlikely(!(tl->flags & F_TIMER_ACTIVE))){
  153. DBG("timer_del called on an inactive timer %p (%p, %p),"
  154. " flags %x\n", tl, tl->next, tl->prev, tl->flags);
  155. return;
  156. }
  157. if (likely((tl->next!=0)&&(tl->prev!=0))){
  158. _timer_rm_list(tl); /* detach */
  159. tl->next=tl->prev=0;
  160. }else{
  161. DBG("timer_del: (f) timer %p (%p, %p) flags %x "
  162. "already detached\n",
  163. tl, tl->next, tl->prev, tl->flags);
  164. }
  165. }
  166. /* called from timer_handle*/
  167. inline static void local_timer_list_expire(struct local_timer* l,
  168. ticks_t t, struct timer_head* h)
  169. {
  170. struct timer_ln * tl;
  171. ticks_t ret;
  172. /*DBG("timer_list_expire @ ticks = %lu, list =%p\n",
  173. (unsigned long) *ticks, h);
  174. */
  175. while(h->next!=(struct timer_ln*)h){
  176. tl=h->next;
  177. _timer_rm_list(tl); /* detach */
  178. tl->next=tl->prev=0; /* debugging */
  179. /*FIXME: process tcpconn */
  180. ret=tl->f(t, tl, tl->data);
  181. if (ret!=0){
  182. /* not one-shot, re-add it */
  183. if (ret!=(ticks_t)-1) /* ! periodic */
  184. tl->initial_timeout=ret;
  185. _local_timer_add(l, t, tl);
  186. }
  187. }
  188. }
  189. /* run all the handler that expire at t ticks */
  190. static inline void local_timer_expire(struct local_timer* h, ticks_t t)
  191. {
  192. /* trust the compiler for optimizing */
  193. if (unlikely((t & H0_MASK)==0)){ /*r1*/
  194. if (unlikely((t & H1_H0_MASK)==0)){ /*r2*/
  195. local_timer_redist(h, t, &h->timer_lst.h2[t>>(H0_BITS+H1_BITS)]);
  196. }
  197. local_timer_redist(h, t, &h->timer_lst.h1[(t & H1_H0_MASK)>>H0_BITS]);
  198. /*r2 >> H0*/
  199. }
  200. /* run handler immediately, no need to move it to the expired list
  201. * (since no locks are used) */
  202. local_timer_list_expire(h, t, &h->timer_lst.h0[t & H0_MASK]);
  203. }
  204. /* "main" local timer routine, should be called with a proper ticks value
  205. * WARNING: it should never be called twice for the same ticks value
  206. * (it could cause too fast expires for long timers), ticks must be also
  207. * always increasing */
  208. void local_timer_run(struct local_timer* lt, ticks_t saved_ticks)
  209. {
  210. /* protect against time running backwards */
  211. if (unlikely(lt->prev_ticks>=saved_ticks)){
  212. LOG(L_CRIT, "BUG: local_timer: backwards or still time\n");
  213. /* try to continue */
  214. lt->prev_ticks=saved_ticks-1;
  215. return;
  216. }
  217. /* go through all the "missed" ticks, taking a possible overflow
  218. * into account */
  219. for (lt->prev_ticks=lt->prev_ticks+1; lt->prev_ticks!=saved_ticks;
  220. lt->prev_ticks++)
  221. local_timer_expire(lt, lt->prev_ticks);
  222. local_timer_expire(lt, lt->prev_ticks); /* do it for saved_ticks too */
  223. local_timer_list_expire(lt, saved_ticks, &lt->timer_lst.expired);
  224. /* WARNING: add_timer(...,0) must go directly to expired list, since
  225. * otherwise there is a race between timer running and adding it
  226. * (it could expire it H0_ENTRIES ticks later instead of 'now')*/
  227. }