Enable REF_DEBUG for ast_module_ref / ast_module_unref.

Add ast_module_shutdown_ref for use by modules that can
only be unloaded during graceful shutdown.

When REF_DEBUG is enabled:
* Add an empty ao2 object to struct ast_module.
* Allocate ao2 object when the module is loaded.
* Perform an ao2_ref in each place where mod->usecount is manipulated.
* ao2_cleanup on module unload.

ASTERISK-24479 #close
Reported by: Corey Farrell
Review: https://reviewboard.asterisk.org/r/4141/


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@431662 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Corey Farrell
2015-02-11 15:38:39 +00:00
parent bc1e13dfc3
commit 9d5c52f10b
3 changed files with 105 additions and 6 deletions

View File

@@ -92,12 +92,17 @@ static unsigned int embedding = 1; /* we always start out by registering embedde
struct ast_module {
const struct ast_module_info *info;
#ifdef REF_DEBUG
/* Used to get module references into REF_DEBUG logs */
void *ref_debug;
#endif
void *lib; /* the shared lib, or NULL if embedded */
int usecount; /* the number of 'users' currently in this module */
struct module_user_list users; /* the list of users in the module */
struct {
unsigned int running:1;
unsigned int declined:1;
unsigned int keepuntilshutdown:1;
} flags;
AST_LIST_ENTRY(ast_module) entry;
char resource[0];
@@ -161,6 +166,9 @@ void ast_module_register(const struct ast_module_info *info)
}
mod->info = info;
#ifdef REF_DEBUG
mod->ref_debug = ao2_t_alloc(0, NULL, info->name);
#endif
AST_LIST_HEAD_INIT(&mod->users);
/* during startup, before the loader has been initialized,
@@ -206,6 +214,9 @@ void ast_module_unregister(const struct ast_module_info *info)
if (mod) {
AST_LIST_HEAD_DESTROY(&mod->users);
#ifdef REF_DEBUG
ao2_cleanup(mod->ref_debug);
#endif
ast_free(mod);
}
}
@@ -225,6 +236,10 @@ struct ast_module_user *__ast_module_user_add(struct ast_module *mod, struct ast
AST_LIST_INSERT_HEAD(&mod->users, u, entry);
AST_LIST_UNLOCK(&mod->users);
#ifdef REF_DEBUG
ao2_ref(mod->ref_debug, +1);
#endif
ast_atomic_fetchadd_int(&mod->usecount, +1);
ast_update_use_count();
@@ -249,6 +264,10 @@ void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
return;
}
#ifdef REF_DEBUG
ao2_ref(mod->ref_debug, -1);
#endif
ast_atomic_fetchadd_int(&mod->usecount, -1);
ast_free(u);
@@ -264,6 +283,11 @@ void __ast_module_user_hangup_all(struct ast_module *mod)
if (u->chan) {
ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
}
#ifdef REF_DEBUG
ao2_ref(mod->ref_debug, -1);
#endif
ast_atomic_fetchadd_int(&mod->usecount, -1);
ast_free(u);
}
@@ -544,10 +568,22 @@ void ast_module_shutdown(void)
mod->info->unload();
}
AST_LIST_HEAD_DESTROY(&mod->users);
#ifdef REF_DEBUG
ao2_cleanup(mod->ref_debug);
#endif
free(mod);
somethingchanged = 1;
}
AST_LIST_TRAVERSE_SAFE_END;
if (!somethingchanged) {
AST_LIST_TRAVERSE(&module_list, mod, entry) {
if (mod->flags.keepuntilshutdown) {
ast_module_unref(mod);
mod->flags.keepuntilshutdown = 0;
somethingchanged = 1;
}
}
}
} while (somethingchanged && !final);
AST_LIST_UNLOCK(&module_list);
@@ -1324,24 +1360,60 @@ int ast_loader_unregister(int (*v)(void))
return cur ? 0 : -1;
}
struct ast_module *ast_module_ref(struct ast_module *mod)
struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func)
{
if (!mod) {
return NULL;
}
#ifdef REF_DEBUG
__ao2_ref_debug(mod->ref_debug, +1, "", file, line, func);
#endif
ast_atomic_fetchadd_int(&mod->usecount, +1);
ast_update_use_count();
return mod;
}
void ast_module_unref(struct ast_module *mod)
void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
{
if (!mod->flags.keepuntilshutdown) {
__ast_module_ref(mod, file, line, func);
mod->flags.keepuntilshutdown = 1;
}
}
void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func)
{
if (!mod) {
return;
}
#ifdef REF_DEBUG
__ao2_ref_debug(mod->ref_debug, -1, "", file, line, func);
#endif
ast_atomic_fetchadd_int(&mod->usecount, -1);
ast_update_use_count();
}
/* The following exists for ABI compatibility */
#undef ast_module_ref
#undef ast_module_unref
struct ast_module *ast_module_ref(struct ast_module *mod);
void ast_module_unref(struct ast_module *mod);
struct ast_module *ast_module_ref(struct ast_module *mod)
{
return __ast_module_ref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__);
}
void ast_module_unref(struct ast_module *mod)
{
__ast_module_unref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__);
}