diff options
author | Automerge script <automerge@asterisk.org> | 2012-12-17 23:18:40 +0000 |
---|---|---|
committer | Automerge script <automerge@asterisk.org> | 2012-12-17 23:18:40 +0000 |
commit | 84e6a9847a7b564e4561d500c896a6985bb1e13e (patch) | |
tree | 2daf02d898eef00fa9dce9812f412a9b3dd4c0db | |
parent | f1e6eefdbab426cef2eec91e8b86bb4a42f52d39 (diff) |
Merged revisions 378091,378095 via svnmerge from
file:///srv/subversion/repos/asterisk/trunk
................
r378091 | rmudgett | 2012-12-17 17:02:54 -0600 (Mon, 17 Dec 2012) | 22 lines
Make chan_local module references tied to local_pvt lifetime.
The chan_local module references were manually tied to the existence of
the ;1 and ;2 channel links.
* Made chan_local module references tied to the existence of the local_pvt
structure as well as automatically take care of the module references.
* Tweaked the wording of the local_fixup() failure warning message to make
sense.
Review: https://reviewboard.asterisk.org/r/2181/
........
Merged revisions 378088 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
Merged revisions 378089 from http://svn.asterisk.org/svn/asterisk/branches/10
........
Merged revisions 378090 from http://svn.asterisk.org/svn/asterisk/branches/11
................
r378095 | rmudgett | 2012-12-17 17:10:42 -0600 (Mon, 17 Dec 2012) | 11 lines
Fix potential double free when unloading a module.
........
Merged revisions 378092 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
Merged revisions 378093 from http://svn.asterisk.org/svn/asterisk/branches/10
........
Merged revisions 378094 from http://svn.asterisk.org/svn/asterisk/branches/11
................
git-svn-id: https://origsvn.digium.com/svn/asterisk/team/mmichelson/threadpool@378099 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r-- | channels/chan_local.c | 43 | ||||
-rw-r--r-- | main/loader.c | 28 |
2 files changed, 49 insertions, 22 deletions
diff --git a/channels/chan_local.c b/channels/chan_local.c index 30d5186d3..14912793f 100644 --- a/channels/chan_local.c +++ b/channels/chan_local.c @@ -151,8 +151,6 @@ struct local_pvt { struct ast_jb_conf jb_conf; /*!< jitterbuffer configuration for this local channel */ struct ast_channel *owner; /*!< Master Channel - Bridging happens here */ struct ast_channel *chan; /*!< Outbound channel - PBX is run here */ - struct ast_module_user *u_owner;/*!< reference to keep the module loaded while in use */ - struct ast_module_user *u_chan; /*!< reference to keep the module loaded while in use */ }; #define LOCAL_ALREADY_MASQED (1 << 0) /*!< Already masqueraded */ @@ -676,7 +674,7 @@ static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) ao2_lock(p); if ((p->owner != oldchan) && (p->chan != oldchan)) { - ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); + ast_log(LOG_WARNING, "Old channel %p wasn't %p or %p\n", oldchan, p->owner, p->chan); ao2_unlock(p); return -1; } @@ -1085,16 +1083,15 @@ static int local_hangup(struct ast_channel *ast) if (isoutbound) { const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); - if ((status) && (p->owner)) { + + if (status && p->owner) { ast_channel_hangupcause_set(p->owner, ast_channel_hangupcause(p->chan)); pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); } ast_clear_flag(p, LOCAL_LAUNCHED_PBX); - ast_module_user_remove(p->u_chan); p->chan = NULL; } else { - ast_module_user_remove(p->u_owner); if (p->chan) { ast_queue_hangup(p->chan); } @@ -1105,6 +1102,7 @@ static int local_hangup(struct ast_channel *ast) if (!p->owner && !p->chan) { ao2_unlock(p); + /* Remove from list */ ao2_unlink(locals, p); ao2_ref(p, -1); @@ -1124,6 +1122,10 @@ local_hangup_cleanup: ao2_unlock(p); ao2_ref(p, -1); } + if (owner) { + ast_channel_unlock(owner); + owner = ast_channel_unref(owner); + } if (chan) { ast_channel_unlock(chan); if (hangup_chan) { @@ -1131,20 +1133,27 @@ local_hangup_cleanup: } chan = ast_channel_unref(chan); } - if (owner) { - ast_channel_unlock(owner); - owner = ast_channel_unref(owner); - } /* leave with the same stupid channel locked that came in */ ast_channel_lock(ast); return res; } -static void local_destroy(void *obj) +/*! + * \internal + * \brief struct local_pvt destructor. + * + * \param vdoomed Void local_pvt to destroy. + * + * \return Nothing + */ +static void local_pvt_destructor(void *vdoomed) { - struct local_pvt *pvt = obj; - pvt->reqcap = ast_format_cap_destroy(pvt->reqcap); + struct local_pvt *doomed = vdoomed; + + doomed->reqcap = ast_format_cap_destroy(doomed->reqcap); + + ast_module_unref(ast_module_info->self); } /*! \brief Create a call structure */ @@ -1155,7 +1164,7 @@ static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *ca char *c = NULL; char *opts = NULL; - if (!(tmp = ao2_alloc(sizeof(*tmp), local_destroy))) { + if (!(tmp = ao2_alloc(sizeof(*tmp), local_pvt_destructor))) { return NULL; } if (!(tmp->reqcap = ast_format_cap_dup(cap))) { @@ -1163,6 +1172,8 @@ static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *ca return NULL; } + ast_module_ref(ast_module_info->self); + /* Initialize private structure information */ parse = ast_strdupa(data); @@ -1262,8 +1273,6 @@ static struct ast_channel *local_new(struct local_pvt *p, int state, const char p->owner = tmp; p->chan = tmp2; - p->u_owner = ast_module_user_add(p->owner); - p->u_chan = ast_module_user_add(p->chan); ast_channel_context_set(tmp, p->context); ast_channel_context_set(tmp2, p->context); @@ -1295,9 +1304,7 @@ static struct ast_channel *local_request(const char *type, struct ast_format_cap } else if (ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) { ao2_unlink(locals, p); p->owner = ast_channel_release(p->owner); - ast_module_user_remove(p->u_owner); p->chan = ast_channel_release(p->chan); - ast_module_user_remove(p->u_chan); chan = NULL; } ao2_ref(p, -1); /* kill the ref from the alloc */ diff --git a/main/loader.c b/main/loader.c index 2af9d2006..7ad515f8a 100644 --- a/main/loader.c +++ b/main/loader.c @@ -237,9 +237,18 @@ void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u) if (!u) { return; } + AST_LIST_LOCK(&mod->users); - AST_LIST_REMOVE(&mod->users, u, entry); + u = AST_LIST_REMOVE(&mod->users, u, entry); AST_LIST_UNLOCK(&mod->users); + if (!u) { + /* + * Was not in the list. Either a bad pointer or + * __ast_module_user_hangup_all() has been called. + */ + return; + } + ast_atomic_fetchadd_int(&mod->usecount, -1); ast_free(u); @@ -559,15 +568,26 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f } if (!error) { + /* Request any channels attached to the module to hangup. */ __ast_module_user_hangup_all(mod); - res = mod->info->unload(); + res = mod->info->unload(); if (res) { ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name); - if (force <= AST_FORCE_FIRM) + if (force <= AST_FORCE_FIRM) { error = 1; - else + } else { ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n"); + } + } + + if (!error) { + /* + * Request hangup on any channels that managed to get attached + * while we called the module unload function. + */ + __ast_module_user_hangup_all(mod); + sched_yield(); } } |