bd7ebf2681629cc6102aa38e4f20e1f451d1e72b
[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 void reset_timer_list( struct s_table* hash_table, enum lists list_id)
12 {
13         hash_table->timers[ list_id ].first_tl.next_tl = & (hash_table->timers[ list_id ].last_tl );
14         hash_table->timers[ list_id ].last_tl.prev_tl = & (hash_table->timers[ list_id ].first_tl );
15         hash_table->timers[ list_id ].first_tl.prev_tl = 
16                 hash_table->timers[ list_id ].last_tl.next_tl = NULL;
17         hash_table->timers[ list_id ].last_tl.time_out = -1;
18 }
19
20 void init_timer_list( struct s_table* hash_table, enum lists list_id)
21 {
22         reset_timer_list( hash_table, list_id );
23         init_timerlist_lock( hash_table, list_id );
24 }
25
26 void print_timer_list(struct s_table* hash_table, enum lists list_id)
27 {
28    struct timer* timer_list=&(hash_table->timers[ list_id ]);
29    struct timer_link *tl ;
30
31    tl = timer_list->first_tl.next_tl;
32    while (tl!=& timer_list->last_tl)
33    {
34       DBG("DEBUG: print_timer_list[%d]: %p, next=%p \n",list_id, tl, tl->next_tl);
35       tl = tl->next_tl;
36    }
37 }
38
39 static void remove_from_timer_list_dummy(  struct timer_link* tl )
40 {
41         DBG("DEBUG: remove_from_timer[%d]: %p \n",tl->list->id,tl);
42         tl->prev_tl->next_tl = tl->next_tl;
43         tl->next_tl->prev_tl = tl->prev_tl;
44     tl->next_tl = 0;
45     tl->prev_tl = 0;
46         tl->list = NULL;
47 }
48
49 /* put a new cell into a list nr. list_id within a hash_table;
50   * set initial timeout
51   */
52 void add_to_tail_of_timer_list( struct timer *timer_list, 
53         struct timer_link *tl, unsigned int time_out )
54 {
55         remove_from_timer_list( tl );
56         /* the entire timer list is locked now -- noone else can manipulate it */
57         lock( timer_list->mutex );
58         tl->time_out = time_out;
59         tl->prev_tl = timer_list->last_tl.prev_tl;
60         tl->next_tl = & timer_list->last_tl;
61         timer_list->last_tl.prev_tl = tl;
62         tl->prev_tl->next_tl = tl;
63         tl->list = timer_list;
64         //print_timer_list(hash_table, list_id);
65         /* give the list lock away */
66         unlock( timer_list->mutex );
67         DBG("DEBUG: add_to_tail_of_timer[%d]: %p\n",timer_list->id,tl);
68 }
69
70
71
72
73
74 /* remove a cell from a list nr. list_id within a hash_table;
75 */
76 void remove_from_timer_list( struct timer_link* tl)
77 {
78         ser_lock_t      m;
79
80         if (is_in_timer_list2( tl )) {
81                 m=tl->list->mutex;
82                 /* the entire timer list is locked now -- noone else can manipulate it */
83                 lock( m );
84                 if ( is_in_timer_list2( tl )  ) remove_from_timer_list_dummy( tl );
85                 //print_timer_list(hash_table, list_id);
86                 /* give the list lock away */
87                 unlock( m );
88         }
89 }
90
91
92
93
94 /*
95         detach items passed by the time from timer list
96 */
97 struct timer_link  *check_and_split_time_list( struct timer *timer_list, int time )
98
99 {
100         struct timer_link *tl , *tmp , *end, *ret;
101
102         //DBG("DEBUG : check_and_split_time_list: start\n");
103
104         /* quick check whether it is worth entering the lock */
105         if (timer_list->first_tl.next_tl==&timer_list->last_tl ||
106                 timer_list->first_tl.next_tl->time_out > time )
107                         return NULL;
108
109         /* the entire timer list is locked now -- noone else can manipulate it */
110         lock( timer_list->mutex );
111
112         end = &timer_list->last_tl;
113         tl = timer_list->first_tl.next_tl;
114         while( tl!=end && tl->time_out <= time) tl=tl->next_tl;
115
116         /* nothing to delete found */
117         if (tl->prev_tl==&(timer_list->first_tl)) {
118                 ret = NULL;
119         } else { /* we did find timers to be fired! */
120                 /* the detached list begins with current beginning */
121                 ret = timer_list->first_tl.next_tl;
122                 /* and we mark the end of the split list */
123                 tl->prev_tl->next_tl = NULL;
124                 /* the shortened list starts from where we suspended */
125                 timer_list->first_tl.next_tl = tl;      
126                 tl->prev_tl = & timer_list->first_tl;
127         }
128
129    /* give the list lock away */
130    unlock( timer_list->mutex );
131
132    //DBG("DEBUG : check_and_split_time_list: done, returns %p\n",tl);
133    //print_timer_list(hash_table, list_id);
134    return ret;
135 }
136
137
138
139
140
141 void timer_routine(unsigned int ticks , void * attr)
142 {
143         struct s_table       *hash_table = (struct s_table *)attr;
144         struct timer*          timers= hash_table->timers;
145         struct timer_link  *tl, *tmp_tl;
146         int                           id;
147
148         DBG("%d\n", ticks);
149
150         for( id=0 ; id<NR_OF_TIMER_LISTS ; id++ )
151         {
152                 /* to waste as little time in lock as possible, detach list
153                    with expired items and process them after leaving the
154                    lock
155                 */
156                 tl = check_and_split_time_list( & (hash_table->timers[ id ]), ticks );
157                 /* process items now */
158                 while (tl)
159                 {
160                         /* reset the timer list linkage */
161                         tmp_tl = tl->next_tl;
162                         tl->next_tl = tl->prev_tl =0 ; 
163                         tl->list = NULL;
164                         DBG("DEBUG: timer routine: timer[%d] , tl=%p next=%p\n",id,tl,tmp_tl);
165                         timers[id].timeout_handler( tl->payload );
166                         tl = tmp_tl;
167                 }
168         }
169 }
170
171
172
173 /* deprecated -- too CPU expensive 
174   */
175 /*
176 void insert_into_timer_list( struct s_table* hash_table , 
177         struct timer_link* new_tl, enum lists list_id , unsigned int time_out )
178 {
179    struct timer          *timer_list = &(hash_table->timers[ list_id ]);
180    struct timer_link  *tl;
181
182    // the entire timer list is locked now -- noone else can manipulate it 
183    lock( timer_list->mutex );
184
185    // if the element is already in list->first remove it 
186    if ( is_in_timer_list( new_tl,list_id)  )
187       remove_from_timer_list_dummy( hash_table , new_tl , list_id);
188
189    new_tl->time_out = time_out ;
190    DBG("DEBUG: insert_into_timer[%d]:%d, %p\n",list_id,new_tl->time_out,new_tl);
191     // seeks the position for insertion 
192    for( tl=timer_list->first_tl ; tl && tl->time_out<new_tl->time_out ; tl=tl->next_tl );
193
194    // link it into list
195     if ( tl )
196     {  // insert before tl
197        new_tl->prev_tl = tl->prev_tl;
198        tl->prev_tl = new_tl;
199     }
200    else
201     {  // at the end or empty list 
202        new_tl->prev_tl = timer_list->last_tl;
203        timer_list->last_tl = new_tl;
204     }
205     if (new_tl->prev_tl )
206        new_tl->prev_tl->next_tl = new_tl;
207     else
208        timer_list->first_tl = new_tl;
209     new_tl->next_tl = tl;
210         tl->list_id = list_id;
211
212    //print_timer_list(hash_table, list_id);
213     // give the list lock away 
214
215     unlock( timer_list->mutex );
216 }
217
218
219 */