|
|
|
@ -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])
|
|
|
|
|