[asterisk-commits] jpeeler: branch 1.4 r218401 - /branches/1.4/channels/chan_dahdi.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Sep 14 16:47:17 CDT 2009


Author: jpeeler
Date: Mon Sep 14 16:47:11 2009
New Revision: 218401

URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=218401
Log:
Fix handling of DAHDI_EVENT_REMOVED event to prevent crash in do_monitor.

After talking to rmudgett about some of his recent iflist locking changes, it
was determined that the only place that would destroy a channel without being
explicitly to do so was in handle_init_event. The loop to walk the interface
list has been modified to wait to destroy the channel until the dahdi_pvt of
the channel to be destroyed is no longer needed.

(closes issue #15378)
Reported by: samy

Modified:
    branches/1.4/channels/chan_dahdi.c

Modified: branches/1.4/channels/chan_dahdi.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.4/channels/chan_dahdi.c?view=diff&rev=218401&r1=218400&r2=218401
==============================================================================
--- branches/1.4/channels/chan_dahdi.c (original)
+++ branches/1.4/channels/chan_dahdi.c Mon Sep 14 16:47:11 2009
@@ -7029,22 +7029,25 @@
 	struct dahdi_pvt *tmp = NULL;
 	struct dahdi_pvt *prev = NULL;
 
+	ast_mutex_lock(&iflock);
 	tmp = iflist;
 	while (tmp) {
 		if (tmp->channel == channel) {
 			int x = DAHDI_FLASH;
 			ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); /* important to create an event for dahdi_wait_event to register so that all ss_threads terminate */
 			destroy_channel(prev, tmp, 1);
+			ast_mutex_unlock(&iflock);
 			ast_module_unref(ast_module_info->self);
 			return RESULT_SUCCESS;
 		}
 		prev = tmp;
 		tmp = tmp->next;
 	}
+	ast_mutex_unlock(&iflock);
 	return RESULT_FAILURE;
 }
 
-static int handle_init_event(struct dahdi_pvt *i, int event)
+static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 {
 	int res;
 	pthread_t threadid;
@@ -7143,7 +7146,7 @@
 			res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
 			if (res < 0)
 					ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
-			return -1;
+			return NULL;
 		}
 		break;
 	case DAHDI_EVENT_NOALARM:
@@ -7209,7 +7212,7 @@
 		default:
 			ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
 			res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
-			return -1;
+			return NULL;
 		}
 		break;
 	case DAHDI_EVENT_POLARITY:
@@ -7241,15 +7244,14 @@
 				"interface %d\n", i->channel);
 		}
 		break;
-	case DAHDI_EVENT_REMOVED: /* destroy channel */
+	case DAHDI_EVENT_REMOVED: /* destroy channel, will actually do so in do_monitor */
 		ast_log(LOG_NOTICE, 
 				"Got DAHDI_EVENT_REMOVED. Destroying channel %d\n", 
 				i->channel);
-		dahdi_destroy_channel_bynum(i->channel);
-		break;
+		return i;
 	}
 	pthread_attr_destroy(&attr);
-	return 0;
+	return NULL;
 }
 
 static void *do_monitor(void *data)
@@ -7257,6 +7259,7 @@
 	int count, res, res2, spoint, pollres=0;
 	struct dahdi_pvt *i;
 	struct dahdi_pvt *last = NULL;
+	struct dahdi_pvt *doomed;
 	time_t thispass = 0, lastpass = 0;
 	int found;
 	char buf[1024];
@@ -7332,8 +7335,19 @@
 		spoint = 0;
 		lastpass = thispass;
 		thispass = time(NULL);
-		i = iflist;
-		while (i) {
+		doomed = NULL;
+		for (i = iflist;; i = i->next) {
+			if (doomed) {
+				int res;
+				res = dahdi_destroy_channel_bynum(doomed->channel);
+				if (!res) {
+					ast_log(LOG_WARNING, "Couldn't find channel to destroy, hopefully another destroy operation just happened.\n");
+				}
+				doomed = NULL;
+			}
+			if (!i) {
+				break;
+			}
 			if (thispass != lastpass) {
 				if (!found && ((i == last) || ((i == iflist) && !last))) {
 					last = i;
@@ -7374,10 +7388,9 @@
 							ast_log(LOG_DEBUG, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
 						/* Don't hold iflock while handling init events */
 						ast_mutex_unlock(&iflock);
-						handle_init_event(i, res);
+						doomed = handle_init_event(i, res);
 						ast_mutex_lock(&iflock);	
 					}
-					i = i->next;
 					continue;
 				}					
 				pollres = ast_fdisset(pfds, i->subs[SUB_REAL].dfd, count, &spoint);
@@ -7387,12 +7400,10 @@
 						if (!i->pri)
 #endif						
 							ast_log(LOG_WARNING, "Whoa....  I'm owned but found (%d) in read...\n", i->subs[SUB_REAL].dfd);
-						i = i->next;
 						continue;
 					}
 					if (!i->cidspill) {
 						ast_log(LOG_WARNING, "Whoa....  I'm reading but have no cidspill (%d)...\n", i->subs[SUB_REAL].dfd);
-						i = i->next;
 						continue;
 					}
 					res = read(i->subs[SUB_REAL].dfd, buf, sizeof(buf));
@@ -7423,7 +7434,6 @@
 						if (!i->pri)
 #endif						
 							ast_log(LOG_WARNING, "Whoa....  I'm owned but found (%d)...\n", i->subs[SUB_REAL].dfd);
-						i = i->next;
 						continue;
 					}
 					res = dahdi_get_event(i->subs[SUB_REAL].dfd);
@@ -7431,11 +7441,10 @@
 						ast_log(LOG_DEBUG, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
 					/* Don't hold iflock while handling init events */
 					ast_mutex_unlock(&iflock);
-					handle_init_event(i, res);
+					doomed = handle_init_event(i, res);
 					ast_mutex_lock(&iflock);	
 				}
 			}
-			i=i->next;
 		}
 		ast_mutex_unlock(&iflock);
 	}




More information about the asterisk-commits mailing list