]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Enable REF_DEBUG for ast_module_ref / ast_module_unref.
authorCorey Farrell <git@cfware.com>
Wed, 11 Feb 2015 15:38:39 +0000 (15:38 +0000)
committerCorey Farrell <git@cfware.com>
Wed, 11 Feb 2015 15:38:39 +0000 (15:38 +0000)
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

bridges/bridge_builtin_features.c
include/asterisk/module.h
main/loader.c

index 21af928550ae7612403f427d912f8493c4214a09..823ef1c932a9564d29e19ec923287651a4698cdc 100644 (file)
@@ -248,6 +248,10 @@ static int feature_hangup(struct ast_bridge *bridge, struct ast_bridge_channel *
 
 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;
 }
 
@@ -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_HANGUP, feature_hangup, NULL);
 
-       /* Bump up our reference count so we can't be unloaded */
-       ast_module_ref(ast_module_info->self);
+       /* This module cannot be unloaded until shutdown */
+       ast_module_shutdown_ref(ast_module_info->self);
 
        return AST_MODULE_LOAD_SUCCESS;
 }
index df9f241378e9a41a78a5549de39b78232abda4b2..e4c66965ef7f582f791b4bbb8ed8d14f63348c30 100644 (file)
@@ -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_hangup_all() __ast_module_user_hangup_all(ast_module_info->self)
 
-struct ast_module *ast_module_ref(struct ast_module *);
-void ast_module_unref(struct ast_module *);
+struct ast_module *__ast_module_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);
+
+/*!
+ * \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)
 #define AST_MODULE_INFO(keystr, flags_to_set, desc, load_func, unload_func, reload_func, load_pri)     \
index 24ab24bc8f18c2463caa6096aa8102762923380e..c4d438a3d9b5f6bf9bd0e5e8f952714f9c5343a9 100644 (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__);
+}
+