Browse code

- variable timer fix: variable timers (avps) won't be exteneded anymore in some special situations. Tested with random generated timer values; minimal perfromance impact. Performance maniacs can turn the new code off modparam("tm", "var_timers", 0). Thanks to Bogdan Iancu <bogdan@voice-system.ro> for the excelent bug report.

Andrei Pelinescu-Onciul authored on 25/01/2007 16:14:49
Showing 9 changed files
... ...
@@ -59,7 +59,7 @@ MAIN_NAME=ser
59 59
 VERSION = 0
60 60
 PATCHLEVEL = 9
61 61
 SUBLEVEL = 7
62
-EXTRAVERSION = -pre7
62
+EXTRAVERSION = -pre8
63 63
 
64 64
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
65 65
 OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]")
... ...
@@ -138,7 +138,9 @@ static void cancel_all_branches(struct cell *t)
138 138
 {
139 139
     int i;
140 140
     int reply_recved=0;
141
-    
141
+    int fr_locked;
142
+   
143
+    fr_locked=0;
142 144
     /* cancel pending client transactions, if any */
143 145
     for( i=0 ; i<t->nr_of_outgoings ; i++ ){
144 146
 
... ...
@@ -147,13 +149,23 @@ static void cancel_all_branches(struct cell *t)
147 149
 	    
148 150
 	    /* stop_rb_timers(&t->uac[i].request); */
149 151
 	    reset_timer( &t->uac[i].request.retr_timer );
150
-	    reset_timer( &t->uac[i].request.fr_timer );
152
+	    if (var_timers){
153
+	    	if (fr_locked==0){
154
+			lock_fr_timers();
155
+			fr_locked=1;
156
+	    	}
157
+	    	del_fr_timer_unsafe( &t->uac[i].request.fr_timer );
158
+	    }else{
159
+	    	del_fr_timer( &t->uac[i].request.fr_timer );
160
+	    }
151 161
 	}
152 162
 	else {
153 163
 
154 164
 	    reply_recved++;
155 165
 	}
156 166
     }
167
+    if (fr_locked)
168
+	unlock_fr_timers();
157 169
 
158 170
     if(!reply_recved){
159 171
 	
... ...
@@ -133,10 +133,16 @@ int t_release_transaction( struct cell *trans )
133 133
 {
134 134
 	set_kr(REQ_RLSD);
135 135
 
136
-	reset_timer( & trans->uas.response.fr_timer );
137 136
 	reset_timer( & trans->uas.response.retr_timer );
138
-
139
-	cleanup_uac_timers( trans );
137
+	if (var_timers){
138
+		lock_fr_timers();
139
+			del_fr_timer_unsafe( & trans->uas.response.fr_timer );
140
+			cleanup_uac_timers_unsafe( trans );
141
+		unlock_fr_timers();
142
+	}else{
143
+		del_fr_timer( & trans->uas.response.fr_timer );
144
+		cleanup_uac_timers( trans );
145
+	}
140 146
 	
141 147
 	put_on_wait( trans );
142 148
 	return 1;
... ...
@@ -395,7 +401,7 @@ static inline int avp2timer(unsigned int* timer, int type, int_str name)
395 401
 
396 402
 int fr_avp2timer(unsigned int* timer)
397 403
 {
398
-	if (fr_timer_avp.n!=0)
404
+	if (var_timers && fr_timer_avp.n!=0)
399 405
 		return avp2timer( timer, fr_timer_avp_type, fr_timer_avp);
400 406
 	else
401 407
 		return 1;
... ...
@@ -404,7 +410,7 @@ int fr_avp2timer(unsigned int* timer)
404 410
 
405 411
 int fr_inv_avp2timer(unsigned int* timer)
406 412
 {
407
-	if (fr_inv_timer_avp.n!=0)
413
+	if (var_timers && fr_inv_timer_avp.n!=0)
408 414
 		return avp2timer( timer, fr_inv_timer_avp_type, fr_inv_timer_avp);
409 415
 	else
410 416
 		return 1;
... ...
@@ -349,7 +349,7 @@ void e2e_cancel( struct sip_msg *cancel_msg,
349 349
 				      * retransmission timers
350 350
 				      */
351 351
 				reset_timer(&t_invite->uac[i].request.retr_timer);
352
-				reset_timer(&t_invite->uac[i].request.fr_timer);
352
+				del_fr_timer(&t_invite->uac[i].request.fr_timer);
353 353
 
354 354
 				/* Generate faked reply */
355 355
 				LOCK_REPLIES(t_invite);
... ...
@@ -66,6 +66,7 @@
66 66
  *              the request (bogdan)
67 67
  *  2005-09-01  reverted to the old way of checking response.dst.send_sock
68 68
  *               in t_retransmit_reply & reply_light (andrei)
69
+ *  2006-12-27  replaced reset(fr_timer) with del_fr_timer(...)  (andrei)
69 70
  */
70 71
 
71 72
 
... ...
@@ -947,18 +948,30 @@ void set_final_timer( /* struct s_table *h_table, */ struct cell *t )
947 948
 	put_on_wait(t);
948 949
 }
949 950
 
950
-void cleanup_uac_timers( struct cell *t )
951
+
952
+/* must be called with the FR TIMER list lock held, if
953
+ * var timers are used */
954
+void cleanup_uac_timers_unsafe( struct cell *t )
951 955
 {
952 956
 	int i;
953 957
 
954 958
 	/* reset FR/retransmission timers */
955 959
 	for (i=0; i<t->nr_of_outgoings; i++ )  {
956 960
 		reset_timer( &t->uac[i].request.retr_timer );
957
-		reset_timer( &t->uac[i].request.fr_timer );
961
+		del_fr_timer_unsafe( &t->uac[i].request.fr_timer );
958 962
 	}
959
-	DBG("DEBUG: cleanup_uac_timers: RETR/FR timers reset\n");
960 963
 }
961 964
 
965
+void cleanup_uac_timers( struct cell *t )
966
+{
967
+
968
+	lock_fr_timers();
969
+		cleanup_uac_timers_unsafe(t);
970
+	unlock_fr_timers();
971
+}
972
+
973
+
974
+
962 975
 static int store_reply( struct cell *trans, int branch, struct sip_msg *rpl)
963 976
 {
964 977
 #		ifdef EXTRA_DEBUG
... ...
@@ -1282,7 +1295,7 @@ int reply_received( struct sip_msg  *p_msg )
1282 1295
 		     /* ... then just stop timers */
1283 1296
 		reset_timer( &uac->local_cancel.retr_timer);
1284 1297
 		if ( msg_status >= 200 ) {
1285
-				reset_timer( &uac->local_cancel.fr_timer);
1298
+				del_fr_timer( &uac->local_cancel.fr_timer);
1286 1299
 		}
1287 1300
 		DBG("DEBUG: reply to local CANCEL processed\n");
1288 1301
 		goto done;
... ...
@@ -1294,7 +1307,7 @@ int reply_received( struct sip_msg  *p_msg )
1294 1307
 	
1295 1308
 	     /* stop final response timer only if I got a final response */
1296 1309
 	if ( msg_status >= 200 ) {
1297
-		reset_timer( &uac->request.fr_timer);
1310
+		del_fr_timer(&uac->request.fr_timer);
1298 1311
 	}
1299 1312
 
1300 1313
 	     /* acknowledge negative INVITE replies (do it before detailed
... ...
@@ -125,6 +125,7 @@ enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch,
125 125
 void set_final_timer( /* struct s_table *h_table,*/ struct cell *t );
126 126
 
127 127
 void cleanup_uac_timers( struct cell *t );
128
+void cleanup_uac_timers_unsafe( struct cell *t );
128 129
 
129 130
 void on_negative_reply( struct cell* t, struct sip_msg* msg,
130 131
 	int code, void *param  );
... ...
@@ -98,6 +98,8 @@
98 98
  *  2003-06-27  timers are not unlinked if timerlist is 0 (andrei)
99 99
  *  2004-02-13  t->is_invite, t->local, t->noisy_ctimer replaced;
100 100
  *              timer_link.payload removed (bogdan)
101
+ *  2006-11-27  added del_fr_timer(): fr timers are immediately removed
102
+ *              from the FR* lists (andrei)
101 103
  */
102 104
 
103 105
 #include "defs.h"
... ...
@@ -130,7 +132,8 @@ static struct timer detached_timer; /* just to have a value to compare with*/
130 132
 									((_tl)->timer_list!=DETACHED_LIST) )
131 133
 
132 134
 int noisy_ctimer=0;
133
-
135
+int var_timers=1; /* set to 0 to disable variable timers &&
136
+					timer loading from avps */
134 137
 
135 138
 int timer_group[NR_OF_TIMER_LISTS] = 
136 139
 {
... ...
@@ -322,7 +325,7 @@ inline static void retransmission_handler( struct timer_link *retr_tl )
322 325
 				"request resending (t=%p, %.9s ... )\n", 
323 326
 				r_buf->my_T, r_buf->buffer);
324 327
 			if (SEND_BUFFER( r_buf )==-1) {
325
-				reset_timer( &r_buf->fr_timer );
328
+				del_fr_timer( &r_buf->fr_timer );
326 329
 				fake_reply(r_buf->my_T, r_buf->branch, 503 );
327 330
 				return;
328 331
 			}
... ...
@@ -436,7 +439,17 @@ void cleanup_localcancel_timers( struct cell *t )
436 439
 	int i;
437 440
 	for (i=0; i<t->nr_of_outgoings; i++ )  {
438 441
 		reset_timer(  &t->uac[i].local_cancel.retr_timer );
439
-		reset_timer(  &t->uac[i].local_cancel.fr_timer );
442
+	}
443
+	if (var_timers){
444
+		lock(timertable->timers[FR_TIMER_LIST].mutex);
445
+			for (i=0; i<t->nr_of_outgoings; i++ )  {
446
+				del_fr_timer_unsafe(&t->uac[i].local_cancel.fr_timer);
447
+			}
448
+		unlock(timertable->timers[FR_TIMER_LIST].mutex);
449
+	}else{
450
+		for (i=0; i<t->nr_of_outgoings; i++ )  {
451
+			del_fr_timer(&t->uac[i].local_cancel.fr_timer);
452
+		}
440 453
 	}
441 454
 }
442 455
 
... ...
@@ -510,6 +523,21 @@ struct timer_table *get_timertable()
510 523
 }
511 524
 
512 525
 
526
+
527
+void lock_fr_timers()
528
+{
529
+	lock(timertable->timers[FR_TIMER_LIST].mutex);
530
+}
531
+
532
+
533
+
534
+void unlock_fr_timers()
535
+{
536
+	unlock(timertable->timers[FR_TIMER_LIST].mutex);
537
+}
538
+
539
+
540
+
513 541
 void unlink_timer_lists()
514 542
 {
515 543
 	struct timer_link  *tl, *end, *tmp;
... ...
@@ -778,6 +806,54 @@ void reset_timer( struct timer_link* tl )
778 806
 
779 807
 
780 808
 
809
+/* removes a timer from the FR_TIMER_LIST or FR_INV_TIMER_LIST, unsafe version,
810
+ *  (it allows immediate delete of a fr timer => solves the race with
811
+ *   variables timers inserted after longer deleted timers)
812
+ * WARNING: - don't try to use it to "move" a timer from one list
813
+ *            to another, you'll run into races
814
+ *          - must be calles with FR_TIMER lock held!
815
+ * see del_fr_timer()
816
+ */
817
+void del_fr_timer_unsafe( struct timer_link *tl)
818
+{
819
+	/* check first if var. timers are really used and we  are on  the
820
+	 * "detached" timer_routine list (the fr
821
+	 * handle is executing or  timer_routine prepares to execute it).
822
+	 * if so do nothing, except reseting the timer to TIMER_DELETED
823
+	 *  (just to give us a change at racing with timer_routine, if 
824
+	 *  TIMER_DELETED is set and the fr handle is not already executing =>
825
+	 *   it will not be called anymore)
826
+	 */
827
+	if (var_timers && tl->timer_list!=DETACHED_LIST){
828
+		remove_timer_unsafe(tl); /* safe to call for null list */
829
+	}else{
830
+		reset_timer(tl);
831
+	}
832
+}
833
+
834
+
835
+
836
+/* removes a timer from the FR_TIMER_LIST or FR_INV_TIMER_LIST
837
+ *  (it allows immediate delete of a fr timer => solves the race with
838
+ *   variables timers inserted after longer deleted timers)
839
+ * WARNING: - don't try to use it to "move" a timer from one list
840
+ *            to another, you'll run into races
841
+ */
842
+void del_fr_timer( struct timer_link *tl)
843
+{
844
+	if (var_timers){
845
+		/* the FR lock is common/shared by both FR_INV_TIMER_LIST 
846
+		 * and FR_TIMER_LIST, so we must lock only one of them */
847
+		lock(timertable->timers[FR_TIMER_LIST].mutex);
848
+			del_fr_timer_unsafe(tl);
849
+		unlock(timertable->timers[FR_TIMER_LIST].mutex);
850
+	}else{
851
+		/* use the older faster method */
852
+		reset_timer(tl);
853
+	}
854
+}
855
+
856
+
781 857
 
782 858
 /* determine timer length and put on a correct timer list
783 859
  * WARNING: - don't try to use it to "move" a timer from one list
... ...
@@ -95,7 +95,7 @@ struct timer_table
95 95
 
96 96
 extern int timer_group[NR_OF_TIMER_LISTS];
97 97
 extern unsigned int timer_id2timeout[NR_OF_TIMER_LISTS];
98
-
98
+extern int var_timers;
99 99
 
100 100
 
101 101
 struct timer_table * tm_init_timers();
... ...
@@ -109,6 +109,9 @@ struct timer_link  *check_and_split_time_list( struct timer*, int);
109 109
 */
110 110
 
111 111
 void reset_timer( struct timer_link* tl );
112
+/* remove a timer from FR_TIMER_LIST or FR_INV_TIMER_LIST */
113
+void del_fr_timer( struct timer_link *tl);
114
+void del_fr_timer_unsafe( struct timer_link *tl);
112 115
 /* determine timer length and put on a correct timer list */
113 116
 void set_timer( struct timer_link *new_tl, enum lists list_id, unsigned int* ext_timeout );
114 117
 /* similar to set_timer, except it allows only one-time
... ...
@@ -117,6 +120,8 @@ void set_1timer( struct timer_link *new_tl, enum lists list_id, unsigned int* ex
117 120
 /*void unlink_timers( struct cell *t );*/
118 121
 void timer_routine(unsigned int, void*);
119 122
 
123
+void lock_fr_timers();
124
+void unlock_fr_timers();
120 125
 
121 126
 struct timer_table *get_timertable();
122 127
 
... ...
@@ -274,7 +274,8 @@ static param_export_t params[]={
274 274
 	{"fr_timer_avp",        STR_PARAM, &fr_timer_param                       },
275 275
 	{"fr_inv_timer_avp",    STR_PARAM, &fr_inv_timer_param                   },
276 276
 	{"tw_append",           STR_PARAM|USE_FUNC_PARAM, (void*)parse_tw_append },
277
-        {"pass_provisional_replies", INT_PARAM, &pass_provisional_replies        },
277
+    {"pass_provisional_replies", INT_PARAM, &pass_provisional_replies        },
278
+    {"var_timers",          INT_PARAM, &var_timers                           },
278 279
 	{0,0,0}
279 280
 };
280 281