aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authordbailey <dbailey@f38db490-d61c-443f-a65b-d21fe96a405b>2007-02-19 15:24:46 +0000
committerdbailey <dbailey@f38db490-d61c-443f-a65b-d21fe96a405b>2007-02-19 15:24:46 +0000
commit12c3f5928769f7a424dc092b6d6dc0ab82762b04 (patch)
tree3c027a7ab9205865fe8cffbd434b073d79e9df94 /channels
parent01980eb4e8e6446488fb8560dd5ad880be650e68 (diff)
Merged revisions 55397 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r55397 | dbailey | 2007-02-19 08:52:59 -0600 (Mon, 19 Feb 2007) | 3 lines 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: http://svn.digium.com/svn/asterisk/trunk@55409 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_iax2.c80
1 files changed, 49 insertions, 31 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 484e89d4a..01994de4b 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -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])