2
0

local_timer.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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. /*!
  37. * \file
  38. * \brief SIP-router core ::
  39. * \ingroup core
  40. * Module: \ref core
  41. */
  42. #include "timer.h"
  43. #include "timer_funcs.h"
  44. #include "dprint.h"
  45. #include "tcp_conn.h"
  46. #include "mem/mem.h"
  47. #include "compiler_opt.h"
  48. #include "local_timer.h"
  49. /* init a local_timer handle
  50. * returns 0 on success, -1 on error */
  51. int init_local_timer(struct local_timer *t, ticks_t crt_ticks)
  52. {
  53. int r;
  54. /* initial values */
  55. memset(t, 0, sizeof(*t));
  56. t->prev_ticks=crt_ticks;
  57. /* init timer structures */
  58. for (r=0; r<H0_ENTRIES; r++)
  59. _timer_init_list(&t->timer_lst.h0[r]);
  60. for (r=0; r<H1_ENTRIES; r++)
  61. _timer_init_list(&t->timer_lst.h1[r]);
  62. for (r=0; r<H2_ENTRIES; r++)
  63. _timer_init_list(&t->timer_lst.h2[r]);
  64. _timer_init_list(&t->timer_lst.expired);
  65. DBG("init_local_timer: timer_list between %p and %p\n",
  66. &t->timer_lst.h0[0], &t->timer_lst.h2[H2_ENTRIES]);
  67. return 0;
  68. }
  69. void destroy_local_timer(struct local_timer* lt)
  70. {
  71. }
  72. /* generic add timer entry to the timer lists function (see _timer_add)
  73. * tl->expire must be set previously, delta is the difference in ticks
  74. * from current time to the timer desired expire (should be tl->expire-*tick)
  75. * If you don't know delta, you probably want to call _timer_add instead.
  76. */
  77. static inline int _local_timer_dist_tl(struct local_timer* h,
  78. struct timer_ln* tl, ticks_t delta)
  79. {
  80. if (likely(delta<H0_ENTRIES)){
  81. if (unlikely(delta==0)){
  82. LOG(L_WARN, "WARNING: local_timer: add_timeout: 0 expire timer"
  83. " added\n");
  84. _timer_add_list(&h->timer_lst.expired, tl);
  85. }else{
  86. _timer_add_list( &h->timer_lst.h0[tl->expire & H0_MASK], tl);
  87. }
  88. }else if (likely(delta<(H0_ENTRIES*H1_ENTRIES))){
  89. _timer_add_list(&h->timer_lst.h1[(tl->expire & H1_H0_MASK)>>H0_BITS],
  90. tl);
  91. }else{
  92. _timer_add_list(&h->timer_lst.h2[tl->expire>>(H1_BITS+H0_BITS)], tl);
  93. }
  94. return 0;
  95. }
  96. static inline void local_timer_redist(struct local_timer* l,
  97. ticks_t t, struct timer_head *h)
  98. {
  99. struct timer_ln* tl;
  100. struct timer_ln* tmp;
  101. timer_foreach_safe(tl, tmp, h){
  102. _local_timer_dist_tl(l, tl, tl->expire-t);
  103. }
  104. /* clear the current list */
  105. _timer_init_list(h);
  106. }
  107. /* local timer add function (no lock, not multithread or multiprocess safe,
  108. * designed for local process use only)
  109. * t = current ticks
  110. * tl must be filled (the intial_timeout and flags must be set)
  111. * returns -1 on error, 0 on success */
  112. static inline int _local_timer_add(struct local_timer *h, ticks_t t,
  113. struct timer_ln* tl)
  114. {
  115. ticks_t delta;
  116. delta=tl->initial_timeout;
  117. tl->expire=t+delta;
  118. return _local_timer_dist_tl(h, tl, delta);
  119. }
  120. /* "public", safe timer add functions (local process use only)
  121. * adds a timer at delta ticks from the current time
  122. * returns -1 on error, 0 on success
  123. * WARNING: to re-add a deleted or expired timer you must call
  124. * timer_reinit(tl) prior to timer_add
  125. * The default behaviour allows timer_add to add a timer only if it
  126. * has never been added before.*/
  127. int local_timer_add(struct local_timer* h, struct timer_ln* tl, ticks_t delta,
  128. ticks_t crt_ticks)
  129. {
  130. int ret;
  131. if (unlikely(tl->flags & F_TIMER_ACTIVE)){
  132. DBG("timer_add called on an active timer %p (%p, %p),"
  133. " flags %x\n", tl, tl->next, tl->prev, tl->flags);
  134. ret=-1; /* refusing to add active or non-reinit. timer */
  135. goto error;
  136. }
  137. tl->initial_timeout=delta;
  138. if (unlikely((tl->next!=0) || (tl->prev!=0))){
  139. LOG(L_CRIT, "BUG: tcp_timer_add: called with linked timer:"
  140. " %p (%p, %p)\n", tl, tl->next, tl->prev);
  141. ret=-1;
  142. goto error;
  143. }
  144. tl->flags|=F_TIMER_ACTIVE;
  145. ret=_local_timer_add(h, crt_ticks, tl);
  146. error:
  147. return ret;
  148. }
  149. /* safe timer delete
  150. * deletes tl and inits the list pointer to 0
  151. * WARNING: to be able to reuse a deleted timer you must call
  152. * timer_reinit(tl) on it
  153. *
  154. */
  155. void local_timer_del(struct local_timer* h, struct timer_ln* tl)
  156. {
  157. /* quick exit if timer inactive */
  158. if (unlikely(!(tl->flags & F_TIMER_ACTIVE))){
  159. DBG("timer_del called on an inactive timer %p (%p, %p),"
  160. " flags %x\n", tl, tl->next, tl->prev, tl->flags);
  161. return;
  162. }
  163. if (likely((tl->next!=0)&&(tl->prev!=0))){
  164. _timer_rm_list(tl); /* detach */
  165. tl->next=tl->prev=0;
  166. }else{
  167. DBG("timer_del: (f) timer %p (%p, %p) flags %x "
  168. "already detached\n",
  169. tl, tl->next, tl->prev, tl->flags);
  170. }
  171. }
  172. /* called from timer_handle*/
  173. inline static void local_timer_list_expire(struct local_timer* l,
  174. ticks_t t, struct timer_head* h)
  175. {
  176. struct timer_ln * tl;
  177. ticks_t ret;
  178. /*DBG("timer_list_expire @ ticks = %lu, list =%p\n",
  179. (unsigned long) *ticks, h);
  180. */
  181. while(h->next!=(struct timer_ln*)h){
  182. tl=h->next;
  183. _timer_rm_list(tl); /* detach */
  184. tl->next=tl->prev=0; /* debugging */
  185. /*FIXME: process tcpconn */
  186. ret=tl->f(t, tl, tl->data);
  187. if (ret!=0){
  188. /* not one-shot, re-add it */
  189. if (ret!=(ticks_t)-1) /* ! periodic */
  190. tl->initial_timeout=ret;
  191. _local_timer_add(l, t, tl);
  192. }
  193. }
  194. }
  195. /* run all the handler that expire at t ticks */
  196. static inline void local_timer_expire(struct local_timer* h, ticks_t t)
  197. {
  198. /* trust the compiler for optimizing */
  199. if (unlikely((t & H0_MASK)==0)){ /*r1*/
  200. if (unlikely((t & H1_H0_MASK)==0)){ /*r2*/
  201. local_timer_redist(h, t, &h->timer_lst.h2[t>>(H0_BITS+H1_BITS)]);
  202. }
  203. local_timer_redist(h, t, &h->timer_lst.h1[(t & H1_H0_MASK)>>H0_BITS]);
  204. /*r2 >> H0*/
  205. }
  206. /* run handler immediately, no need to move it to the expired list
  207. * (since no locks are used) */
  208. local_timer_list_expire(h, t, &h->timer_lst.h0[t & H0_MASK]);
  209. }
  210. /* "main" local timer routine, should be called with a proper ticks value
  211. * WARNING: it should never be called twice for the same ticks value
  212. * (it could cause too fast expires for long timers), ticks must be also
  213. * always increasing */
  214. void local_timer_run(struct local_timer* lt, ticks_t saved_ticks)
  215. {
  216. /* protect against time running backwards */
  217. if (unlikely(lt->prev_ticks>=saved_ticks)){
  218. LOG(L_CRIT, "BUG: local_timer: backwards or still time\n");
  219. /* try to continue */
  220. lt->prev_ticks=saved_ticks-1;
  221. return;
  222. }
  223. /* go through all the "missed" ticks, taking a possible overflow
  224. * into account */
  225. for (lt->prev_ticks=lt->prev_ticks+1; lt->prev_ticks!=saved_ticks;
  226. lt->prev_ticks++)
  227. local_timer_expire(lt, lt->prev_ticks);
  228. local_timer_expire(lt, lt->prev_ticks); /* do it for saved_ticks too */
  229. local_timer_list_expire(lt, saved_ticks, &lt->timer_lst.expired);
  230. /* WARNING: add_timer(...,0) must go directly to expired list, since
  231. * otherwise there is a race between timer running and adding it
  232. * (it could expire it H0_ENTRIES ticks later instead of 'now')*/
  233. }