Merged revisions 55397 via svnmerge from
[asterisk/asterisk.git] / channels / chan_iax2.c
index 484e89d..01994de 100644 (file)
@@ -461,6 +461,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;
@@ -889,6 +890,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 idle list off */
@@ -922,7 +924,9 @@ static struct iax2_thread *find_idle_thread(void)
        ast_cond_init(&thread->cond, NULL);
 
        /* Create thread and send it on it's way */
-       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_background(&thread->threadid, &attr, iax2_process_thread, thread)) {
                ast_cond_destroy(&thread->cond);
                ast_mutex_destroy(&thread->lock);
                free(thread);
@@ -7755,6 +7759,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;
@@ -7762,6 +7776,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);
@@ -7781,7 +7797,7 @@ static void *iax2_process_thread(void *data)
                                AST_LIST_REMOVE(&dynamic_list, thread, list);
                                AST_LIST_UNLOCK(&dynamic_list);
                                ast_atomic_dec_and_test(&iaxdynamicthreadcount);
-                               break;
+                               break;          /* exiting the main loop */
                        }
                } else {
                        ast_cond_wait(&thread->cond, &thread->lock);
@@ -7823,6 +7839,10 @@ static void *iax2_process_thread(void *data)
                put_into_idle = 1;
        }
 
+       /* 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;
 }
 
@@ -8211,6 +8231,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(&queue);
@@ -8250,6 +8272,7 @@ static void *network_thread(void *ignore)
                AST_LIST_TRAVERSE_SAFE_END
                AST_LIST_UNLOCK(&queue);
 
+               pthread_testcancel();
                if (count >= 20 && option_debug)
                        ast_log(LOG_DEBUG, "chan_iax2: Sent %d queued outbound frames all at once\n", count);
 
@@ -8265,6 +8288,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++) {
@@ -8274,7 +8298,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;
@@ -10005,27 +10031,27 @@ static struct ast_cli_entry cli_iax2[] = {
 #endif /* IAXTESTS */
 };
 
-static void thread_free(struct iax2_thread *thread)
-{
-       ast_mutex_destroy(&thread->lock);
-       ast_cond_destroy(&thread->cond);
-       free(thread);
-}
-
 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(&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(&queue);
                pthread_join(netthreadid, NULL);
        }
        if (schedthreadid != AST_PTHREADT_NULL) {
-               pthread_cancel(schedthreadid);
                ast_mutex_lock(&sched_lock);
+               pthread_cancel(schedthreadid);
                ast_cond_signal(&sched_cond);
                ast_mutex_unlock(&sched_lock);
                pthread_join(schedthreadid, NULL);
@@ -10035,39 +10061,31 @@ static int __unload_module(void)
        AST_LIST_LOCK(&idle_list);
        AST_LIST_TRAVERSE_SAFE_BEGIN(&idle_list, thread, list) {
                AST_LIST_REMOVE_CURRENT(&idle_list, list);
-               threadid = thread->threadid;
-               pthread_cancel(threadid);
-               signal_condition(&thread->lock, &thread->cond);
-               pthread_join(threadid, NULL);
-               thread_free(thread);
+               pthread_cancel(thread->threadid);
        }
        AST_LIST_TRAVERSE_SAFE_END
-       AST_LIST_UNLOCK(&idle_list);
+                       AST_LIST_UNLOCK(&idle_list);
 
        AST_LIST_LOCK(&active_list);
        AST_LIST_TRAVERSE_SAFE_BEGIN(&active_list, thread, list) {
                AST_LIST_REMOVE_CURRENT(&active_list, list);
-               threadid = thread->threadid;
-               pthread_cancel(threadid);
-               signal_condition(&thread->lock, &thread->cond);
-               pthread_join(threadid, NULL);
-               thread_free(thread);
+               pthread_cancel(thread->threadid);
        }
        AST_LIST_TRAVERSE_SAFE_END
-       AST_LIST_UNLOCK(&active_list);
+                       AST_LIST_UNLOCK(&active_list);
 
        AST_LIST_LOCK(&dynamic_list);
        AST_LIST_TRAVERSE_SAFE_BEGIN(&dynamic_list, thread, list) {
                AST_LIST_REMOVE_CURRENT(&dynamic_list, list);
-               threadid = thread->threadid;
-               pthread_cancel(threadid);
-               signal_condition(&thread->lock, &thread->cond);
-               pthread_join(threadid, NULL);
-               thread_free(thread);
+               pthread_cancel(thread->threadid);
        }
        AST_LIST_TRAVERSE_SAFE_END
-       AST_LIST_UNLOCK(&dynamic_list);
-
+                       AST_LIST_UNLOCK(&dynamic_list);
+       
+       /* 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])