499bdea25b5d0c275c5228a3a8dc7b736bccff8c
[sip-router] / modules / tm / timer.c
1 /*
2  * $Id$
3  *
4  */
5
6 /* 
7   timer.c is where we implement TM timers. It has been designed
8   for high performance using some techniques of which timer users
9   need to be aware.
10
11         One technique is "fixed-timer-length". We maintain separate 
12         timer lists, all of them include elements of the same time
13         to fire. That allows *appending* new events to the list as
14         opposed to inserting them by time, which is costly due to
15         searching time spent in a mutex. The performance benefit is
16         noticeable. The limitation is you need a new timer list for
17         each new timer length.
18
19         Another technique is the timer process slices off expired elements
20         from the list in a mutex, but executes the timer after the mutex
21         is left. That saves time greatly as whichever process wants to
22         add/remove a timer, it does not have to wait until the current
23         list is processed. However, be aware the timers may hit in a delayed
24         manner; you have no guarantee in your process that after resetting a timer, 
25         it will no more hit. It might have been removed by timer process,
26     and is waiting to be executed.  The following example shows it:
27
28                         PROCESS1                                TIMER PROCESS
29
30         0.                                                              timer hits, it is removed from queue and
31                                                                         about to be executed
32         1.      process1 decides to
33                 reset the timer 
34         2.                                                              timer is executed now
35         3.      if the process1 naively
36                 thinks the timer could not 
37                 have been executed after 
38                 resetting the timer, it is
39                 WRONG -- it was (step 2.)
40
41         So be careful when writing the timer handlers. Currently defined timers 
42         don't hurt if they hit delayed, I hope at least. Retransmission timer 
43         may results in a useless retransmission -- not too bad. FR timer not too
44         bad either as timer processing uses a REPLY mutex making it safe to other
45         processing affecting transaction state. Wait timer not bad either -- processes
46         putting a transaction on wait don't do anything with it anymore.
47
48                 Example when it does not hurt:
49
50                         P1                                              TIMER
51         0.                                                              RETR timer removed from list and
52                                                                         scheduled for execution
53         1. 200/BYE received->
54            reset RETR, put_on_wait
55         2.                                                              RETR timer executed -- too late but it does
56                                                                         not hurt
57         3.                                                              WAIT handler executed
58
59         The rule of thumb is don't touch data you put under a timer. Create data,
60     put them under a timer, and let them live until they are safely destroyed from
61     wait/delete timer.  The only safe place to manipulate the data is 
62     from timer process in which delayed timers cannot hit (all timers are
63     processed sequentially).
64
65         A "bad example" -- rewriting content of retransmission buffer
66         in an unprotected way is bad because a delayed retransmission timer might 
67         hit. Thats why our reply retransmission procedure is enclosed in 
68         a REPLY_LOCK.
69
70 */
71
72
73 #include "config.h"
74 #include "h_table.h"
75 #include "timer.h"
76 #include "../../dprint.h"
77 #include "lock.h"
78 #include "t_stats.h"
79
80 #include "../../hash_func.h"
81 #include "../../dprint.h"
82 #include "../../config.h"
83 #include "../../parser/parser_f.h"
84 #include "../../ut.h"
85 #include "t_funcs.h"
86 #include "t_reply.h"
87 #include "t_cancel.h"
88
89
90 static struct timer_table *timertable;
91
92 int noisy_ctimer=0;
93
94
95 int timer_group[NR_OF_TIMER_LISTS] = 
96 {
97         TG_FR, TG_FR,
98         TG_WT,
99         TG_DEL,
100         TG_RT, TG_RT, TG_RT, TG_RT
101 };
102
103 /* default values of timeouts for all the timer list
104    (see timer.h for enumeration of timer lists)
105 */
106 unsigned int timer_id2timeout[NR_OF_TIMER_LISTS] = {
107         FR_TIME_OUT,            /* FR_TIMER_LIST */
108         INV_FR_TIME_OUT,        /* FR_INV_TIMER_LIST */
109         WT_TIME_OUT,            /* WT_TIMER_LIST */
110         DEL_TIME_OUT,           /* DELETE_LIST */
111         RETR_T1,                        /* RT_T1_TO_1 */
112         RETR_T1 << 1,           /* RT_T1_TO_2 */
113         RETR_T1 << 2,           /* RT_T1_TO_3 */
114         RETR_T2                         /* RT_T2 */
115                                                 /* NR_OF_TIMER_LISTS */
116 };
117
118 /******************** handlers ***************************/
119
120
121
122 static void delete_cell( struct cell *p_cell, int unlock )
123 {
124
125 #ifdef EXTRA_DEBUG
126         int i;
127 #endif
128
129         /* there may still be FR/RETR timers, which have been reset
130            (i.e., time_out==TIMER_DELETED) but are stilled linked to
131            timer lists and must be removed from there before the
132            structures are released
133         */
134         unlink_timers( p_cell );
135
136 #ifdef EXTRA_DEBUG
137
138         if (is_in_timer_list2(& p_cell->wait_tl )) {
139                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
140                         " still on WAIT, timeout=%d\n", p_cell, p_cell->wait_tl.time_out);
141                 abort();
142         }
143         if (is_in_timer_list2(& p_cell->uas.response.retr_timer )) {
144                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
145                         " still on RETR (rep), timeout=%d\n",
146                         p_cell, p_cell->uas.response.retr_timer.time_out);
147                 abort();
148         }
149         if (is_in_timer_list2(& p_cell->uas.response.fr_timer )) {
150                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
151                         " still on FR (rep), timeout=%d\n", p_cell,
152                         p_cell->uas.response.fr_timer.time_out);
153                 abort();
154         }
155         for (i=0; i<p_cell->nr_of_outgoings; i++) {
156                 if (is_in_timer_list2(& p_cell->uac[i].request.retr_timer)) {
157                         LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
158                                 " still on RETR (req %d), timeout %d\n", p_cell, i,
159                                 p_cell->uac[i].request.retr_timer.time_out);
160                         abort();
161                 }
162                 if (is_in_timer_list2(& p_cell->uac[i].request.fr_timer)) {
163                         LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
164                                 " still on FR (req %d), timeout %d\n", p_cell, i,
165                                 p_cell->uac[i].request.fr_timer.time_out);
166                         abort();
167                 }
168                 if (is_in_timer_list2(& p_cell->uac[i].local_cancel.retr_timer)) {
169                         LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
170                                 " still on RETR/cancel (req %d), timeout %d\n", p_cell, i,
171                                 p_cell->uac[i].request.retr_timer.time_out);
172                         abort();
173                 }
174                 if (is_in_timer_list2(& p_cell->uac[i].local_cancel.fr_timer)) {
175                         LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
176                                 " still on FR/cancel (req %d), timeout %d\n", p_cell, i,
177                                 p_cell->uac[i].request.fr_timer.time_out);
178                         abort();
179                 }
180         }
181         /* reset_retr_timers( hash__XX_table, p_cell ); */
182 #endif
183         /* still in use ... don't delete */
184         if ( IS_REFFED_UNSAFE(p_cell) ) {
185                 if (unlock) UNLOCK_HASH(p_cell->hash_index);
186                 DBG("DEBUG: delete_cell %p: can't delete -- still reffed\n",
187                         p_cell);
188                 /* it's added to del list for future del */
189                 set_timer( &(p_cell->dele_tl), DELETE_LIST );
190         } else {
191                 if (unlock) UNLOCK_HASH(p_cell->hash_index);
192                 DBG("DEBUG: delete transaction %p\n", p_cell );
193                 free_cell( p_cell );
194         }
195 }
196
197 static void fake_reply(struct cell *t, int branch, int code )
198 {
199         branch_bm_t cancel_bitmap;
200         short do_cancel_branch;
201         enum rps reply_status;
202
203         do_cancel_branch=t->is_invite && should_cancel_branch(t, branch);
204
205         cancel_bitmap=do_cancel_branch ? 1<<branch : 0;
206         if (t->local) {
207                 reply_status=local_reply( t, FAKED_REPLY, branch, 
208                         code, &cancel_bitmap );
209         } else {
210                 reply_status=relay_reply( t, FAKED_REPLY, branch, code,
211                         &cancel_bitmap );
212         }
213         /* now when out-of-lock do the cancel I/O */
214         if (do_cancel_branch) cancel_branch(t, branch );
215         /* it's cleaned up on error; if no error occured and transaction
216            completed regularly, I have to clean-up myself
217         */
218         if (reply_status==RPS_COMPLETED) {
219                 /* don't need to cleanup uac_timers -- they were cleaned
220                    branch by branch and this last branch's timers are
221                    reset now too
222                 */
223                 /* don't need to issue cancels -- local cancels have been
224                    issued branch by branch and this last branch was
225                    cancelled now too
226                 */
227                 /* then the only thing to do now is to put the transaction
228                    on FR/wait state 
229                 */
230                 set_final_timer(  t );
231         }
232 }
233
234
235 inline static void retransmission_handler( void *attr)
236 {
237         struct retr_buf* r_buf ;
238         enum lists id;
239
240         r_buf = (struct retr_buf*)attr;
241 #ifdef EXTRA_DEBUG
242         if (r_buf->my_T->damocles) {
243                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
244                         " called from RETR timer\n",r_buf->my_T);
245                 abort();
246         }       
247 #endif
248
249         /*the transaction is already removed from RETRANSMISSION_LIST by timer*/
250         /* retransmision */
251         if ( r_buf->activ_type==TYPE_LOCAL_CANCEL 
252                 || r_buf->activ_type==0 ) {
253                         DBG("DEBUG: retransmission_handler : "
254                                 "request resending (t=%p, %.9s ... )\n", 
255                                 r_buf->my_T, r_buf->buffer);
256                         if (SEND_BUFFER( r_buf )<=0) {
257                                 reset_timer( &r_buf->fr_timer );
258                                 fake_reply(r_buf->my_T, r_buf->branch, 503 );
259                                 return;
260                         }
261         } else {
262                         DBG("DEBUG: retransmission_handler : "
263                                 "reply resending (t=%p, %.9s ... )\n", 
264                                 r_buf->my_T, r_buf->buffer);
265                         t_retransmit_reply(r_buf->my_T);
266         }
267
268         id = r_buf->retr_list;
269         r_buf->retr_list = id < RT_T2 ? id + 1 : RT_T2;
270
271         set_timer(&(r_buf->retr_timer),id < RT_T2 ? id + 1 : RT_T2 );
272
273         DBG("DEBUG: retransmission_handler : done\n");
274 }
275
276
277
278
279 inline static void final_response_handler( void *attr)
280 {
281         int silent;
282         struct retr_buf* r_buf;
283         struct cell *t;
284
285         r_buf = (struct retr_buf*)attr;
286         t=r_buf->my_T;
287
288 #       ifdef EXTRA_DEBUG
289         if (t->damocles) 
290         {
291                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
292                         " called from FR timer\n",r_buf->my_T);
293                 abort();
294         }
295 #       endif
296
297         reset_timer(  &(r_buf->retr_timer) );
298
299         /* the transaction is already removed from FR_LIST by the timer */
300
301         /* FR for local cancels.... */
302         if (r_buf->activ_type==TYPE_LOCAL_CANCEL)
303         {
304                 DBG("DEBUG: FR_handler: stop retr for Local Cancel\n");
305                 return;
306         }
307
308         /* FR for replies (negative INVITE replies) */
309         if (r_buf->activ_type>0) {
310 #               ifdef EXTRA_DEBUG
311                 if (t->uas.request->REQ_METHOD!=METHOD_INVITE
312                         || t->uas.status < 300 ) {
313                         LOG(L_ERR, "ERROR: FR timer: uknown type reply buffer\n");
314                         abort();
315                 }
316 #               endif
317                 put_on_wait( t );
318                 return;
319         };
320
321         /* lock reply processing to determine how to proceed reliably */
322         LOCK_REPLIES( t );
323         /* now it can be only a request retransmission buffer;
324            try if you can simply discard the local transaction 
325            state without compellingly removing it from the
326            world */
327         silent=
328                 /* not for UACs */
329                 !t->local
330                 /* invites only */
331                 && t->is_invite
332                 /* parallel forking does not allow silent state discarding */
333                 && t->nr_of_outgoings==1
334                 /* on_no_reply handler not installed -- serial forking could occur 
335                    otherwise */
336                 && t->on_negative==0
337                 /* something received -- we will not be silent on error */
338                 && t->uac[r_buf->branch].last_received>0
339                 /* don't go silent if disallowed globally ... */
340                 && noisy_ctimer==0
341                 /* ... or for this particular transaction */
342                 && t->noisy_ctimer==0;
343         if (silent) {
344                 UNLOCK_REPLIES(t);
345                 DBG("DEBUG: FR_handler: transaction silently dropped (%p)\n",t);
346                 put_on_wait( t );
347                 return;
348         }
349
350         DBG("DEBUG: FR_handler:stop retr. and send CANCEL (%p)\n", t);
351         fake_reply(t, r_buf->branch, 408 );
352
353         DBG("DEBUG: final_response_handler : done\n");
354 }
355
356 void cleanup_localcancel_timers( struct cell *t )
357 {
358         int i;
359         for (i=0; i<t->nr_of_outgoings; i++ )  {
360                 reset_timer(  &t->uac[i].local_cancel.retr_timer );
361                 reset_timer(  &t->uac[i].local_cancel.fr_timer );
362         }
363 }
364
365
366 inline static void wait_handler( void *attr)
367 {
368         struct cell *p_cell = (struct cell*)attr;
369
370 #ifdef EXTRA_DEBUG
371         if (p_cell->damocles) {
372                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
373                         " called from WAIT timer\n",p_cell);
374                 abort();
375         }       
376         DBG("DEBUG: ---------- WAIT timer hit ------- \n");
377 #endif
378
379         /* stop cancel timers if any running */
380         if (p_cell->is_invite) cleanup_localcancel_timers( p_cell );
381
382         /* the transaction is already removed from WT_LIST by the timer */
383         /* remove the cell from the hash table */
384         DBG("DEBUG: wait_handler : removing %p from table \n", p_cell );
385         LOCK_HASH( p_cell->hash_index );
386         remove_from_hash_table_unsafe(  p_cell );
387         /* jku: no more here -- we do it when we put a transaction on wait */
388 #ifdef EXTRA_DEBUG
389         p_cell->damocles = 1;
390 #endif
391         /* delete (returns with UNLOCK-ed_HASH) */
392         delete_cell( p_cell, 1 /* unlock on return */ );
393         DBG("DEBUG: wait_handler : done\n");
394 }
395
396
397
398
399 inline static void delete_handler( void *attr)
400 {
401         struct cell *p_cell = (struct cell*)attr;
402
403         DBG("DEBUG: delete_handler : removing %p \n", p_cell );
404 #ifdef EXTRA_DEBUG
405         if (p_cell->damocles==0) {
406                 LOG( L_ERR, "ERROR: transaction %p not scheduled for deletion"
407                         " and called from DELETE timer\n",p_cell);
408                 abort();
409         }       
410 #endif
411
412         /* we call delete now without any locking on hash/ref_count;
413            we can do that because delete_handler is only entered after
414            the delete timer was installed from wait_handler, which
415            removed transaction from hash table and did not destroy it
416            because some processes were using it; that means that the
417            processes currently using the transaction can unref and no
418            new processes can ref -- we can wait until ref_count is
419            zero safely without locking
420         */
421         delete_cell( p_cell, 0 /* don't unlock on return */ );
422     DBG("DEBUG: delete_handler : done\n");
423 }
424
425
426 /***********************************************************/
427
428 struct timer_table *get_timertable()
429 {
430         return timertable;
431 }
432
433
434 void unlink_timer_lists()
435 {
436         struct timer_link  *tl, *end, *tmp;
437         enum lists i;
438
439         /* remember the DELETE LIST */
440         tl = timertable->timers[DELETE_LIST].first_tl.next_tl;
441         end = & timertable->timers[DELETE_LIST].last_tl;
442         /* unlink the timer lists */
443         for( i=0; i<NR_OF_TIMER_LISTS ; i++ )
444                 reset_timer_list( i );
445         DBG("DEBUG: tm_shutdown : empting DELETE list\n");
446         /* deletes all cells from DELETE_LIST list 
447            (they are no more accessible from enrys) */
448         while (tl!=end) {
449                 tmp=tl->next_tl;
450                 free_cell((struct cell*)tl->payload);
451                 tl=tmp;
452         }
453         
454 }
455
456 struct timer_table *tm_init_timers()
457 {
458         enum lists i;
459
460         timertable=(struct timer_table *) shm_malloc(sizeof(struct timer_table));
461         if (!timertable) {
462                 LOG(L_ERR, "ERROR: tm_init_timers: no shmem for timer_Table\n");
463                 goto error0;
464         }
465         memset(timertable, 0, sizeof (struct timer_table));
466                 
467
468         /* inits the timers*/
469         for(  i=0 ; i<NR_OF_TIMER_LISTS ; i++ )
470         init_timer_list( i );
471     
472     /* init. timer lists */
473         timertable->timers[RT_T1_TO_1].id = RT_T1_TO_1;
474         timertable->timers[RT_T1_TO_2].id = RT_T1_TO_2;
475         timertable->timers[RT_T1_TO_3].id = RT_T1_TO_3;
476         timertable->timers[RT_T2].id      = RT_T2;
477         timertable->timers[FR_TIMER_LIST].id     = FR_TIMER_LIST; 
478         timertable->timers[FR_INV_TIMER_LIST].id = FR_INV_TIMER_LIST;
479         timertable->timers[WT_TIMER_LIST].id     = WT_TIMER_LIST;
480         timertable->timers[DELETE_LIST].id       = DELETE_LIST;
481
482         return timertable;
483
484 error0:
485         return 0;
486 }
487
488 void free_timer_table()
489 {
490         enum lists i;
491
492         if (timertable) {
493                 /* the mutexs for sync the lists are released*/
494                 for ( i=0 ; i<NR_OF_TIMER_LISTS ; i++ )
495                         release_timerlist_lock( &timertable->timers[i] );
496                 shm_free(timertable);
497         }
498                 
499 }
500
501 void reset_timer_list( enum lists list_id)
502 {
503         timertable->timers[list_id].first_tl.next_tl =
504                 &(timertable->timers[list_id].last_tl );
505         timertable->timers[list_id].last_tl.prev_tl =
506                 &(timertable->timers[list_id].first_tl );
507         timertable->timers[list_id].first_tl.prev_tl =
508                 timertable->timers[list_id].last_tl.next_tl = NULL;
509         timertable->timers[list_id].last_tl.time_out = -1;
510 }
511
512
513
514
515 void init_timer_list( /* struct s_table* ht, */ enum lists list_id)
516 {
517         reset_timer_list( /* ht, */ list_id );
518         init_timerlist_lock( /* ht, */ list_id );
519 }
520
521
522
523
524 void print_timer_list( enum lists list_id)
525 {
526         struct timer* timer_list=&(timertable->timers[ list_id ]);
527         struct timer_link *tl ;
528
529         tl = timer_list->first_tl.next_tl;
530         while (tl!=& timer_list->last_tl)
531         {
532                 DBG("DEBUG: print_timer_list[%d]: %p, next=%p \n",
533                         list_id, tl, tl->next_tl);
534                 tl = tl->next_tl;
535         }
536 }
537
538
539
540
541 void remove_timer_unsafe(  struct timer_link* tl )
542 {
543 #ifdef EXTRA_DEBUG
544         if (tl && tl->timer_list &&
545                 tl->timer_list->last_tl.prev_tl==0) {
546                 LOG( L_CRIT,
547                 "CRITICAL : Oh no, zero link in trailing timer element\n");
548                 abort();
549         };
550 #endif
551         if (is_in_timer_list2( tl )) {
552 #ifdef EXTRA_DEBUG
553                 DBG("DEBUG: unlinking timer: tl=%p, timeout=%d, group=%d\n", 
554                         tl, tl->time_out, tl->tg);
555 #endif
556                 tl->prev_tl->next_tl = tl->next_tl;
557                 tl->next_tl->prev_tl = tl->prev_tl;
558                 tl->next_tl = 0;
559                 tl->prev_tl = 0;
560                 tl->timer_list = NULL;
561         }
562 }
563
564
565
566
567 /* put a new cell into a list nr. list_id */
568 void add_timer_unsafe( struct timer *timer_list, struct timer_link *tl,
569         unsigned int time_out )
570 {
571 #ifdef EXTRA_DEBUG
572         if (timer_list->last_tl.prev_tl==0) {
573         LOG( L_CRIT,
574                 "CRITICAL : Oh no, zero link in trailing timer element\n");
575                 abort();
576         };
577 #endif
578
579         tl->time_out = time_out;
580         tl->prev_tl = timer_list->last_tl.prev_tl;
581         tl->next_tl = & timer_list->last_tl;
582         timer_list->last_tl.prev_tl = tl;
583         tl->prev_tl->next_tl = tl;
584         tl->timer_list = timer_list;
585 #ifdef EXTRA_DEBUG
586         if ( tl->tg != timer_group[ timer_list->id ] ) {
587                 LOG( L_CRIT, "CRITICAL error: changing timer group\n");
588                 abort();
589         }
590 #endif
591         DBG("DEBUG: add_to_tail_of_timer[%d]: %p\n",timer_list->id,tl);
592 }
593
594
595
596
597 /* detach items passed by the time from timer list */
598 struct timer_link  *check_and_split_time_list( struct timer *timer_list,
599         int time )
600 {
601         struct timer_link *tl , *end, *ret;
602
603
604         /* quick check whether it is worth entering the lock */
605         if (timer_list->first_tl.next_tl==&timer_list->last_tl 
606                         || ( /* timer_list->first_tl.next_tl
607                                 && */ timer_list->first_tl.next_tl->time_out > time) )
608                 return NULL;
609
610         /* the entire timer list is locked now -- noone else can manipulate it */
611         lock(timer_list->mutex);
612
613         end = &timer_list->last_tl;
614         tl = timer_list->first_tl.next_tl;
615         while( tl!=end && tl->time_out <= time) {
616                 tl->timer_list = NULL;
617                 tl=tl->next_tl;
618         }
619
620         /* nothing to delete found */
621         if (tl->prev_tl==&(timer_list->first_tl)) {
622                 ret = NULL;
623         } else { /* we did find timers to be fired! */
624                 /* the detached list begins with current beginning */
625                 ret = timer_list->first_tl.next_tl;
626                 /* and we mark the end of the split list */
627                 tl->prev_tl->next_tl = NULL;
628                 /* the shortened list starts from where we suspended */
629                 timer_list->first_tl.next_tl = tl;      
630                 tl->prev_tl = & timer_list->first_tl;
631         }
632 #ifdef EXTRA_DEBUG
633         if (timer_list->last_tl.prev_tl==0) {
634                 LOG( L_CRIT,
635                 "CRITICAL : Oh no, zero link in trailing timer element\n");
636                 abort();
637         };
638 #endif
639         /* give the list lock away */
640         unlock(timer_list->mutex);
641
642         return ret;
643 }
644
645
646
647 /* stop timer */
648 void reset_timer( struct timer_link* tl )
649 {
650         /* disqualify this timer from execution by setting its time_out
651            to zero; it will stay in timer-list until the timer process
652            starts removing outdated elements; then it will remove it
653            but not execute; there is a race condition, though -- see
654            timer.c for more details
655         */
656         tl->time_out = TIMER_DELETED;
657 #ifdef EXTRA_DEBUG
658         DBG("DEBUG: reset_timer (group %d, tl=%p)\n", tl->tg, tl );
659 #endif
660 #ifdef _OBSOLETED
661         /* lock(timer_group_lock[ tl->tg ]); */
662         /* hack to work arround this timer group thing*/
663         lock(hash__XX_table->timers[timer_group[tl->tg]].mutex);
664         remove_timer_unsafe( tl );
665         unlock(hash_XX_table->timers[timer_group[tl->tg]].mutex);
666         /*unlock(timer_group_lock[ tl->tg ]);*/
667 #endif
668 }
669
670
671
672
673 /* determine timer length and put on a correct timer list */
674 void set_timer( struct timer_link *new_tl, enum lists list_id )
675 {
676         unsigned int timeout;
677         struct timer* list;
678
679
680         if (list_id<FR_TIMER_LIST || list_id>=NR_OF_TIMER_LISTS) {
681                 LOG(L_CRIT, "ERROR: set_timer: unkown list: %d\n", list_id);
682 #ifdef EXTRA_DEBUG
683                 abort();
684 #endif
685                 return;
686         }
687         timeout = timer_id2timeout[ list_id ];
688         list= &(timertable->timers[ list_id ]);
689
690         lock(list->mutex);
691         /* make sure I'm not already on a list */
692         remove_timer_unsafe( new_tl );
693         add_timer_unsafe( list, new_tl, get_ticks()+timeout);
694         unlock(list->mutex);
695 }
696
697 /* similar to set_timer, except it allows only one-time
698    timer setting and all later attempts are ignored */
699 void set_1timer( struct timer_link *new_tl, enum lists list_id )
700 {
701         unsigned int timeout;
702         struct timer* list;
703
704
705         if (list_id<FR_TIMER_LIST || list_id>=NR_OF_TIMER_LISTS) {
706                 LOG(L_CRIT, "ERROR: set_timer: unkown list: %d\n", list_id);
707 #ifdef EXTRA_DEBUG
708                 abort();
709 #endif
710                 return;
711         }
712         timeout = timer_id2timeout[ list_id ];
713         list= &(timertable->timers[ list_id ]);
714
715         lock(list->mutex);
716         if (!(new_tl->time_out>TIMER_DELETED)) {
717                 /* make sure I'm not already on a list */
718                 /* remove_timer_unsafe( new_tl ); */
719                 add_timer_unsafe( list, new_tl, get_ticks()+timeout);
720
721                 /* set_1timer is used only by WAIT -- that's why we can
722                    afford updating wait statistics; I admit its not nice
723                    but it greatly utilizes existing lock 
724                 */
725                 cur_stats->waiting++;acc_stats->waiting++;
726         }
727         unlock(list->mutex);
728 }
729
730
731 void unlink_timers( struct cell *t )
732 {
733         int i;
734         int remove_fr, remove_retr;
735
736         remove_fr=0; remove_retr=0;
737
738         /* first look if we need to remove timers and play with
739            costly locks at all
740
741             note that is_in_timer_list2 is unsafe but it does not
742             hurt -- transaction is already dead (wait state) so that
743             noone else will install a FR/RETR timer and it can only
744             be removed from timer process itself -> it is safe to
745             use it without any protection
746         */
747         if (is_in_timer_list2(&t->uas.response.fr_timer)) remove_fr=1; 
748         else for (i=0; i<t->nr_of_outgoings; i++)
749                 if (is_in_timer_list2(&t->uac[i].request.fr_timer)
750                         || is_in_timer_list2(&t->uac[i].local_cancel.fr_timer)) {
751                                 remove_fr=1;
752                                 break;
753                 }
754         if (is_in_timer_list2(&t->uas.response.retr_timer)) remove_retr=1; 
755         else for (i=0; i<t->nr_of_outgoings; i++)
756                 if (is_in_timer_list2(&t->uac[i].request.retr_timer)
757                         || is_in_timer_list2(&t->uac[i].local_cancel.retr_timer)) {
758                                 remove_retr=1;
759                                 break;
760                 }
761
762         /* do what we have to do....*/
763         if (remove_retr) {
764                 /* RT_T1 lock is shared by all other RT timer
765                    lists -- we can safely lock just one
766                 */
767                 lock(timertable->timers[RT_T1_TO_1].mutex);
768                 remove_timer_unsafe(&t->uas.response.retr_timer);
769                 for (i=0; i<t->nr_of_outgoings; i++) {
770                         remove_timer_unsafe(&t->uac[i].request.retr_timer);
771                         remove_timer_unsafe(&t->uac[i].local_cancel.retr_timer);
772                 }
773                 unlock(timertable->timers[RT_T1_TO_1].mutex);
774         }
775         if (remove_fr) {
776                 /* FR lock is shared by all other FR timer
777                    lists -- we can safely lock just one
778                 */
779                 lock(timertable->timers[FR_TIMER_LIST].mutex);
780                 remove_timer_unsafe(&t->uas.response.fr_timer);
781                 for (i=0; i<t->nr_of_outgoings; i++) {
782                         remove_timer_unsafe(&t->uac[i].request.fr_timer);
783                         remove_timer_unsafe(&t->uac[i].local_cancel.fr_timer);
784                 }
785                 unlock(timertable->timers[FR_TIMER_LIST].mutex);
786         }
787 }
788
789
790
791
792 #define run_handler_for_each( _tl , _handler ) \
793         while ((_tl))\
794         {\
795                 /* reset the timer list linkage */\
796                 tmp_tl = (_tl)->next_tl;\
797                 (_tl)->next_tl = (_tl)->prev_tl = 0;\
798                 DBG("DEBUG: timer routine:%d,tl=%p next=%p\n",\
799                         id,(_tl),tmp_tl);\
800                 if ((_tl)->time_out>TIMER_DELETED) \
801                         (_handler)( (_tl)->payload );\
802                 (_tl) = tmp_tl;\
803         }
804
805
806
807
808 void timer_routine(unsigned int ticks , void * attr)
809 {
810         /* struct timer_table *tt= (struct timer_table*)attr; */
811         struct timer_link *tl, *tmp_tl;
812         int                id;
813
814 #ifdef BOGDAN_TRIFLE
815         DBG(" %d \n",ticks);
816 #endif
817
818         for( id=0 ; id<NR_OF_TIMER_LISTS ; id++ )
819         {
820                 /* to waste as little time in lock as possible, detach list
821                    with expired items and process them after leaving the lock */
822                 tl=check_and_split_time_list( &timertable->timers[ id ], ticks);
823                 /* process items now */
824                 switch (id)
825                 {
826                         case FR_TIMER_LIST:
827                         case FR_INV_TIMER_LIST:
828                                 run_handler_for_each(tl,final_response_handler);
829                                 break;
830                         case RT_T1_TO_1:
831                         case RT_T1_TO_2:
832                         case RT_T1_TO_3:
833                         case RT_T2:
834                                 run_handler_for_each(tl,retransmission_handler);
835                                 break;
836                         case WT_TIMER_LIST:
837                                 run_handler_for_each(tl,wait_handler);
838                                 break;
839                         case DELETE_LIST:
840                                 run_handler_for_each(tl,delete_handler);
841                                 break;
842                 }
843         }
844 }
845