From: Doug Bailey Date: Mon, 19 Feb 2007 14:52:59 +0000 (+0000) Subject: Changed iax2 process thread to detached to correct memory leak due to left over threa... X-Git-Tag: 1.4.1~74 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c967342095f8589620d09ceefd369b59d6b25a5b;p=thirdparty%2Fasterisk.git 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 git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@55397 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 923970e1a6..0412d66dc1 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -227,7 +227,6 @@ static struct ast_flags globalflags = { 0 }; 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 AST_LIST_HEAD_STATIC(registrations, iax2_registry); 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 @@ struct iax2_thread { char curfunc[80]; #endif int actions; - int halt; pthread_t threadid; int threadnum; struct sockaddr_in iosin; @@ -843,6 +842,7 @@ static void insert_idle_thread(struct iax2_thread *thread) 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 @@ static struct iax2_thread *find_idle_thread(void) 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 @@ retryowner2: 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 @@ static void *iax2_process_thread(void *data) 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,18 +7627,13 @@ static void *iax2_process_thread(void *data) 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); AST_LIST_INSERT_HEAD(&active_list, thread, list); @@ -7660,10 +7669,10 @@ static void *iax2_process_thread(void *data) 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 @@ static void *sched_thread(void *ignore) 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 @@ static void *network_thread(void *ignore) 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 @@ static void *network_thread(void *ignore) 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 void *network_thread(void *ignore) 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 @@ static int start_network_thread(void) 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 struct ast_cli_entry cli_iax2[] = { 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 @@ static int __unload_module(void) 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 @@ static int __unload_module(void) 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