[asterisk-commits] dbailey: branch 1.4 r55397 - /branches/1.4/channels/chan_iax2.c

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Mon Feb 19 07:53:00 MST 2007


Author: dbailey
Date: Mon Feb 19 08:52:59 2007
New Revision: 55397

URL: http://svn.digium.com/view/asterisk?view=rev&rev=55397
Log:
Changed iax2 process thread to detached to correct memory leak due to left over thread context on thread exit.  
Modified module unload process to avoid deadlocks on pthread cancels

Modified:
    branches/1.4/channels/chan_iax2.c

Modified: branches/1.4/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/branches/1.4/channels/chan_iax2.c?view=diff&rev=55397&r1=55396&r2=55397
==============================================================================
--- branches/1.4/channels/chan_iax2.c (original)
+++ branches/1.4/channels/chan_iax2.c Mon Feb 19 08:52:59 2007
@@ -227,7 +227,6 @@
 static pthread_t netthreadid = AST_PTHREADT_NULL;
 static pthread_t schedthreadid = AST_PTHREADT_NULL;
 AST_MUTEX_DEFINE_STATIC(sched_lock);
-static int sched_halt = 0;
 static ast_cond_t sched_cond;
 
 enum {
@@ -448,6 +447,7 @@
 static int iaxthreadcount = DEFAULT_THREAD_COUNT;
 static int iaxmaxthreadcount = DEFAULT_MAX_THREAD_COUNT;
 static int iaxdynamicthreadcount = 0;
+static int iaxactivethreadcount = 0;
 
 struct iax_rr {
 	int jitter;
@@ -690,7 +690,6 @@
 	char curfunc[80];
 #endif	
 	int actions;
-	int halt;
 	pthread_t threadid;
 	int threadnum;
 	struct sockaddr_in iosin;
@@ -843,6 +842,7 @@
 
 static struct iax2_thread *find_idle_thread(void)
 {
+	pthread_attr_t attr;
 	struct iax2_thread *thread = NULL;
 
 	/* Pop the head of the list off */
@@ -862,7 +862,9 @@
 				thread->type = IAX_TYPE_DYNAMIC;
 				ast_mutex_init(&thread->lock);
 				ast_cond_init(&thread->cond, NULL);
-				if (ast_pthread_create_background(&thread->threadid, NULL, iax2_process_thread, thread)) {
+				pthread_attr_init(&attr);
+				pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);	
+				if (ast_pthread_create(&thread->threadid, &attr, iax2_process_thread, thread)) {
 					free(thread);
 					thread = NULL;
 				} else {
@@ -7587,6 +7589,16 @@
 	return 1;
 }
 
+/* Function to clean up process thread if it is cancelled */
+static void iax2_process_thread_cleanup(void *data)
+{
+	struct iax2_thread *thread = data;
+	ast_mutex_destroy(&thread->lock);
+	ast_cond_destroy(&thread->cond);
+	free(thread);
+	ast_atomic_dec_and_test(&iaxactivethreadcount);
+}
+
 static void *iax2_process_thread(void *data)
 {
 	struct iax2_thread *thread = data;
@@ -7594,6 +7606,8 @@
 	struct timespec ts;
 	int put_into_idle = 0;
 
+	ast_atomic_fetchadd_int(&iaxactivethreadcount,1);
+	pthread_cleanup_push(iax2_process_thread_cleanup, data);
 	for(;;) {
 		/* Wait for something to signal us to be awake */
 		ast_mutex_lock(&thread->lock);
@@ -7613,17 +7627,12 @@
 				AST_LIST_REMOVE(&dynamic_list, thread, list);
 				iaxdynamicthreadcount--;
 				AST_LIST_UNLOCK(&dynamic_list);
-				break;
+				break;		/* exiting the main loop */
 			}
 		} else {
 			ast_cond_wait(&thread->cond, &thread->lock);
 		}
 		ast_mutex_unlock(&thread->lock);
-
-		/* If we were signalled, then we are already out of both lists or we are shutting down */
-		if (thread->halt) {
-			break;
-		}
 
 		/* Add ourselves to the active list now */
 		AST_LIST_LOCK(&active_list);
@@ -7660,10 +7669,10 @@
 		put_into_idle = 1;
 	}
 
-	/* Free our own memory */
-	ast_mutex_destroy(&thread->lock);
-	ast_cond_destroy(&thread->cond);
-	free(thread);
+	/* I am exiting here on my own volition, I need to clean up my own data structures
+	* Assume that I am no longer in any of the lists (idle, active, or dynamic)
+	*/
+	pthread_cleanup_pop(1);
 
 	return NULL;
 }
@@ -8027,17 +8036,16 @@
 		ts.tv_sec = tv.tv_sec;
 		ts.tv_nsec = tv.tv_usec * 1000;
 
+		pthread_testcancel();
 		ast_mutex_lock(&sched_lock);
 		ast_cond_timedwait(&sched_cond, &sched_lock, &ts);
-		if (sched_halt == 1)
-			break;
 		ast_mutex_unlock(&sched_lock);
+		pthread_testcancel();
 
 		count = ast_sched_runq(sched);
 		if (count >= 20)
 			ast_log(LOG_DEBUG, "chan_iax2: ast_sched_runq ran %d scheduled tasks all at once\n", count);
 	}
-	ast_mutex_unlock(&sched_lock);
 	return NULL;
 }
 
@@ -8052,6 +8060,8 @@
 		ast_io_add(io, timingfd, timing_read, AST_IO_IN | AST_IO_PRI, NULL);
 	
 	for(;;) {
+		pthread_testcancel();
+
 		/* Go through the queue, sending messages which have not yet been
 		   sent, and scheduling retransmissions if appropriate */
 		AST_LIST_LOCK(&iaxq.queue);
@@ -8092,6 +8102,8 @@
 		AST_LIST_TRAVERSE_SAFE_END
 		AST_LIST_UNLOCK(&iaxq.queue);
 
+		pthread_testcancel();
+
 		if (count >= 20)
 			ast_log(LOG_DEBUG, "chan_iax2: Sent %d queued outbound frames all at once\n", count);
 
@@ -8107,6 +8119,7 @@
 
 static int start_network_thread(void)
 {
+	pthread_attr_t attr;
 	int threadcount = 0;
 	int x;
 	for (x = 0; x < iaxthreadcount; x++) {
@@ -8116,7 +8129,9 @@
 			thread->threadnum = ++threadcount;
 			ast_mutex_init(&thread->lock);
 			ast_cond_init(&thread->cond, NULL);
-			if (ast_pthread_create_background(&thread->threadid, NULL, iax2_process_thread, thread)) {
+			pthread_attr_init(&attr);
+			pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);	
+			if (ast_pthread_create(&thread->threadid, &attr, iax2_process_thread, thread)) {
 				ast_log(LOG_WARNING, "Failed to create new thread!\n");
 				free(thread);
 				thread = NULL;
@@ -9866,32 +9881,35 @@
 
 static int __unload_module(void)
 {
-	pthread_t threadid = AST_PTHREADT_NULL;
 	struct iax2_thread *thread = NULL;
 	int x;
 
+	/* Make sure threads do not hold shared resources when they are canceled */
+	
+	/* Grab the sched lock resource to keep it away from threads about to die */
 	/* Cancel the network thread, close the net socket */
 	if (netthreadid != AST_PTHREADT_NULL) {
+		AST_LIST_LOCK(&iaxq.queue);
+		ast_mutex_lock(&sched_lock);
 		pthread_cancel(netthreadid);
+		ast_cond_signal(&sched_cond);
+		ast_mutex_unlock(&sched_lock);	/* Release the schedule lock resource */
+		AST_LIST_UNLOCK(&iaxq.queue);
 		pthread_join(netthreadid, NULL);
 	}
 	if (schedthreadid != AST_PTHREADT_NULL) {
+		ast_mutex_lock(&sched_lock);	
 		pthread_cancel(schedthreadid);
-		ast_mutex_lock(&sched_lock);
-		sched_halt = 1;
 		ast_cond_signal(&sched_cond);
-		ast_mutex_unlock(&sched_lock);
+		ast_mutex_unlock(&sched_lock);	
 		pthread_join(schedthreadid, NULL);
 	}
-
+	
 	/* Call for all threads to halt */
 	AST_LIST_LOCK(&idle_list);
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&idle_list, thread, list) {
 		AST_LIST_REMOVE_CURRENT(&idle_list, list);
-		threadid = thread->threadid;
-		thread->halt = 1;
-		signal_condition(&thread->lock, &thread->cond);
-		pthread_join(threadid, NULL);
+		pthread_cancel(thread->threadid);
 	}
 	AST_LIST_TRAVERSE_SAFE_END
 	AST_LIST_UNLOCK(&idle_list);
@@ -9899,10 +9917,7 @@
 	AST_LIST_LOCK(&active_list);
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&active_list, thread, list) {
 		AST_LIST_REMOVE_CURRENT(&active_list, list);
-		threadid = thread->threadid;
-		thread->halt = 1;
-		signal_condition(&thread->lock, &thread->cond);
-		pthread_join(threadid, NULL);
+		pthread_cancel(thread->threadid);
 	}
 	AST_LIST_TRAVERSE_SAFE_END
 	AST_LIST_UNLOCK(&active_list);
@@ -9910,16 +9925,17 @@
 	AST_LIST_LOCK(&dynamic_list);
         AST_LIST_TRAVERSE_SAFE_BEGIN(&dynamic_list, thread, list) {
 		AST_LIST_REMOVE_CURRENT(&dynamic_list, list);
-		threadid = thread->threadid;
-                thread->halt = 1;
-                signal_condition(&thread->lock, &thread->cond);
-		pthread_join(threadid, NULL);
+		pthread_cancel(thread->threadid);
         }
 	AST_LIST_TRAVERSE_SAFE_END
         AST_LIST_UNLOCK(&dynamic_list);
 
 	AST_LIST_HEAD_DESTROY(&iaxq.queue);
 
+	/* Wait for threads to exit */
+	while(0 < iaxactivethreadcount)
+		usleep(10000);
+	
 	ast_netsock_release(netsock);
 	for (x=0;x<IAX_MAX_CALLS;x++)
 		if (iaxs[x])



More information about the asterisk-commits mailing list