memory access syncing protection added
[sip-router] / modules / tm / timer.c
1 /*
2  * $Id$
3  */
4
5
6 #include "config.h"
7 #include "h_table.h"
8 #include "timer.h"
9 #include "../../dprint.h"
10
11 int timer_group[NR_OF_TIMER_LISTS] = { 
12         TG_FR, TG_FR,
13         TG_WT,
14         TG_DEL,
15         TG_RT, TG_RT, TG_RT, TG_RT
16 };
17
18 void reset_timer_list( struct s_table* hash_table, enum lists list_id)
19 {
20         hash_table->timers[ list_id ].first_tl.next_tl = & (hash_table->timers[ list_id ].last_tl );
21         hash_table->timers[ list_id ].last_tl.prev_tl = & (hash_table->timers[ list_id ].first_tl );
22         hash_table->timers[ list_id ].first_tl.prev_tl = 
23                 hash_table->timers[ list_id ].last_tl.next_tl = NULL;
24         hash_table->timers[ list_id ].last_tl.time_out = -1;
25 }
26
27 void init_timer_list( struct s_table* hash_table, enum lists list_id)
28 {
29         reset_timer_list( hash_table, list_id );
30         init_timerlist_lock( hash_table, list_id );
31 }
32
33 void print_timer_list(struct s_table* hash_table, enum lists list_id)
34 {
35    struct timer* timer_list=&(hash_table->timers[ list_id ]);
36    struct timer_link *tl ;
37
38    tl = timer_list->first_tl.next_tl;
39    while (tl!=& timer_list->last_tl)
40    {
41       DBG("DEBUG: print_timer_list[%d]: %p, next=%p \n",list_id, tl, tl->next_tl);
42       tl = tl->next_tl;
43    }
44 }
45
46 /* static void remove_from_timer_list_dummy(  struct timer_link* tl ) */
47 void remove_timer_unsafe(  struct timer_link* tl )
48 {
49         if (is_in_timer_list2( tl )) {
50                 tl->prev_tl->next_tl = tl->next_tl;
51                 tl->next_tl->prev_tl = tl->prev_tl;
52                 tl->next_tl = 0;
53                 tl->prev_tl = 0;
54                 tl->timer_list = NULL;
55         }
56 }
57
58 /* put a new cell into a list nr. list_id within a hash_table;
59   * set initial timeout
60   */
61 void add_timer_unsafe( struct timer *timer_list,
62         struct timer_link *tl, unsigned int time_out )
63 {
64         /*      remove_from_timer_list( tl ); */
65         /* the entire timer list is locked now -- noone else can manipulate it */
66         /* lock( timer_list->mutex ); */
67         tl->time_out = time_out;
68         tl->prev_tl = timer_list->last_tl.prev_tl;
69         tl->next_tl = & timer_list->last_tl;
70         timer_list->last_tl.prev_tl = tl;
71         tl->prev_tl->next_tl = tl;
72         tl->timer_list = timer_list;
73 #       ifdef EXTRA_DEBUG
74                 if ( tl->tg != timer_group[ timer_list->id ] ) {
75                         LOG( L_CRIT, "CRITICAL error: changing timer group\n");
76                         abort();
77                 }
78 #       endif
79         /* give the list lock away */
80         /* unlock( timer_list->mutex ); */
81         DBG("DEBUG: add_to_tail_of_timer[%d]: %p\n",timer_list->id,tl);
82 }
83
84 /*
85         detach items passed by the time from timer list
86 */
87 struct timer_link  *check_and_split_time_list( struct timer *timer_list, int time )
88
89 {
90         struct timer_link *tl , *tmp , *end, *ret;
91
92         /* quick check whether it is worth entering the lock */
93         if (timer_list->first_tl.next_tl==&timer_list->last_tl ||
94                 timer_list->first_tl.next_tl->time_out > time )
95                         return NULL;
96
97         /* the entire timer list is locked now -- noone else can manipulate it */
98         lock( timer_list->mutex );
99
100         end = &timer_list->last_tl;
101         tl = timer_list->first_tl.next_tl;
102         while( tl!=end && tl->time_out <= time) {
103                 tl->timer_list = NULL;
104                 tl=tl->next_tl;
105         }
106
107         /* nothing to delete found */
108         if (tl->prev_tl==&(timer_list->first_tl)) {
109                 ret = NULL;
110         } else { /* we did find timers to be fired! */
111                 /* the detached list begins with current beginning */
112                 ret = timer_list->first_tl.next_tl;
113                 /* and we mark the end of the split list */
114                 tl->prev_tl->next_tl = NULL;
115                 /* the shortened list starts from where we suspended */
116                 timer_list->first_tl.next_tl = tl;      
117                 tl->prev_tl = & timer_list->first_tl;
118         }
119
120    /* give the list lock away */
121    unlock( timer_list->mutex );
122
123    return ret;
124 }
125
126
127
128
129
130 void timer_routine(unsigned int ticks , void * attr)
131 {
132         struct s_table       *hash_table = (struct s_table *)attr;
133         struct timer*          timers= hash_table->timers;
134         struct timer_link  *tl, *tmp_tl;
135         int                           id;
136
137         DBG("%d\n", ticks);
138
139         for( id=0 ; id<NR_OF_TIMER_LISTS ; id++ )
140         {
141                 /* to waste as little time in lock as possible, detach list
142                    with expired items and process them after leaving the
143                    lock
144                 */
145                 tl = check_and_split_time_list( & (hash_table->timers[ id ]), ticks );
146                 /* process items now */
147                 while (tl)
148                 {
149                         /* reset the timer list linkage */
150                         tmp_tl = tl->next_tl;
151                         tl->next_tl = tl->prev_tl =0 ; 
152                         DBG("DEBUG: timer routine: timer[%d] , tl=%p next=%p\n",id,tl,tmp_tl);
153                         timers[id].timeout_handler( tl->payload );
154                         tl = tmp_tl;
155                 }
156         }
157 }
158
159
160