diff --git a/res/res_smdi.c b/res/res_smdi.c index b8bf5d89613a1bfc419332eb5645b737666e475a..c6f3f3af5fbc5ac8f9512db8bcf87befe3618af3 100644 --- a/res/res_smdi.c +++ b/res/res_smdi.c @@ -223,10 +223,12 @@ static struct { static void smdi_interface_destroy(void *obj) { struct ast_smdi_interface *iface = obj; + int mod_unref_defer = 0; if (iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) { pthread_cancel(iface->thread); pthread_join(iface->thread, NULL); + mod_unref_defer = 1; } iface->thread = AST_PTHREADT_STOP; @@ -243,9 +245,9 @@ static void smdi_interface_destroy(void *obj) ast_mutex_destroy(&iface->mwi_q_lock); ast_cond_destroy(&iface->mwi_q_cond); - ast_free(iface); - - ast_module_unref(ast_module_info->self); + if (mod_unref_defer) { + ast_module_unref(ast_module_info->self); + } } /*! @@ -608,7 +610,6 @@ static void *smdi_read(void *iface_p) md_msg = ao2_alloc(sizeof(*md_msg), NULL); if (!md_msg) { - ao2_ref(iface, -1); return NULL; } @@ -618,7 +619,6 @@ static void *smdi_read(void *iface_p) if (c == EOF) { ast_log(LOG_ERROR, "Unexpected EOF while reading MD message\n"); ao2_ref(md_msg, -1); - ao2_ref(iface, -1); return NULL; } md_msg->mesg_desk_num[i] = (char) c; @@ -635,7 +635,6 @@ static void *smdi_read(void *iface_p) if (c == EOF) { ast_log(LOG_ERROR, "Unexpected EOF while reading SMDI message\n"); ao2_ref(md_msg, -1); - ao2_ref(iface, -1); return NULL; } md_msg->mesg_desk_term[i] = (char) c; @@ -651,7 +650,6 @@ static void *smdi_read(void *iface_p) if (c == EOF) { ast_log(LOG_ERROR, "Unexpected EOF while reading SMDI message\n"); ao2_ref(md_msg, -1); - ao2_ref(iface, -1); return NULL; } md_msg->type = (char) c; @@ -730,7 +728,6 @@ static void *smdi_read(void *iface_p) mwi_msg = ao2_alloc(sizeof(*mwi_msg), NULL); if (!mwi_msg) { - ao2_ref(iface, -1); return NULL; } @@ -764,7 +761,6 @@ static void *smdi_read(void *iface_p) if (c == EOF) { ast_log(LOG_ERROR, "Unexpected EOF while reading MWI message\n"); ao2_ref(mwi_msg, -1); - ao2_ref(iface, -1); return NULL; } mwi_msg->cause[i] = (char) c; @@ -785,7 +781,6 @@ static void *smdi_read(void *iface_p) } ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name); - ao2_ref(iface, -1); return NULL; } @@ -982,6 +977,11 @@ static int smdi_load(int reload) return 0; new_ifaces = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, smdi_ifaces_cmp_fn); + if (!new_ifaces) { + ast_config_destroy(conf); + return -1; + } + for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) { RAII_VAR(struct ast_smdi_interface *, iface, NULL, ao2_cleanup); @@ -1104,7 +1104,13 @@ static int smdi_load(int reload) /* set the message expiry time */ iface->msg_expiry = msg_expiry; - /* start the listener thread */ + /* + * start the listener thread + * + * The listener thread does not actually hold a ref to iface. When all + * external refs go away, the destructor will stop the listener thread + * before actually destroying the iface object. + */ ast_verb(3, "Starting SMDI monitor thread for %s\n", iface->name); if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) { ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name); @@ -1154,7 +1160,7 @@ static int smdi_load(int reload) return -1; } - if (ao2_container_count(new_ifaces)) { + if (!ao2_container_count(new_ifaces)) { res = 1; }