[Asterisk-code-review] loader: Create ast module running ref. (asterisk[master])
Corey Farrell
asteriskteam at digium.com
Fri Dec 29 19:26:49 CST 2017
Corey Farrell has uploaded this change for review. ( https://gerrit.asterisk.org/7770
Change subject: loader: Create ast_module_running_ref.
......................................................................
loader: Create ast_module_running_ref.
This function returns NULL if the module in question is not running. I
did not change ast_module_ref as most callers do not check the result
and they always call ast_module_unref.
Make use of this function when running registered items from:
* app_stack API's
* bridge technologies
* CLI commands
* File formats
* Manager Actions
* RTP engines
* Sorcery Wizards
* Timing Interfaces
* Translators
* AGI Commands
* Fax Technologies
ASTERISK-20346 #close
Change-Id: Ia16fd28e188b2fc0b9d18b8a5d9cacc31df73fcc
---
M include/asterisk/module.h
M main/app.c
M main/bridge.c
M main/cli.c
M main/file.c
M main/loader.c
M main/manager.c
M main/rtp_engine.c
M main/sorcery.c
M main/timing.c
M main/translate.c
M res/res_agi.c
M res/res_fax.c
13 files changed, 143 insertions(+), 78 deletions(-)
git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/70/7770/1
diff --git a/include/asterisk/module.h b/include/asterisk/module.h
index d3b9ddc..103cd30 100644
--- a/include/asterisk/module.h
+++ b/include/asterisk/module.h
@@ -357,6 +357,7 @@
#define ast_module_user_hangup_all() __ast_module_user_hangup_all(AST_MODULE_SELF)
struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func);
+struct ast_module *__ast_module_running_ref(struct ast_module *mod, const char *file, int line, const char *func);
void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func);
void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func);
@@ -369,6 +370,20 @@
* from being unloaded.
*/
#define ast_module_ref(mod) __ast_module_ref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+/*!
+ * \brief Hold a reference to the module if it is running.
+ * \param mod Module to reference
+ * \retval mod if running
+ * \retval NULL if not running
+ *
+ * The returned pointer should be released with ast_module_unref.
+ *
+ * \note A module reference will prevent the module from being unloaded.
+ */
+#define ast_module_running_ref(mod) \
+ __ast_module_running_ref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
/*!
* \brief Prevent unload of the module before shutdown
* \param mod Module to hold
diff --git a/main/app.c b/main/app.c
index 215ec04..2db9a8f 100644
--- a/main/app.c
+++ b/main/app.c
@@ -386,6 +386,7 @@
return res;
}
+/* BUGBUG this is not thread safe. */
static const struct ast_app_stack_funcs *app_stack_callbacks;
void ast_install_stack_functions(const struct ast_app_stack_funcs *funcs)
@@ -399,16 +400,16 @@
const char *new_args;
funcs = app_stack_callbacks;
- if (!funcs || !funcs->expand_sub_args) {
+ if (!funcs || !funcs->expand_sub_args || !ast_module_running_ref(funcs->module)) {
ast_log(LOG_WARNING,
"Cannot expand 'Gosub(%s)' arguments. The app_stack module is not available.\n",
args);
return NULL;
}
- ast_module_ref(funcs->module);
new_args = funcs->expand_sub_args(chan, args);
ast_module_unref(funcs->module);
+
return new_args;
}
@@ -418,13 +419,12 @@
int res;
funcs = app_stack_callbacks;
- if (!funcs || !funcs->run_sub) {
+ if (!funcs || !funcs->run_sub || !ast_module_running_ref(funcs->module)) {
ast_log(LOG_WARNING,
"Cannot run 'Gosub(%s)'. The app_stack module is not available.\n",
sub_args);
return -1;
}
- ast_module_ref(funcs->module);
if (autoservice_chan) {
ast_autoservice_start(autoservice_chan);
diff --git a/main/bridge.c b/main/bridge.c
index 88d9e54..48f7a49 100644
--- a/main/bridge.c
+++ b/main/bridge.c
@@ -522,8 +522,13 @@
if (best) {
/* Increment it's module reference count if present so it does not get unloaded while in use */
- ast_module_ref(best->mod);
- ast_debug(1, "Chose bridge technology %s\n", best->name);
+ if (ast_module_running_ref(best->mod)) {
+ ast_debug(1, "Chose bridge technology %s\n", best->name);
+ } else {
+ /* The bridge module is not actually running. */
+ /* BUGBUG: improve handling of this situation. */
+ best = NULL;
+ }
}
AST_RWLIST_UNLOCK(&bridge_technologies);
diff --git a/main/cli.c b/main/cli.c
index 1299c2a..214ead7 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -2679,9 +2679,11 @@
.n = state - matchnum,
.argv = argv,
.argc = x};
- ast_module_ref(e->module);
- ret = e->handler(e, CLI_GENERATE, &a);
- ast_module_unref(e->module);
+
+ if (!e->module || ast_module_running_ref(e->module)) {
+ ret = e->handler(e, CLI_GENERATE, &a);
+ ast_module_unref(e->module);
+ }
}
if (ret)
break;
@@ -2760,9 +2762,10 @@
*/
args[0] = (char *)e;
- ast_module_ref(e->module);
- retval = e->handler(e, CLI_HANDLER, &a);
- ast_module_unref(e->module);
+ if (!e->module || ast_module_running_ref(e->module)) {
+ retval = e->handler(e, CLI_HANDLER, &a);
+ ast_module_unref(e->module);
+ }
if (retval == CLI_SHOWUSAGE) {
ast_cli(fd, "%s", S_OR(e->usage, "Invalid usage, but no usage information available.\n"));
diff --git a/main/file.c b/main/file.c
index 41131f9..8dded81 100644
--- a/main/file.c
+++ b/main/file.c
@@ -425,11 +425,17 @@
static struct ast_filestream *get_filestream(struct ast_format_def *fmt, FILE *bfile)
{
struct ast_filestream *s;
-
int l = sizeof(*s) + fmt->buf_size + fmt->desc_size; /* total allocation size */
- if ( (s = ao2_alloc(l, filestream_destructor)) == NULL)
+
+ if (!ast_module_running_ref(fmt->module)) {
return NULL;
- ast_module_ref(fmt->module);
+ }
+
+ s = ao2_alloc(l, filestream_destructor);
+ if (!s) {
+ ast_module_unref(fmt->module);
+ return NULL;
+ }
s->fmt = fmt;
s->f = bfile;
diff --git a/main/loader.c b/main/loader.c
index fe18048..88c1cda 100644
--- a/main/loader.c
+++ b/main/loader.c
@@ -1702,6 +1702,16 @@
return mod;
}
+struct ast_module *__ast_module_running_ref(struct ast_module *mod,
+ const char *file, int line, const char *func)
+{
+ if (!mod || !mod->flags.running) {
+ return NULL;
+ }
+
+ return __ast_module_ref(mod, file, line, func);
+}
+
void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
{
if (!mod || mod->flags.keepuntilshutdown) {
diff --git a/main/manager.c b/main/manager.c
index 576978c..60e0d43 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -2923,34 +2923,40 @@
}
action = astman_get_header(&m, "Action");
- if (strcasecmp(action, "login")) {
- act_found = action_find(action);
- if (act_found) {
- /*
- * we have to simulate a session for this action request
- * to be able to pass it down for processing
- * This is necessary to meet the previous design of manager.c
- */
- s.hook = hook;
- ao2_lock(act_found);
- if (act_found->registered && act_found->func) {
- if (act_found->module) {
- ast_module_ref(act_found->module);
- }
- ao2_unlock(act_found);
- ret = act_found->func(&s, &m);
- ao2_lock(act_found);
- if (act_found->module) {
- ast_module_unref(act_found->module);
- }
- } else {
- ret = -1;
- }
- ao2_unlock(act_found);
- ao2_t_ref(act_found, -1, "done with found action object");
+ do {
+ if (!strcasecmp(action, "login")) {
+ break;
}
- }
+
+ act_found = action_find(action);
+ if (!act_found) {
+ break;
+ }
+
+ /*
+ * we have to simulate a session for this action request
+ * to be able to pass it down for processing
+ * This is necessary to meet the previous design of manager.c
+ */
+ s.hook = hook;
+
+ ret = -1;
+ ao2_lock(act_found);
+ if (act_found->registered && act_found->func) {
+ struct ast_module *mod_ref = ast_module_running_ref(act_found->module);
+
+ ao2_unlock(act_found);
+ if (mod_ref || !act_found->module) {
+ ret = act_found->func(&s, &m);
+ ast_module_unref(mod_ref);
+ }
+ } else {
+ ao2_unlock(act_found);
+ }
+ ao2_t_ref(act_found, -1, "done with found action object");
+ } while (0);
+
ast_free(dup_str);
return ret;
}
@@ -6442,21 +6448,21 @@
if ((s->session->writeperm & act_found->authority)
|| act_found->authority == 0) {
/* We have the authority to execute the action. */
+ ret = -1;
ao2_lock(act_found);
if (act_found->registered && act_found->func) {
- ast_debug(1, "Running action '%s'\n", act_found->action);
- if (act_found->module) {
- ast_module_ref(act_found->module);
- }
+ struct ast_module *mod_ref = ast_module_running_ref(act_found->module);
+
ao2_unlock(act_found);
- ret = act_found->func(s, m);
- acted = 1;
- ao2_lock(act_found);
- if (act_found->module) {
- ast_module_unref(act_found->module);
+ if (mod_ref || !act_found->module) {
+ ast_debug(1, "Running action '%s'\n", act_found->action);
+ ret = act_found->func(s, m);
+ acted = 1;
+ ast_module_unref(mod_ref);
}
+ } else {
+ ao2_unlock(act_found);
}
- ao2_unlock(act_found);
}
if (!acted) {
/*
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 76bdf87..1c73477 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -428,6 +428,7 @@
struct ast_sockaddr address = {{0,}};
struct ast_rtp_instance *instance = NULL;
struct ast_rtp_engine *engine = NULL;
+ struct ast_module *mod_ref;
AST_RWLIST_RDLOCK(&engines);
@@ -450,10 +451,15 @@
}
/* Bump up the reference count before we return so the module can not be unloaded */
- ast_module_ref(engine->mod);
+ mod_ref = ast_module_running_ref(engine->mod);
AST_RWLIST_UNLOCK(&engines);
+ if (!mod_ref) {
+ /* BUGBUG: improve handling of this situation. */
+ return NULL;
+ }
+
/* Allocate a new RTP instance */
if (!(instance = ao2_alloc(sizeof(*instance), instance_destructor))) {
ast_module_unref(engine->mod);
diff --git a/main/sorcery.c b/main/sorcery.c
index 51b55c5..eb78487 100644
--- a/main/sorcery.c
+++ b/main/sorcery.c
@@ -1011,16 +1011,19 @@
RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, ao2_alloc(sizeof(*object_wizard), sorcery_object_wizard_destructor), ao2_cleanup);
int created = 0;
- if (!wizard) {
+ if (!object_wizard) {
+ return AST_SORCERY_APPLY_FAIL;
+ }
+
+ if (!wizard || wizard->callbacks.module != ast_module_running_ref(wizard->callbacks.module)) {
ast_log(LOG_ERROR, "Wizard '%s' could not be applied to object type '%s' as it was not found\n",
name, type);
- return AST_SORCERY_APPLY_FAIL;
- } else if (!object_wizard) {
return AST_SORCERY_APPLY_FAIL;
}
if (!object_type) {
if (!(object_type = sorcery_object_type_alloc(type, module))) {
+ ast_module_unref(wizard->callbacks.module);
return AST_SORCERY_APPLY_FAIL;
}
created = 1;
@@ -1037,6 +1040,7 @@
ast_debug(1, "Wizard %s already applied to object type %s\n",
wizard->callbacks.name, object_type->name);
AST_VECTOR_RW_UNLOCK(&object_type->wizards);
+ ast_module_unref(wizard->callbacks.module);
return AST_SORCERY_APPLY_DUPLICATE;
}
}
@@ -1047,10 +1051,9 @@
ast_log(LOG_WARNING, "Wizard '%s' failed to open mapping for object type '%s' with data: %s\n",
name, object_type->name, S_OR(data, ""));
AST_VECTOR_RW_UNLOCK(&object_type->wizards);
+ ast_module_unref(wizard->callbacks.module);
return AST_SORCERY_APPLY_FAIL;
}
-
- ast_module_ref(wizard->callbacks.module);
object_wizard->wizard = ao2_bump(wizard);
object_wizard->caching = caching;
diff --git a/main/timing.c b/main/timing.c
index c6a9480..18852c6 100644
--- a/main/timing.c
+++ b/main/timing.c
@@ -124,17 +124,22 @@
void *data = NULL;
struct timing_holder *h;
struct ast_timer *t = NULL;
+ int idx = 1;
ast_heap_rdlock(timing_interfaces);
- if ((h = ast_heap_peek(timing_interfaces, 1))) {
- data = h->iface->timer_open();
- ast_module_ref(h->mod);
+ while ((h = ast_heap_peek(timing_interfaces, idx))) {
+ if (ast_module_running_ref(h->mod)) {
+ data = h->iface->timer_open();
+ break;
+ }
+ idx++;
}
if (data) {
if (!(t = ast_calloc(1, sizeof(*t)))) {
h->iface->timer_close(data);
+ ast_module_unref(h->mod);
} else {
t->data = data;
t->holder = h;
diff --git a/main/translate.c b/main/translate.c
index 02717c5..3d49057 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -342,7 +342,10 @@
*/
pvt->explicit_dst = ao2_bump(explicit_dst);
- ast_module_ref(t->module);
+ if (!ast_module_running_ref(t->module)) {
+ ast_free(pvt);
+ return NULL;
+ }
/* call local init routine, if present */
if (t->newpvt && t->newpvt(pvt)) {
diff --git a/res/res_agi.c b/res/res_agi.c
index 85914c0..393a503 100644
--- a/res/res_agi.c
+++ b/res/res_agi.c
@@ -4040,14 +4040,19 @@
parse_args(buf, &argc, argv);
c = find_command(argv, 0);
- if (c && (!dead || (dead && c->dead))) {
- /* if this command wasn't registered by res_agi, be sure to usecount
- the module we are using */
- if (c->mod != ast_module_info->self)
- ast_module_ref(c->mod);
+ if (!c || !ast_module_running_ref(c->mod)) {
+ ami_res = "Invalid or unknown command";
+ resultcode = 510;
+
+ ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
+
+ publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
+
+ return AGI_RESULT_SUCCESS;
+ }
+
+ if (!dead || (dead && c->dead)) {
res = c->handler(chan, agi, argc, argv);
- if (c->mod != ast_module_info->self)
- ast_module_unref(c->mod);
switch (res) {
case RESULT_SHOWUSAGE:
ami_res = "Usage";
@@ -4094,21 +4099,15 @@
break;
}
- } else if (c) {
+ } else {
ami_res = "Command Not Permitted on a dead channel or intercept routine";
resultcode = 511;
ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
- } else {
- ami_res = "Invalid or unknown command";
- resultcode = 510;
-
- ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
-
- publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
}
+ ast_module_unref(c->mod);
return AGI_RESULT_SUCCESS;
}
diff --git a/res/res_fax.c b/res/res_fax.c
index 0938452..4be5aee 100644
--- a/res/res_fax.c
+++ b/res/res_fax.c
@@ -1161,8 +1161,10 @@
if ((faxmod->tech->caps & details->caps) != details->caps) {
continue;
}
+ if (!ast_module_running_ref(faxmod->tech->module)) {
+ continue;
+ }
ast_debug(4, "Reserving a FAX session from '%s'.\n", faxmod->tech->description);
- ast_module_ref(faxmod->tech->module);
s->tech = faxmod->tech;
break;
}
@@ -1279,8 +1281,10 @@
if ((faxmod->tech->caps & details->caps) != details->caps) {
continue;
}
+ if (!ast_module_running_ref(faxmod->tech->module)) {
+ continue;
+ }
ast_debug(4, "Requesting a new FAX session from '%s'.\n", faxmod->tech->description);
- ast_module_ref(faxmod->tech->module);
if (reserved) {
/* Balance module ref from reserved session */
ast_module_unref(reserved->tech->module);
--
To view, visit https://gerrit.asterisk.org/7770
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia16fd28e188b2fc0b9d18b8a5d9cacc31df73fcc
Gerrit-Change-Number: 7770
Gerrit-PatchSet: 1
Gerrit-Owner: Corey Farrell <git at cfware.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20171229/5fc247ee/attachment-0001.html>
More information about the asterisk-code-review
mailing list