[svn-commits] rmudgett: branch 1.4 r221769 - /branches/1.4/channels/misdn/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Oct 1 18:18:34 CDT 2009


Author: rmudgett
Date: Thu Oct  1 18:18:28 2009
New Revision: 221769

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=221769
Log:
Occasionally losing use of B channels in chan_misdn.

I have not been able to reproduce the problem of losing channels.
However, I have seen in the code a reentrancy problem that might give
these symptoms.

The reentrancy patch does several things:
1) Guards B channel and B channel structure allocation.
2) Makes the B channel structure find routines more precise in locating records.
3) Never leave a B channel allocated if we received cause 44.

The last item may cause temporary outgoing call problems, but they should
clear when the line becomes idle.

(closes issue #15490)
Reported by: slutec18
Patches:
      issue15490_channel_alloc_reentrancy.patch uploaded by rmudgett (license 664)
Tested by: rmudgett, slutec18

(closes issue #15458)
Reported by: FabienToune
Patches:
      issue15458_channel_alloc_reentrancy.patch uploaded by rmudgett (license 664)
Tested by: FabienToune, rmudgett, slutec18

Modified:
    branches/1.4/channels/misdn/isdn_lib.c
    branches/1.4/channels/misdn/isdn_lib_intern.h

Modified: branches/1.4/channels/misdn/isdn_lib.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.4/channels/misdn/isdn_lib.c?view=diff&rev=221769&r1=221768&r2=221769
==============================================================================
--- branches/1.4/channels/misdn/isdn_lib.c (original)
+++ branches/1.4/channels/misdn/isdn_lib.c Thu Oct  1 18:18:28 2009
@@ -500,6 +500,7 @@
 	
 	channel--;
 
+	pthread_mutex_lock(&stack->st_lock);
  	if (dec) {
 		for (i = bnums; i >=0; i--) {
 			if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 D channel ;) and work with chan preselection */
@@ -523,6 +524,7 @@
 	}
 
 	if (!chan) {
+		pthread_mutex_unlock(&stack->st_lock);
 		cb_log (1, stack->port, " !! NO FREE CHAN IN STACK\n");
 		dump_chan_list(stack);
 		bc->out_cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
@@ -530,10 +532,12 @@
 	}	
 
 	if (set_chan_in_stack(stack, chan)<0) {
+		pthread_mutex_unlock(&stack->st_lock);
 		cb_log (0, stack->port, "Channel Already in use:%d\n", chan);
 		bc->out_cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
 		return -1;
 	}
+	pthread_mutex_unlock(&stack->st_lock);
 
 	bc->channel=chan;
 	return 0;
@@ -777,9 +781,9 @@
 	for (i=0; i<=stack->b_num; i++) {
 		if (global_state == MISDN_INITIALIZED)  {
 			cb_event(EVENT_CLEANUP, &stack->bc[i], NULL); 
-			empty_chan_in_stack(stack,i+1);
 			empty_bc(&stack->bc[i]);
 			clean_up_bc(&stack->bc[i]);
+			empty_chan_in_stack(stack, i + 1);
 			stack->bc[i].in_use = 0;
 		}
 		
@@ -1242,6 +1246,8 @@
   
 	msg_queue_init(&stack->downqueue);
 	msg_queue_init(&stack->upqueue);
+
+	pthread_mutex_init(&stack->st_lock, NULL);
   
 	/* query port's requirements */
 	ret = mISDN_get_stack_info(midev, port, buff, sizeof(buff));
@@ -1416,6 +1422,8 @@
 
 	if (stack->upper_id) 
 		mISDN_write_frame(stack->midev, buf, stack->upper_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+
+	pthread_mutex_destroy(&stack->st_lock);
 }
 
 
@@ -1461,8 +1469,11 @@
 static struct misdn_bchannel *find_bc_by_masked_l3id(struct misdn_stack *stack, unsigned long l3id, unsigned long mask)
 {
 	int i;
-	for (i=0; i<=stack->b_num; i++) {
-		if ( (stack->bc[i].l3_id & mask)  ==  (l3id & mask)) return &stack->bc[i] ;
+
+	for (i = 0; i <= stack->b_num; i++) {
+		if (stack->bc[i].in_use && (stack->bc[i].l3_id & mask) == (l3id & mask)) {
+			return &stack->bc[i];
+		}
 	}
 	return stack_holder_find(stack,l3id);
 }
@@ -1471,8 +1482,11 @@
 struct misdn_bchannel *find_bc_by_l3id(struct misdn_stack *stack, unsigned long l3id)
 {
 	int i;
-	for (i=0; i<=stack->b_num; i++) {
-		if (stack->bc[i].l3_id == l3id) return &stack->bc[i] ;
+
+	for (i = 0; i <= stack->b_num; i++) {
+		if (stack->bc[i].in_use && stack->bc[i].l3_id == l3id) {
+			return &stack->bc[i];
+		}
 	}
 	return stack_holder_find(stack,l3id);
 }
@@ -1482,11 +1496,11 @@
 	struct misdn_stack *stack;
 	int i;
 
-	for (stack=glob_mgr->stack_list;
-	     stack;
-	     stack=stack->next) {
-		for (i=0; i<=stack->b_num; i++) {
-			if ( (stack->bc[i].addr&STACK_ID_MASK)==(addr&STACK_ID_MASK) ||  stack->bc[i].layer_id== addr ) {
+	for (stack = glob_mgr->stack_list; stack; stack = stack->next) {
+		for (i = 0; i <= stack->b_num; i++) {
+			if (stack->bc[i].in_use
+				&& ((stack->bc[i].addr & STACK_ID_MASK) == (addr & STACK_ID_MASK)
+					|| stack->bc[i].layer_id == addr)) {
 				return &stack->bc[i];
 			}
 		}
@@ -1500,11 +1514,9 @@
 	struct misdn_stack *stack;
 	int i;
 	
-	for (stack=glob_mgr->stack_list;
-	     stack;
-	     stack=stack->next) {
-		for (i=0; i<=stack->b_num; i++) {
-			if ( stack->bc[i].conf_id==confid ) {
+	for (stack = glob_mgr->stack_list; stack; stack = stack->next) {
+		for (i = 0; i <= stack->b_num; i++) {
+			if (stack->bc[i].in_use && stack->bc[i].conf_id == confid) {
 				return &stack->bc[i];
 			}
 		}
@@ -1518,10 +1530,12 @@
 	struct misdn_stack *stack = find_stack_by_port(port);
 	int i;
 
-	if (!stack) return NULL;	
-	
-	for (i=0; i<=stack->b_num; i++) {
-		if ( stack->bc[i].channel== channel ) {
+	if (!stack) {
+		return NULL;
+	}
+	
+	for (i = 0; i <= stack->b_num; i++) {
+		if (stack->bc[i].in_use && stack->bc[i].channel == channel) {
 			return &stack->bc[i];
 		}
 	}
@@ -1588,7 +1602,9 @@
 				if (!bc->channel)
 					cb_log(0, stack->port, "Any Channel Requested, but we have no more!!\n");
 				else 
-					cb_log(0, stack->port, "Requested Channel Already in Use releasing this call with cause 34!!!!\n");
+					cb_log(0, stack->port,
+						"Requested Channel Already in Use releasing this call with cause %d!!!!\n",
+						bc->out_cause);
 
 				/* when the channel is already in use, we can't
 				 * simply clear it, we need to make sure that 
@@ -1699,6 +1715,7 @@
 /* Empties bc if it's reserved (no SETUP out yet) */
 void misdn_lib_release(struct misdn_bchannel *bc)
 {
+	int channel;
 	struct misdn_stack *stack=get_stack_by_bc(bc);
 
 	if (!stack) {
@@ -1706,11 +1723,12 @@
 		return;
 	}
 	
-	if (bc->channel>0) 
-		empty_chan_in_stack(stack,bc->channel);
-	
+	channel = bc->channel;
 	empty_bc(bc);
 	clean_up_bc(bc);
+	if (channel > 0) {
+		empty_chan_in_stack(stack, channel);
+	}
 	bc->in_use=0;
 }
 
@@ -2753,22 +2771,19 @@
 				bc->cause=tmpcause;
 				bc->out_cause=tmp_out_cause;
 				clean_up_bc(bc);
+				bc->in_use = 0;
 				
 				if (tmpcause == AST_CAUSE_REQUESTED_CHAN_UNAVAIL) {
-					cb_log(0,stack->port,"**** Received CAUSE:%d, so not cleaning up channel %d\n", AST_CAUSE_REQUESTED_CHAN_UNAVAIL, channel);
-					cb_log(0,stack->port,"**** This channel is now no longer available,\nplease try to restart it with 'misdn send restart <port> <channel>'\n");
-					set_chan_in_stack(stack, channel);
-					bc->channel=channel;
+					cb_log(0, stack->port, "**** Received CAUSE:%d, restarting channel %d\n", AST_CAUSE_REQUESTED_CHAN_UNAVAIL, channel);
 					misdn_lib_send_restart(stack->port, channel);
-				} else {
-					if (channel>0)
-						empty_chan_in_stack(stack, channel);
 				}
-				bc->in_use=0;
+				if (channel > 0) {
+					empty_chan_in_stack(stack, channel);
+				}
 			}
 
 			if (event == EVENT_RESTART) {
-				cb_log(0, stack->port, "**** Received RESTART_ACK channel:%d\n", bc->restart_channel);
+				cb_log(0, stack->port, "**** Received RESTART channel:%d\n", bc->restart_channel);
 				empty_chan_in_stack(stack, bc->restart_channel);
 			}
 
@@ -3149,11 +3164,12 @@
 	struct misdn_stack *stack;
 	int i;
   
-	for (stack=glob_mgr->stack_list;
-	     stack;
-	     stack=stack->next) {
-		for (i=0; i<=stack->b_num; i++)
-			if (stack->bc[i].pid == pid) return &stack->bc[i];
+	for (stack = glob_mgr->stack_list; stack; stack = stack->next) {
+		for (i = 0; i <= stack->b_num; i++) {
+			if (stack->bc[i].in_use && stack->bc[i].pid == pid) {
+				return &stack->bc[i];
+			}
+		}
 	}
   
 	return NULL;
@@ -3183,7 +3199,6 @@
 {
 	bc->channel = channel;
 	bc->channel_preselected = channel?1:0;
-	bc->in_use = 1;
 	bc->need_disconnect=1;
 	bc->need_release=1;
 	bc->need_release_complete=1;
@@ -3197,6 +3212,8 @@
 	bc->b_stid=0;
 	bc->layer_id=0;
 #endif
+
+	bc->in_use = 1;
 }
 
 struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, int dec)
@@ -3208,8 +3225,6 @@
 		cb_log(0,port,"Requested channel out of bounds (%d)\n",channel);
 		return NULL;
 	}
-
-	usleep(1000);
 
 	for (stack=glob_mgr->stack_list; stack; stack=stack->next) {
     
@@ -3221,21 +3236,25 @@
 				return NULL;
 			}
 		
+			pthread_mutex_lock(&stack->st_lock);
 			if (channel > 0) {
 				if (channel <= stack->b_num) {
 					for (i = 0; i < stack->b_num; i++) {
 						if ( stack->bc[i].channel == channel) {
 							if (test_inuse(&stack->bc[i])) { 
+								pthread_mutex_unlock(&stack->st_lock);
 								cb_log(0,port,"Requested channel:%d on port:%d is already in use\n",channel, port);
 								return NULL;
 
 							} else {
 								prepare_bc(&stack->bc[i], channel);
+								pthread_mutex_unlock(&stack->st_lock);
 								return &stack->bc[i];
 							}
 						}
 					}
 				} else {
+					pthread_mutex_unlock(&stack->st_lock);
 					cb_log(0,port,"Requested channel:%d is out of bounds on port:%d\n",channel, port);
 					return NULL;
 				}
@@ -3252,6 +3271,7 @@
 							
 						prepare_bc(&stack->bc[i], channel);
 						stack->bc[i].dec=1;
+						pthread_mutex_unlock(&stack->st_lock);
 						return &stack->bc[i];
 					}
 				}
@@ -3263,10 +3283,12 @@
 							stack->bc[i].cw=1;
 
 						prepare_bc(&stack->bc[i], channel);
+						pthread_mutex_unlock(&stack->st_lock);
 						return &stack->bc[i];
 					}
 				}
 			}
+			pthread_mutex_unlock(&stack->st_lock);
 
 			cb_log(1,port,"There is no free channel on port (%d)\n",port);
 			return NULL;
@@ -3849,7 +3871,7 @@
 		/* clean up chan in stack, to be sure we don't think it's
 		 * in use anymore */
 		for (cnt=0; cnt<=stack->b_num; cnt++) {
-			if (stack->bc[cnt].channel == channel) {
+			if (stack->bc[cnt].in_use && stack->bc[cnt].channel == channel) {
 				empty_bc(&stack->bc[cnt]);
 				clean_up_bc(&stack->bc[cnt]);
 				stack->bc[cnt].in_use=0;

Modified: branches/1.4/channels/misdn/isdn_lib_intern.h
URL: http://svnview.digium.com/svn/asterisk/branches/1.4/channels/misdn/isdn_lib_intern.h?view=diff&rev=221769&r1=221768&r2=221769
==============================================================================
--- branches/1.4/channels/misdn/isdn_lib_intern.h (original)
+++ branches/1.4/channels/misdn/isdn_lib_intern.h Thu Oct  1 18:18:28 2009
@@ -55,6 +55,9 @@
 	net_stack_t nst;
 	manager_t mgr;
 	pthread_mutex_t nstlock;
+
+	/*! \brief Stack struct critical section lock. */
+	pthread_mutex_t st_lock;
 
 	/*! \brief D Channel mISDN driver stack ID (Parent stack ID) */
 	int d_stid;
@@ -121,7 +124,7 @@
 	/*! \brief Array of B channels in use (a[0] = B1).  TRUE if B channel in use */
 	int channels[MAX_BCHANS + 1];
 
-	/*! \brief List of holded channels */
+	/*! \brief List of held channels */
 	struct misdn_bchannel *holding;
 
 	/*! \brief Next stack in the list of stacks */




More information about the svn-commits mailing list