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
This commit is contained in:
Automerge script 2012-12-17 23:18:40 +00:00
parent f1e6eefdba
commit 84e6a9847a
2 changed files with 49 additions and 22 deletions

View File

@ -151,8 +151,6 @@ struct local_pvt {
struct ast_jb_conf jb_conf; /*!< jitterbuffer configuration for this local channel */ struct ast_jb_conf jb_conf; /*!< jitterbuffer configuration for this local channel */
struct ast_channel *owner; /*!< Master Channel - Bridging happens here */ struct ast_channel *owner; /*!< Master Channel - Bridging happens here */
struct ast_channel *chan; /*!< Outbound channel - PBX is run 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 */ #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); ao2_lock(p);
if ((p->owner != oldchan) && (p->chan != oldchan)) { 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); ao2_unlock(p);
return -1; return -1;
} }
@ -1085,16 +1083,15 @@ static int local_hangup(struct ast_channel *ast)
if (isoutbound) { if (isoutbound) {
const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 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)); ast_channel_hangupcause_set(p->owner, ast_channel_hangupcause(p->chan));
pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
} }
ast_clear_flag(p, LOCAL_LAUNCHED_PBX); ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
ast_module_user_remove(p->u_chan);
p->chan = NULL; p->chan = NULL;
} else { } else {
ast_module_user_remove(p->u_owner);
if (p->chan) { if (p->chan) {
ast_queue_hangup(p->chan); ast_queue_hangup(p->chan);
} }
@ -1105,6 +1102,7 @@ static int local_hangup(struct ast_channel *ast)
if (!p->owner && !p->chan) { if (!p->owner && !p->chan) {
ao2_unlock(p); ao2_unlock(p);
/* Remove from list */ /* Remove from list */
ao2_unlink(locals, p); ao2_unlink(locals, p);
ao2_ref(p, -1); ao2_ref(p, -1);
@ -1124,6 +1122,10 @@ local_hangup_cleanup:
ao2_unlock(p); ao2_unlock(p);
ao2_ref(p, -1); ao2_ref(p, -1);
} }
if (owner) {
ast_channel_unlock(owner);
owner = ast_channel_unref(owner);
}
if (chan) { if (chan) {
ast_channel_unlock(chan); ast_channel_unlock(chan);
if (hangup_chan) { if (hangup_chan) {
@ -1131,20 +1133,27 @@ local_hangup_cleanup:
} }
chan = ast_channel_unref(chan); 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 */ /* leave with the same stupid channel locked that came in */
ast_channel_lock(ast); ast_channel_lock(ast);
return res; 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; struct local_pvt *doomed = vdoomed;
pvt->reqcap = ast_format_cap_destroy(pvt->reqcap);
doomed->reqcap = ast_format_cap_destroy(doomed->reqcap);
ast_module_unref(ast_module_info->self);
} }
/*! \brief Create a call structure */ /*! \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 *c = NULL;
char *opts = NULL; char *opts = NULL;
if (!(tmp = ao2_alloc(sizeof(*tmp), local_destroy))) { if (!(tmp = ao2_alloc(sizeof(*tmp), local_pvt_destructor))) {
return NULL; return NULL;
} }
if (!(tmp->reqcap = ast_format_cap_dup(cap))) { 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; return NULL;
} }
ast_module_ref(ast_module_info->self);
/* Initialize private structure information */ /* Initialize private structure information */
parse = ast_strdupa(data); 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->owner = tmp;
p->chan = tmp2; 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(tmp, p->context);
ast_channel_context_set(tmp2, 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)) { } else if (ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) {
ao2_unlink(locals, p); ao2_unlink(locals, p);
p->owner = ast_channel_release(p->owner); p->owner = ast_channel_release(p->owner);
ast_module_user_remove(p->u_owner);
p->chan = ast_channel_release(p->chan); p->chan = ast_channel_release(p->chan);
ast_module_user_remove(p->u_chan);
chan = NULL; chan = NULL;
} }
ao2_ref(p, -1); /* kill the ref from the alloc */ ao2_ref(p, -1); /* kill the ref from the alloc */

View File

@ -237,9 +237,18 @@ void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
if (!u) { if (!u) {
return; return;
} }
AST_LIST_LOCK(&mod->users); 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); 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_atomic_fetchadd_int(&mod->usecount, -1);
ast_free(u); ast_free(u);
@ -559,15 +568,26 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f
} }
if (!error) { if (!error) {
/* Request any channels attached to the module to hangup. */
__ast_module_user_hangup_all(mod); __ast_module_user_hangup_all(mod);
res = mod->info->unload();
res = mod->info->unload();
if (res) { if (res) {
ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name); ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
if (force <= AST_FORCE_FIRM) if (force <= AST_FORCE_FIRM) {
error = 1; error = 1;
else } else {
ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n"); 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();
} }
} }