mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-17 23:38:23 +00:00
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:
@@ -248,6 +248,10 @@ static int feature_hangup(struct ast_bridge *bridge, struct ast_bridge_channel *
|
|||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
{
|
{
|
||||||
|
ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_HANGUP);
|
||||||
|
ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER);
|
||||||
|
ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_BLINDTRANSFER);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,8 +261,8 @@ static int load_module(void)
|
|||||||
ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL);
|
ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL);
|
||||||
ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
|
ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
|
||||||
|
|
||||||
/* Bump up our reference count so we can't be unloaded */
|
/* This module cannot be unloaded until shutdown */
|
||||||
ast_module_ref(ast_module_info->self);
|
ast_module_shutdown_ref(ast_module_info->self);
|
||||||
|
|
||||||
return AST_MODULE_LOAD_SUCCESS;
|
return AST_MODULE_LOAD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -269,8 +269,31 @@ void __ast_module_user_hangup_all(struct ast_module *);
|
|||||||
#define ast_module_user_remove(user) __ast_module_user_remove(ast_module_info->self, user)
|
#define ast_module_user_remove(user) __ast_module_user_remove(ast_module_info->self, user)
|
||||||
#define ast_module_user_hangup_all() __ast_module_user_hangup_all(ast_module_info->self)
|
#define ast_module_user_hangup_all() __ast_module_user_hangup_all(ast_module_info->self)
|
||||||
|
|
||||||
struct ast_module *ast_module_ref(struct ast_module *);
|
struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func);
|
||||||
void ast_module_unref(struct ast_module *);
|
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);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Hold a reference to the module
|
||||||
|
* \param mod Module to reference
|
||||||
|
* \return mod
|
||||||
|
*
|
||||||
|
* \note A module reference will prevent the module
|
||||||
|
* from being unloaded.
|
||||||
|
*/
|
||||||
|
#define ast_module_ref(mod) __ast_module_ref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||||
|
/*!
|
||||||
|
* \brief Prevent unload of the module before shutdown
|
||||||
|
* \param mod Module to hold
|
||||||
|
*
|
||||||
|
* \note This should not be balanced by a call to ast_module_unref.
|
||||||
|
*/
|
||||||
|
#define ast_module_shutdown_ref(mod) __ast_module_shutdown_ref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||||
|
/*!
|
||||||
|
* \brief Release a reference to the module
|
||||||
|
* \param mod Module to release
|
||||||
|
*/
|
||||||
|
#define ast_module_unref(mod) __ast_module_unref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
#define AST_MODULE_INFO(keystr, flags_to_set, desc, load_func, unload_func, reload_func, load_pri) \
|
#define AST_MODULE_INFO(keystr, flags_to_set, desc, load_func, unload_func, reload_func, load_pri) \
|
||||||
|
|||||||
@@ -92,12 +92,17 @@ static unsigned int embedding = 1; /* we always start out by registering embedde
|
|||||||
|
|
||||||
struct ast_module {
|
struct ast_module {
|
||||||
const struct ast_module_info *info;
|
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 */
|
void *lib; /* the shared lib, or NULL if embedded */
|
||||||
int usecount; /* the number of 'users' currently in this module */
|
int usecount; /* the number of 'users' currently in this module */
|
||||||
struct module_user_list users; /* the list of users in the module */
|
struct module_user_list users; /* the list of users in the module */
|
||||||
struct {
|
struct {
|
||||||
unsigned int running:1;
|
unsigned int running:1;
|
||||||
unsigned int declined:1;
|
unsigned int declined:1;
|
||||||
|
unsigned int keepuntilshutdown:1;
|
||||||
} flags;
|
} flags;
|
||||||
AST_LIST_ENTRY(ast_module) entry;
|
AST_LIST_ENTRY(ast_module) entry;
|
||||||
char resource[0];
|
char resource[0];
|
||||||
@@ -161,6 +166,9 @@ void ast_module_register(const struct ast_module_info *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod->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);
|
AST_LIST_HEAD_INIT(&mod->users);
|
||||||
|
|
||||||
/* during startup, before the loader has been initialized,
|
/* during startup, before the loader has been initialized,
|
||||||
@@ -206,6 +214,9 @@ void ast_module_unregister(const struct ast_module_info *info)
|
|||||||
|
|
||||||
if (mod) {
|
if (mod) {
|
||||||
AST_LIST_HEAD_DESTROY(&mod->users);
|
AST_LIST_HEAD_DESTROY(&mod->users);
|
||||||
|
#ifdef REF_DEBUG
|
||||||
|
ao2_cleanup(mod->ref_debug);
|
||||||
|
#endif
|
||||||
ast_free(mod);
|
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_INSERT_HEAD(&mod->users, u, entry);
|
||||||
AST_LIST_UNLOCK(&mod->users);
|
AST_LIST_UNLOCK(&mod->users);
|
||||||
|
|
||||||
|
#ifdef REF_DEBUG
|
||||||
|
ao2_ref(mod->ref_debug, +1);
|
||||||
|
#endif
|
||||||
|
|
||||||
ast_atomic_fetchadd_int(&mod->usecount, +1);
|
ast_atomic_fetchadd_int(&mod->usecount, +1);
|
||||||
|
|
||||||
ast_update_use_count();
|
ast_update_use_count();
|
||||||
@@ -249,6 +264,10 @@ void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef REF_DEBUG
|
||||||
|
ao2_ref(mod->ref_debug, -1);
|
||||||
|
#endif
|
||||||
|
|
||||||
ast_atomic_fetchadd_int(&mod->usecount, -1);
|
ast_atomic_fetchadd_int(&mod->usecount, -1);
|
||||||
ast_free(u);
|
ast_free(u);
|
||||||
|
|
||||||
@@ -264,6 +283,11 @@ void __ast_module_user_hangup_all(struct ast_module *mod)
|
|||||||
if (u->chan) {
|
if (u->chan) {
|
||||||
ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
|
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_atomic_fetchadd_int(&mod->usecount, -1);
|
||||||
ast_free(u);
|
ast_free(u);
|
||||||
}
|
}
|
||||||
@@ -544,10 +568,22 @@ void ast_module_shutdown(void)
|
|||||||
mod->info->unload();
|
mod->info->unload();
|
||||||
}
|
}
|
||||||
AST_LIST_HEAD_DESTROY(&mod->users);
|
AST_LIST_HEAD_DESTROY(&mod->users);
|
||||||
|
#ifdef REF_DEBUG
|
||||||
|
ao2_cleanup(mod->ref_debug);
|
||||||
|
#endif
|
||||||
free(mod);
|
free(mod);
|
||||||
somethingchanged = 1;
|
somethingchanged = 1;
|
||||||
}
|
}
|
||||||
AST_LIST_TRAVERSE_SAFE_END;
|
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);
|
} while (somethingchanged && !final);
|
||||||
|
|
||||||
AST_LIST_UNLOCK(&module_list);
|
AST_LIST_UNLOCK(&module_list);
|
||||||
@@ -1324,24 +1360,60 @@ int ast_loader_unregister(int (*v)(void))
|
|||||||
return cur ? 0 : -1;
|
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) {
|
if (!mod) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef REF_DEBUG
|
||||||
|
__ao2_ref_debug(mod->ref_debug, +1, "", file, line, func);
|
||||||
|
#endif
|
||||||
|
|
||||||
ast_atomic_fetchadd_int(&mod->usecount, +1);
|
ast_atomic_fetchadd_int(&mod->usecount, +1);
|
||||||
ast_update_use_count();
|
ast_update_use_count();
|
||||||
|
|
||||||
return mod;
|
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) {
|
if (!mod) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef REF_DEBUG
|
||||||
|
__ao2_ref_debug(mod->ref_debug, -1, "", file, line, func);
|
||||||
|
#endif
|
||||||
|
|
||||||
ast_atomic_fetchadd_int(&mod->usecount, -1);
|
ast_atomic_fetchadd_int(&mod->usecount, -1);
|
||||||
ast_update_use_count();
|
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__);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user