2
0

dlg_timer.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2006 Voice System SRL
  5. *
  6. * This file is part of Kamailio, a free SIP server.
  7. *
  8. * Kamailio 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. * Kamailio is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * History:
  23. * --------
  24. * 2006-04-14 initial version (bogdan)
  25. * 2007-03-06 to avoid races, tests on timer links are done under locks
  26. * (bogdan)
  27. */
  28. /*!
  29. * \file
  30. * \brief Timer related functions for the dialog module
  31. * \ingroup dialog
  32. * Module: \ref dialog
  33. */
  34. #include "../../mem/shm_mem.h"
  35. #include "../../timer.h"
  36. #include "dlg_timer.h"
  37. /*! global dialog timer */
  38. struct dlg_timer *d_timer = 0;
  39. /*! global dialog timer handler */
  40. dlg_timer_handler timer_hdl = 0;
  41. /*!
  42. * \brief Initialize the dialog timer handler
  43. * Initialize the dialog timer handler, allocate the lock and a global
  44. * timer in shared memory. The global timer handler will be set on success.
  45. * \param hdl dialog timer handler
  46. * \return 0 on success, -1 on failure
  47. */
  48. int init_dlg_timer(dlg_timer_handler hdl)
  49. {
  50. d_timer = (struct dlg_timer*)shm_malloc(sizeof(struct dlg_timer));
  51. if (d_timer==0) {
  52. LM_ERR("no more shm mem\n");
  53. return -1;
  54. }
  55. memset( d_timer, 0, sizeof(struct dlg_timer) );
  56. d_timer->first.next = d_timer->first.prev = &(d_timer->first);
  57. d_timer->lock = lock_alloc();
  58. if (d_timer->lock==0) {
  59. LM_ERR("failed to alloc lock\n");
  60. goto error0;
  61. }
  62. if (lock_init(d_timer->lock)==0) {
  63. LM_ERR("failed to init lock\n");
  64. goto error1;
  65. }
  66. timer_hdl = hdl;
  67. return 0;
  68. error1:
  69. lock_dealloc(d_timer->lock);
  70. error0:
  71. shm_free(d_timer);
  72. d_timer = 0;
  73. return -1;
  74. }
  75. /*!
  76. * \brief Destroy global dialog timer
  77. */
  78. void destroy_dlg_timer(void)
  79. {
  80. if (d_timer==0)
  81. return;
  82. lock_destroy(d_timer->lock);
  83. lock_dealloc(d_timer->lock);
  84. shm_free(d_timer);
  85. d_timer = 0;
  86. }
  87. /*!
  88. * \brief Helper function for insert_dialog_timer
  89. * \see insert_dialog_timer
  90. * \param tl dialog timer list
  91. */
  92. static inline void insert_dialog_timer_unsafe(struct dlg_tl *tl)
  93. {
  94. struct dlg_tl* ptr;
  95. /* insert in sorted order */
  96. for(ptr = d_timer->first.prev; ptr != &d_timer->first ; ptr = ptr->prev) {
  97. if ( ptr->timeout <= tl->timeout )
  98. break;
  99. }
  100. LM_DBG("inserting %p for %d\n", tl,tl->timeout);
  101. tl->prev = ptr;
  102. tl->next = ptr->next;
  103. tl->prev->next = tl;
  104. tl->next->prev = tl;
  105. }
  106. /*!
  107. * \brief Insert a dialog timer to the list
  108. * \param tl dialog timer list
  109. * \param interval timeout value in seconds
  110. * \return 0 on success, -1 when the input timer list is invalid
  111. */
  112. int insert_dlg_timer(struct dlg_tl *tl, int interval)
  113. {
  114. lock_get( d_timer->lock);
  115. if (tl->next!=0 || tl->prev!=0) {
  116. LM_CRIT("Trying to insert a bogus dlg tl=%p tl->next=%p tl->prev=%p\n",
  117. tl, tl->next, tl->prev);
  118. lock_release( d_timer->lock);
  119. return -1;
  120. }
  121. tl->timeout = get_ticks()+interval;
  122. insert_dialog_timer_unsafe( tl );
  123. lock_release( d_timer->lock);
  124. return 0;
  125. }
  126. /*!
  127. * \brief Helper function for remove_dialog_timer
  128. * \param tl dialog timer list
  129. * \see remove_dialog_timer
  130. */
  131. static inline void remove_dialog_timer_unsafe(struct dlg_tl *tl)
  132. {
  133. tl->prev->next = tl->next;
  134. tl->next->prev = tl->prev;
  135. }
  136. /*!
  137. * \brief Remove a dialog timer from the list
  138. * \param tl dialog timer that should be removed
  139. * \return 1 when the input timer is empty, 0 when the timer was removed,
  140. * -1 when the input timer list is invalid
  141. */
  142. int remove_dialog_timer(struct dlg_tl *tl)
  143. {
  144. lock_get( d_timer->lock);
  145. if (tl->prev==NULL && tl->timeout==0) {
  146. lock_release( d_timer->lock);
  147. return 1;
  148. }
  149. if (tl->prev==NULL || tl->next==NULL) {
  150. LM_CRIT("bogus tl=%p tl->prev=%p tl->next=%p\n",
  151. tl, tl->prev, tl->next);
  152. lock_release( d_timer->lock);
  153. return -1;
  154. }
  155. remove_dialog_timer_unsafe(tl);
  156. tl->next = NULL;
  157. tl->prev = NULL;
  158. tl->timeout = 0;
  159. lock_release( d_timer->lock);
  160. return 0;
  161. }
  162. /*!
  163. * \brief Update a dialog timer on the list
  164. * \param tl dialog timer
  165. * \param timeout new timeout value in seconds
  166. * \return 0 on success, -1 when the input list is invalid
  167. * \note the update is implemented as a remove, insert
  168. */
  169. int update_dlg_timer(struct dlg_tl *tl, int timeout)
  170. {
  171. lock_get( d_timer->lock);
  172. if (tl->next==0 || tl->prev==0) {
  173. LM_CRIT("Trying to update a bogus dlg tl=%p tl->next=%p tl->prev=%p\n",
  174. tl, tl->next, tl->prev);
  175. lock_release( d_timer->lock);
  176. return -1;
  177. }
  178. remove_dialog_timer_unsafe( tl );
  179. tl->timeout = get_ticks()+timeout;
  180. insert_dialog_timer_unsafe( tl );
  181. lock_release( d_timer->lock);
  182. return 0;
  183. }
  184. /*!
  185. * \brief Helper function for dlg_timer_routine
  186. * \param time time for expiration check
  187. * \return list of expired dialogs on success, 0 on failure
  188. */
  189. static inline struct dlg_tl* get_expired_dlgs(unsigned int time)
  190. {
  191. struct dlg_tl *tl , *end, *ret;
  192. lock_get( d_timer->lock);
  193. if (d_timer->first.next==&(d_timer->first)
  194. || d_timer->first.next->timeout > time ) {
  195. lock_release( d_timer->lock);
  196. return 0;
  197. }
  198. end = &d_timer->first;
  199. tl = d_timer->first.next;
  200. LM_DBG("start with tl=%p tl->prev=%p tl->next=%p (%d) at %d "
  201. "and end with end=%p end->prev=%p end->next=%p\n",
  202. tl,tl->prev,tl->next,tl->timeout,time,
  203. end,end->prev,end->next);
  204. while( tl!=end && tl->timeout <= time) {
  205. LM_DBG("getting tl=%p tl->prev=%p tl->next=%p with %d\n",
  206. tl,tl->prev,tl->next,tl->timeout);
  207. tl->prev = 0;
  208. tl->timeout = 0;
  209. tl=tl->next;
  210. }
  211. LM_DBG("end with tl=%p tl->prev=%p tl->next=%p and d_timer->first.next->prev=%p\n",
  212. tl,tl->prev,tl->next,d_timer->first.next->prev);
  213. if (tl==end && d_timer->first.next->prev) {
  214. ret = 0;
  215. } else {
  216. ret = d_timer->first.next;
  217. tl->prev->next = 0;
  218. d_timer->first.next = tl;
  219. tl->prev = &d_timer->first;
  220. }
  221. lock_release( d_timer->lock);
  222. return ret;
  223. }
  224. /*!
  225. * \brief Timer routine for expiration of dialogs
  226. * Timer handler for expiration of dialogs, runs the global timer handler on them.
  227. * \param time for expiration checks
  228. * \param attr unused
  229. */
  230. void dlg_timer_routine(unsigned int ticks , void * attr)
  231. {
  232. struct dlg_tl *tl, *ctl;
  233. tl = get_expired_dlgs( ticks );
  234. while (tl) {
  235. ctl = tl;
  236. tl = tl->next;
  237. ctl->next = NULL;
  238. LM_DBG("tl=%p next=%p\n", ctl, tl);
  239. timer_hdl( ctl );
  240. }
  241. }