dlg_timer.c 6.4 KB

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