* a call which this thread is already processing a full frame for, they
* are queued up here. */
AST_LIST_HEAD_NOLOCK(, iax2_pkt_buf) full_frames;
+ unsigned char stop;
};
/* Thread lists */
ast_mutex_lock(&thread->init_lock);
/* Create thread and send it on it's way */
- if (ast_pthread_create_detached_background(&thread->threadid, NULL, iax2_process_thread, thread)) {
+ if (ast_pthread_create_background(&thread->threadid, NULL, iax2_process_thread, thread)) {
ast_cond_destroy(&thread->cond);
ast_mutex_destroy(&thread->lock);
ast_free(thread);
struct timespec ts;
int put_into_idle = 0;
int first_time = 1;
+ int old_state;
- ast_atomic_fetchadd_int(&iaxactivethreadcount,1);
+ ast_atomic_fetchadd_int(&iaxactivethreadcount, 1);
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
pthread_cleanup_push(iax2_process_thread_cleanup, data);
- for(;;) {
+
+ for (;;) {
/* Wait for something to signal us to be awake */
ast_mutex_lock(&thread->lock);
+ if (thread->stop) {
+ ast_mutex_unlock(&thread->lock);
+ break;
+ }
+
/* Flag that we're ready to accept signals */
if (first_time) {
signal_condition(&thread->init_lock, &thread->init_cond);
}
/* Put into idle list if applicable */
- if (put_into_idle)
+ if (put_into_idle) {
insert_idle_thread(thread);
+ }
if (thread->type == IAX_THREAD_TYPE_DYNAMIC) {
struct iax2_thread *t = NULL;
if (ast_cond_timedwait(&thread->cond, &thread->lock, &ts) == ETIMEDOUT) {
/* This thread was never put back into the available dynamic
* thread list, so just go away. */
- if (!put_into_idle) {
+ if (!put_into_idle || thread->stop) {
ast_mutex_unlock(&thread->lock);
break;
}
wait = ast_tvadd(ast_tvnow(), ast_samp2tv(30000, 1000));
ts.tv_sec = wait.tv_sec;
ts.tv_nsec = wait.tv_usec * 1000;
- if (ast_cond_timedwait(&thread->cond, &thread->lock, &ts) == ETIMEDOUT)
- {
+ if (ast_cond_timedwait(&thread->cond, &thread->lock, &ts) == ETIMEDOUT) {
ast_mutex_unlock(&thread->lock);
break;
}
ast_mutex_unlock(&thread->lock);
+ if (thread->stop) {
+ break;
+ }
+
if (thread->iostate == IAX_IOSTATE_IDLE)
continue;
/* See what we need to do */
- switch(thread->iostate) {
+ switch (thread->iostate) {
case IAX_IOSTATE_READY:
thread->actions++;
thread->iostate = IAX_IOSTATE_PROCESSING;
thread->threadnum = ++threadcount;
ast_mutex_init(&thread->lock);
ast_cond_init(&thread->cond, NULL);
- if (ast_pthread_create_detached(&thread->threadid, NULL, iax2_process_thread, thread)) {
+ if (ast_pthread_create_background(&thread->threadid, NULL, iax2_process_thread, thread)) {
ast_log(LOG_WARNING, "Failed to create new thread!\n");
ast_free(thread);
thread = NULL;
#endif /* IAXTESTS */
};
+static void cleanup_thread_list(void *head)
+{
+ AST_LIST_HEAD(iax2_thread_list, iax2_thread);
+ struct iax2_thread_list *list_head = head;
+ struct iax2_thread *thread;
+
+ AST_LIST_LOCK(list_head);
+ while ((thread = AST_LIST_REMOVE_HEAD(&idle_list, list))) {
+ pthread_t thread_id = thread->threadid;
+
+ thread->stop = 1;
+ signal_condition(&thread->lock, &thread->cond);
+
+ AST_LIST_UNLOCK(list_head);
+ pthread_join(thread_id, NULL);
+ AST_LIST_LOCK(list_head);
+ }
+ AST_LIST_UNLOCK(list_head);
+}
+
static int __unload_module(void)
{
- struct iax2_thread *thread = NULL;
struct ast_context *con;
int x;
+ ast_manager_unregister("IAXpeers");
+ ast_manager_unregister("IAXpeerlist");
+ ast_manager_unregister("IAXnetstats");
+ ast_manager_unregister("IAXregistry");
+ ast_unregister_application(papp);
+ ast_cli_unregister_multiple(cli_iax2, ARRAY_LEN(cli_iax2));
+ ast_unregister_switch(&iax2_switch);
+ ast_channel_unregister(&iax2_tech);
+
if (netthreadid != AST_PTHREADT_NULL) {
pthread_cancel(netthreadid);
pthread_kill(netthreadid, SIGURG);
pthread_join(netthreadid, NULL);
}
- sched = ast_sched_thread_destroy(sched);
+ for (x = 0; x < ARRAY_LEN(iaxs); x++) {
+ if (iaxs[x]) {
+ iax2_destroy(x);
+ }
+ }
/* Call for all threads to halt */
- AST_LIST_LOCK(&idle_list);
- while ((thread = AST_LIST_REMOVE_HEAD(&idle_list, list)))
- pthread_cancel(thread->threadid);
- AST_LIST_UNLOCK(&idle_list);
+ cleanup_thread_list(&idle_list);
+ cleanup_thread_list(&active_list);
+ cleanup_thread_list(&dynamic_list);
- AST_LIST_LOCK(&active_list);
- while ((thread = AST_LIST_REMOVE_HEAD(&active_list, list)))
- pthread_cancel(thread->threadid);
- AST_LIST_UNLOCK(&active_list);
+ sched = ast_sched_thread_destroy(sched);
- AST_LIST_LOCK(&dynamic_list);
- while ((thread = AST_LIST_REMOVE_HEAD(&dynamic_list, list)))
- pthread_cancel(thread->threadid);
- AST_LIST_UNLOCK(&dynamic_list);
-
- /* Wait for threads to exit */
- while(0 < iaxactivethreadcount)
- usleep(10000);
-
ast_netsock_release(netsock);
ast_netsock_release(outsock);
- for (x = 0; x < ARRAY_LEN(iaxs); x++) {
- if (iaxs[x]) {
- iax2_destroy(x);
- }
- }
- ast_manager_unregister( "IAXpeers" );
- ast_manager_unregister( "IAXpeerlist" );
- ast_manager_unregister( "IAXnetstats" );
- ast_manager_unregister( "IAXregistry" );
- ast_unregister_application(papp);
- ast_cli_unregister_multiple(cli_iax2, ARRAY_LEN(cli_iax2));
- ast_unregister_switch(&iax2_switch);
- ast_channel_unregister(&iax2_tech);
+
delete_users();
iax_provision_unload();
reload_firmware(1);