]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Changed iax2 process thread to detached to correct memory leak due to left over threa...
authorDoug Bailey <dbailey@digium.com>
Mon, 19 Feb 2007 14:52:59 +0000 (14:52 +0000)
committerDoug Bailey <dbailey@digium.com>
Mon, 19 Feb 2007 14:52:59 +0000 (14:52 +0000)
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

channels/chan_iax2.c

index 923970e1a6f21ead1a6a5e69d6e511f80f599a66..0412d66dc1e8000e77e74fd62db18e6b1bba7b3d 100644 (file)
@@ -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<IAX_MAX_CALLS;x++)
                if (iaxs[x])