Pārlūkot izejas kodu

- ported stable tm timer race fix (many thanks to Dong Liu for
the initial diagnosis and testing of the patch)

Andrei Pelinescu-Onciul 22 gadi atpakaļ
vecāks
revīzija
068caa24d7
3 mainītis faili ar 47 papildinājumiem un 5 dzēšanām
  1. 7 0
      modules/tm/h_table.c
  2. 33 4
      modules/tm/timer.c
  3. 7 1
      modules/tm/timer.h

+ 7 - 0
modules/tm/h_table.c

@@ -33,6 +33,7 @@
  * 2003-03-30  set_kr for requests only (jiri)
  * 2003-04-04  bug_fix: REQ_IN callback not called for local 
  *             UAC transactions (jiri)
+ * 2003-09-12  timer_link->tg will be set only if EXTRA_DEBUG (andrei)
  */
 
 #include "defs.h"
@@ -174,8 +175,10 @@ struct cell*  build_cell( struct sip_msg* p_msg )
 	memset( new_cell, 0, sizeof( struct cell ) );
 
 	/* UAS */
+#ifdef EXTRA_DEBUG
 	new_cell->uas.response.retr_timer.tg=TG_RT;
 	new_cell->uas.response.fr_timer.tg=TG_FR;
+#endif
 	new_cell->uas.response.fr_timer.payload =
 	new_cell->uas.response.retr_timer.payload = &(new_cell->uas.response);
 	new_cell->uas.response.my_T=new_cell;
@@ -205,8 +208,10 @@ struct cell*  build_cell( struct sip_msg* p_msg )
 		uac=&new_cell->uac[i];
 		uac->request.my_T = new_cell;
 		uac->request.branch = i;
+#ifdef EXTRA_DEBUG
 		uac->request.fr_timer.tg = TG_FR;
 		uac->request.retr_timer.tg = TG_RT;
+#endif
 		uac->request.retr_timer.payload = 
 		uac->request.fr_timer.payload = &uac->request;
 		uac->local_cancel=uac->request;
@@ -226,8 +231,10 @@ struct cell*  build_cell( struct sip_msg* p_msg )
 	new_cell->dele_tl.payload = new_cell;
 	new_cell->relaied_reply_branch   = -1;
 	/* new_cell->T_canceled = T_UNDEFINED; */
+#ifdef EXTRA_DEBUG
 	new_cell->wait_tl.tg=TG_WT;
 	new_cell->dele_tl.tg=TG_DEL;
+#endif
 
 	if (!syn_branch) {
 		if (p_msg) {

+ 33 - 4
modules/tm/timer.c

@@ -120,6 +120,12 @@
 
 
 static struct timer_table *timertable=0;
+static struct timer detached_timer; /* just to have a value to compare with*/
+
+#define DETACHED_LIST (&detached_timer)
+
+#define is_in_timer_list2(_tl) ( (_tl)->timer_list &&  \
+									((_tl)->timer_list!=DETACHED_LIST) )
 
 int noisy_ctimer=0;
 
@@ -299,7 +305,9 @@ inline static void retransmission_handler( void *attr)
 
 	id = r_buf->retr_list;
 	r_buf->retr_list = id < RT_T2 ? id + 1 : RT_T2;
-
+	
+	r_buf->retr_timer.timer_list= NULL; /* set to NULL so that set_timer
+										   will work */
 	set_timer(&(r_buf->retr_timer),id < RT_T2 ? id + 1 : RT_T2 );
 
 	DBG("DEBUG: retransmission_handler : done\n");
@@ -646,7 +654,7 @@ struct timer_link  *check_and_split_time_list( struct timer *timer_list,
 	end = &timer_list->last_tl;
 	tl = timer_list->first_tl.next_tl;
 	while( tl!=end && tl->time_out <= time) {
-		tl->timer_list = NULL;
+		tl->timer_list = DETACHED_LIST;
 		tl=tl->next_tl;
 	}
 
@@ -677,7 +685,11 @@ struct timer_link  *check_and_split_time_list( struct timer *timer_list,
 
 
 
-/* stop timer */
+/* stop timer
+ * WARNING: a reset'ed timer will be lost forever
+ *  (succesive set_timer won't work unless you're lucky
+ *   an catch the race condition, the ideea here is there is no
+ *   guarantee you can do anything after a timer_reset)*/
 void reset_timer( struct timer_link* tl )
 {
 	/* disqualify this timer from execution by setting its time_out
@@ -695,7 +707,14 @@ void reset_timer( struct timer_link* tl )
 
 
 
-/* determine timer length and put on a correct timer list */
+/* determine timer length and put on a correct timer list
+ * WARNING: - don't try to use it to "move" a timer from one list
+ *            to another, you'll run into races
+ *          - reset_timer; set_timer might not work, a reset'ed timer
+ *             has no set_timer guarantee, it might be lost;
+ *             same for an expired timer: only it's handler can
+ *             set it again, an external set_timer has no guarantee
+ */
 void set_timer( struct timer_link *new_tl, enum lists list_id )
 {
 	unsigned int timeout;
@@ -713,9 +732,19 @@ void set_timer( struct timer_link *new_tl, enum lists list_id )
 	list= &(timertable->timers[ list_id ]);
 
 	lock(list->mutex);
+	/* check first if we are on the "detached" timer_routine list,
+	 * if so do nothing, the timer is not valid anymore
+	 * (sideffect: reset_timer ; set_timer is not safe, a reseted timer
+	 *  might be lost, depending on this race condition ) */
+	if (new_tl->timer_list==DETACHED_LIST){
+		LOG(L_CRIT, "WARNING: set_timer called on a \"detached\" timer"
+				" -- ignoring: %p\n", new_tl);
+		goto end;
+	}
 	/* make sure I'm not already on a list */
 	remove_timer_unsafe( new_tl );
 	add_timer_unsafe( list, new_tl, get_ticks()+timeout);
+end:
 	unlock(list->mutex);
 }
 

+ 7 - 1
modules/tm/timer.h

@@ -24,6 +24,11 @@
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+/*
+ * History:
+ * --------
+ *  2003-09-12  timer_link.tg exists only if EXTRA_DEBUG (andrei)
+ */
 
 
 #ifndef _TIMER_H
@@ -39,7 +44,6 @@
 #define TIMER_DELETED	1
 
 
-#define is_in_timer_list2(_tl) ( (_tl)->timer_list )
 
 /* identifiers of timer lists;*/
 /* fixed-timer retransmission lists (benefit: fixed timer$
@@ -63,7 +67,9 @@ typedef struct timer_link
 	volatile unsigned int       time_out;
 	void              *payload;
 	struct timer      *timer_list;
+#ifdef EXTRA_DEBUG
 	enum timer_groups  tg;
+#endif
 }timer_link_type ;