]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Fix a variety of ref counting issues
authorMatthew Jordan <mjordan@digium.com>
Tue, 2 Oct 2012 01:27:19 +0000 (01:27 +0000)
committerMatthew Jordan <mjordan@digium.com>
Tue, 2 Oct 2012 01:27:19 +0000 (01:27 +0000)
This patch resolves a number of ref leaks that occur primarily on Asterisk
shutdown.  It adds a variety of shutdown routines to core portions of
Asterisk such that they can reclaim resources allocate duringd initialization.

Review: https://reviewboard.asterisk.org/r/2137
........

Merged revisions 374177 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 374178 from http://svn.asterisk.org/svn/asterisk/branches/10

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@374196 65c4cc65-6c06-0410-ace0-fbb531ad65f3

24 files changed:
channels/chan_agent.c
include/asterisk/astobj2.h
main/asterisk.c
main/astobj2.c
main/ccss.c
main/cel.c
main/channel.c
main/config_options.c
main/data.c
main/db.c
main/event.c
main/features.c
main/format.c
main/format_pref.c
main/indications.c
main/manager.c
main/message.c
main/named_acl.c
main/pbx.c
main/taskprocessor.c
main/udptl.c
main/xmldoc.c
res/res_musiconhold.c
res/res_xmpp.c

index e44ccec01f17964b0e538269adf8d01413e6c8da..8f1162a50d8ac2dc03f81901633f1e4777420b6a 100644 (file)
@@ -2590,12 +2590,15 @@ static int load_module(void)
        ast_format_cap_add_all(agent_tech.capabilities);
        /* Make sure we can register our agent channel type */
        if (ast_channel_register(&agent_tech)) {
+               agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
                ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
                return AST_MODULE_LOAD_FAILURE;
        }
        /* Read in the config */
-       if (!read_agent_config(0))
+       if (!read_agent_config(0)) {
+               agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
                return AST_MODULE_LOAD_DECLINE;
+       }
        /* Dialplan applications */
        ast_register_application_xml(app, login_exec);
        ast_register_application_xml(app3, agentmonitoroutgoing_exec);
index 5cf770a7ca2d1a45134cd0e15c28dcd1e23fa67a..81d074e1409f4475d9ccc5801441793e008c1f13 100644 (file)
@@ -1465,6 +1465,12 @@ void ao2_bt(void);       /* backtrace */
  * \note they must be able to handle NULL parameters because most of the
  * allocation/find functions can fail and we don't want to try to tear
  * down a NULL */
-void ao2_cleanup(void *obj);
+void __ao2_cleanup(void *obj);
+void __ao2_cleanup_debug(void *obj, const char *file, int line, const char *function);
+#ifdef REF_DEBUG
+#define ao2_cleanup(obj) __ao2_cleanup_debug((obj), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#else
+#define ao2_cleanup(obj) __ao2_cleanup(obj)
+#endif
 void ao2_iterator_cleanup(struct ao2_iterator *iter);
 #endif /* _ASTERISK_ASTOBJ2_H */
index e8b9b34dea9d9a6615beabd391f856935724cc84..6a04cf3a1b9b09ffd60fc608c935744dc7f63a1f 100644 (file)
@@ -1702,6 +1702,9 @@ static int can_safely_quit(shutdown_nice_t niceness, int restart)
         * (if in batch mode). really_quit happens to call it again when running
         * the atexit handlers, otherwise this would be a bit early. */
        ast_cdr_engine_term();
+
+       /* Shutdown the message queue for the technology agnostic message channel.
+        * This has to occur before we pause shutdown pending ast_undestroyed_channels. */
        ast_msg_shutdown();
 
        if (niceness == SHUTDOWN_NORMAL) {
index 176ea5aea41e96eea564c0af768188883f7ce9b6..0f4f2e05c58787d49d3f156fbe4efb53066e8987 100644 (file)
@@ -1528,7 +1528,14 @@ struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, en
        return clone;
 }
 
-void ao2_cleanup(void *obj)
+void __ao2_cleanup_debug(void *obj, const char *file, int line, const char *function)
+{
+       if (obj) {
+               __ao2_ref_debug(obj, -1, "ao2_cleanup", file, line, function);
+       }
+}
+
+void __ao2_cleanup(void *obj)
 {
        if (obj) {
                ao2_ref(obj, -1);
index 76b02dac6cae6bb15c5008c971d5254f63786738..9f656d38638edd89b52659a5b2b9f11cce03b391 100644 (file)
@@ -4518,6 +4518,31 @@ static struct ast_cli_entry cc_cli[] = {
        AST_CLI_DEFINE(handle_cc_kill, "Kill a CC transaction"),
 };
 
+static void cc_shutdown(void)
+{
+       ast_devstate_prov_del("ccss");
+       ast_cc_agent_unregister(&generic_agent_callbacks);
+       ast_cc_monitor_unregister(&generic_monitor_cbs);
+       ast_unregister_application(cccancel_app);
+       ast_unregister_application(ccreq_app);
+
+       if (cc_sched_context) {
+               ast_sched_context_destroy(cc_sched_context);
+               cc_sched_context = NULL;
+       }
+       if (cc_core_taskprocessor) {
+               cc_core_taskprocessor = ast_taskprocessor_unreference(cc_core_taskprocessor);
+       }
+       if (generic_monitors) {
+               ao2_t_ref(generic_monitors, -1, "Unref generic_monitor container in cc_shutdown");
+               generic_monitors = NULL;
+       }
+       if (cc_core_instances) {
+               ao2_t_ref(cc_core_instances, -1, "Unref cc_core_instances container in cc_shutdown");
+               cc_core_instances = NULL;
+       }
+}
+
 int ast_cc_init(void)
 {
        int res;
@@ -4555,5 +4580,7 @@ int ast_cc_init(void)
        initialize_cc_devstate_map();
        res |= ast_devstate_prov_add("ccss", ccss_device_state);
 
+       ast_register_atexit(cc_shutdown);
+
        return res;
 }
index 35f78cadf2181b144dc00aa41104a646ac88adfc..3301e81e7fc1881d03cfaaf50229222f3cd6c95c 100644 (file)
@@ -716,6 +716,10 @@ static void ast_cel_engine_term(void)
                ao2_ref(appset, -1);
                appset = NULL;
        }
+       if (linkedids) {
+               ao2_ref(linkedids, -1);
+               linkedids = NULL;
+       }
 }
 
 int ast_cel_engine_init(void)
index d2049fadcd516caaf2947ae176eec05acb92dbff..2232097ff61490e86f3544865896dea27b7f3178 100644 (file)
@@ -8505,6 +8505,14 @@ static const struct ast_data_entry channel_providers[] = {
        AST_DATA_ENTRY("/asterisk/core/channeltypes", &channeltypes_provider),
 };
 
+static void channels_shutdown(void)
+{
+       ast_data_unregister(NULL);
+       if (channels) {
+               ao2_ref(channels, -1);
+       }
+}
+
 void ast_channels_init(void)
 {
        channels = ao2_container_alloc(NUM_CHANNEL_BUCKETS,
@@ -8515,6 +8523,8 @@ void ast_channels_init(void)
        ast_data_register_multiple_core(channel_providers, ARRAY_LEN(channel_providers));
 
        ast_plc_reload();
+
+       ast_register_atexit(channels_shutdown);
 }
 
 /*! \brief Print call group and pickup group ---*/
index c350ee5f69f8191faf04a59399f034a0c74987b5..5e76a7a7be3919004e18b33e5fe599ad18932055 100644 (file)
@@ -158,6 +158,8 @@ static int link_option_to_types(struct aco_type **types, struct aco_option *opt)
                        }
                        return -1;
                }
+               /* The container should hold the only ref to opt */
+               ao2_ref(opt, -1);
        }
        return 0;
 }
index c5a34543c875006450b83cafbaed149343282a38..7a19b1f8f74d730f6599b9ecaf2791c87423e4c4 100644 (file)
@@ -3314,6 +3314,14 @@ AST_TEST_DEFINE(test_data_get)
 
 #endif
 
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void data_shutdown(void)
+{
+       ast_manager_unregister("DataGet");
+       ao2_t_ref(root_data.container, -1, "Unref root_data.container in data_shutdown");
+       ast_rwlock_destroy(&root_data.lock);
+}
+
 int ast_data_init(void)
 {
        int res = 0;
@@ -3333,5 +3341,7 @@ int ast_data_init(void)
        AST_TEST_REGISTER(test_data_get);
 #endif
 
+       ast_register_atexit(data_shutdown);
+
        return res;
 }
index 05ae26cc9b8b8bde5b76613776f2bbc7d72de2a1..2a19ce9315f31299083729f608bd8ec22d757b5a 100644 (file)
--- a/main/db.c
+++ b/main/db.c
@@ -946,8 +946,14 @@ static void *db_sync_thread(void *data)
        return NULL;
 }
 
+/*! \internal \brief Clean up resources on Asterisk shutdown */
 static void astdb_atexit(void)
 {
+       ast_manager_unregister("DBGet");
+       ast_manager_unregister("DBPut");
+       ast_manager_unregister("DBDel");
+       ast_manager_unregister("DBDelTree");
+
        /* Set doexit to 1 to kill thread. db_sync must be called with
         * mutex held. */
        doexit = 1;
index 12d3abb7fde96463fe406dba4eafd32d54cb8b9a..4c231fe91f2d9b5d13ec43649b98d391fd12162a 100644 (file)
@@ -1811,6 +1811,38 @@ static struct ast_cli_entry event_cli[] = {
        AST_CLI_DEFINE(event_dump_cache, "Dump the internal event cache (for debugging)"),
 };
 
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void event_shutdown(void)
+{
+       struct ast_event_sub *sub;
+       int i;
+
+       if (event_dispatcher) {
+               event_dispatcher = ast_taskprocessor_unreference(event_dispatcher);
+       }
+
+       /* Remove any remaining subscriptions.  Note that we can't just call
+        * unsubscribe, as it will attempt to lock the subscription list
+        * as well */
+       for (i = 0; i < AST_EVENT_TOTAL; i++) {
+               AST_RWDLLIST_WRLOCK(&ast_event_subs[i]);
+               while ((sub = AST_RWDLLIST_REMOVE_HEAD(&ast_event_subs[i], entry))) {
+                       ast_event_sub_destroy(sub);
+               }
+               AST_RWDLLIST_UNLOCK(&ast_event_subs[i]);
+               AST_RWDLLIST_HEAD_DESTROY(&ast_event_subs[i]);
+       }
+
+       for (i = 0; i < AST_EVENT_TOTAL; i++) {
+               if (!ast_event_cache[i].hash_fn) {
+                       continue;
+               }
+               if (ast_event_cache[i].container) {
+                       ao2_ref(ast_event_cache[i].container, -1);
+               }
+       }
+}
+
 int ast_event_init(void)
 {
        int i;
@@ -1827,17 +1859,23 @@ int ast_event_init(void)
 
                if (!(ast_event_cache[i].container = ao2_container_alloc(NUM_CACHE_BUCKETS,
                                ast_event_hash, ast_event_cmp))) {
-                       return -1;
+                       goto event_init_cleanup;
                }
        }
 
        if (!(event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0))) {
-               return -1;
+               goto event_init_cleanup;
        }
 
        ast_cli_register_multiple(event_cli, ARRAY_LEN(event_cli));
 
+       ast_register_atexit(event_shutdown);
+
        return 0;
+
+event_init_cleanup:
+       event_shutdown();
+       return -1;
 }
 
 size_t ast_event_minimum_length(void)
index f89ca816d43c299c9bad938ec90f08a4b694baa5..e84a2a27154e5bde20c716cdc2b0b2e998e139c4 100644 (file)
@@ -7023,7 +7023,6 @@ static int load_config(int reload)
                        return -1;
                }
                ast_debug(1, "Configuration of default default parking lot done.\n");
-               parkinglot_addref(default_parkinglot);
        }
 
        cfg = ast_config_load2("features.conf", "features", config_flags);
@@ -8958,6 +8957,24 @@ static struct ast_custom_function featuremap_function = {
        .write = featuremap_write
 };
 
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void features_shutdown(void)
+{
+       ast_devstate_prov_del("Park");
+       ast_custom_function_unregister(&featuremap_function);
+       ast_custom_function_unregister(&feature_function);
+       ast_manager_unregister("Bridge");
+       ast_manager_unregister("Park");
+       ast_manager_unregister("Parkinglots");
+       ast_manager_unregister("ParkedCalls");
+       ast_unregister_application(parkcall);
+       ast_unregister_application(parkedcall);
+       ast_unregister_application(app_bridge);
+
+       pthread_cancel(parking_thread);
+       ao2_ref(parkinglots, -1);
+}
+
 int ast_features_init(void)
 {
        int res;
@@ -8993,6 +9010,8 @@ int ast_features_init(void)
        res |= AST_TEST_REGISTER(features_test);
 #endif /* defined(TEST_FRAMEWORK) */
 
+       ast_register_atexit(features_shutdown);
+
        return res;
 }
 
index 2d37eb458b8182a2acd1c4d2770b460b28b8fb77..139dfd331009644c65c123583470326eaa0c32d1 100644 (file)
@@ -957,6 +957,7 @@ static int format_list_add_static(
        entry->custom_entry = 0;
 
        ao2_link(format_list, entry);
+       ao2_ref(entry, -1);
        return 0;
 }
 
@@ -1025,6 +1026,7 @@ static int build_format_list_array(void)
        ast_rwlock_unlock(&format_list_array_lock);
        return 0;
 }
+
 static int format_list_init(void)
 {
        struct ast_format tmpfmt;
@@ -1074,6 +1076,20 @@ static int format_list_init(void)
        return 0;
 }
 
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void format_list_shutdown(void)
+{
+       ast_rwlock_destroy(&format_list_array_lock);
+       if (format_list) {
+               ao2_t_ref(format_list, -1, "Unref format_list container in shutdown");
+               format_list = NULL;
+       }
+       if (format_list_array) {
+               ao2_t_ref(format_list_array, -1, "Unref format_list_array in shutdown");
+               format_list_array = NULL;
+       }
+}
+
 int ast_format_list_init(void)
 {
        if (ast_rwlock_init(&format_list_array_lock)) {
@@ -1086,17 +1102,23 @@ int ast_format_list_init(void)
                goto init_list_cleanup;
        }
 
+       ast_register_atexit(format_list_shutdown);
        return 0;
 init_list_cleanup:
 
-       ast_rwlock_destroy(&format_list_array_lock);
-       ao2_ref(format_list, -1);
-       if (format_list_array) {
-               ao2_ref(format_list_array, -1);
-       }
+       format_list_shutdown();
        return -1;
 }
 
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void format_attr_shutdown(void)
+{
+       if (interfaces) {
+               ao2_ref(interfaces, -1);
+               interfaces = NULL;
+       }
+}
+
 int ast_format_attr_init(void)
 {
        ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
@@ -1106,6 +1128,7 @@ int ast_format_attr_init(void)
        if (!interfaces) {
                return -1;
        }
+       ast_register_atexit(format_attr_shutdown);
        return 0;
 }
 
@@ -1371,7 +1394,7 @@ int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interf
                        ast_rtp_engine_load_format(&f_list[x].format);
                }
        }
-
+       f_list = ast_format_list_destroy(f_list);
        return 0;
 }
 
@@ -1405,6 +1428,6 @@ int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *inte
 
        /* This will remove all custom formats previously created for this interface */
        load_format_config();
-
+       f_list = ast_format_list_destroy(f_list);
        return 0;
 }
index 9cb513c2285a364f4c73d274fa40e7aa328c4ffa..8b495ba56740ef86ddf1888f97365349930e47c3 100644 (file)
@@ -285,6 +285,7 @@ struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, struc
 
        if (idx < 0) {
                ast_log(AST_LOG_WARNING, "Format %s unknown; unable to get preferred codec packet size\n", ast_getformatname(format));
+               ast_format_list_destroy(f_list);
                return fmt;
        }
 
index 4f0fc29480074c614b14f0b10bc42f5ab5b8f609..f3356d60309242c8a0a50a826d0f7f1ed0d1fc78 100644 (file)
@@ -1150,6 +1150,15 @@ int ast_tone_zone_data_add_structure(struct ast_data *tree, struct ast_tone_zone
        return 0;
 }
 
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void indications_shutdown(void)
+{
+       if (ast_tone_zones) {
+               ao2_ref(ast_tone_zones, -1);
+               ast_tone_zones = NULL;
+       }
+}
+
 /*! \brief Load indications module */
 int ast_indications_init(void)
 {
@@ -1164,6 +1173,7 @@ int ast_indications_init(void)
 
        ast_cli_register_multiple(cli_indications, ARRAY_LEN(cli_indications));
 
+       ast_register_atexit(indications_shutdown);
        return 0;
 }
 
index 19c7b67fffff50c3799e16dfd8ee32770925b7d9..6fd81a3515bbc49a1d60ea709d808b1b6ed02178 100644 (file)
@@ -7225,6 +7225,66 @@ static void load_channelvars(struct ast_variable *var)
        AST_RWLIST_UNLOCK(&channelvars);
 }
 
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void manager_shutdown(void)
+{
+       struct ast_manager_user *user;
+
+       if (registered) {
+               ast_manager_unregister("Ping");
+               ast_manager_unregister("Events");
+               ast_manager_unregister("Logoff");
+               ast_manager_unregister("Login");
+               ast_manager_unregister("Challenge");
+               ast_manager_unregister("Hangup");
+               ast_manager_unregister("Status");
+               ast_manager_unregister("Setvar");
+               ast_manager_unregister("Getvar");
+               ast_manager_unregister("GetConfig");
+               ast_manager_unregister("GetConfigJSON");
+               ast_manager_unregister("UpdateConfig");
+               ast_manager_unregister("CreateConfig");
+               ast_manager_unregister("ListCategories");
+               ast_manager_unregister("Redirect");
+               ast_manager_unregister("Atxfer");
+               ast_manager_unregister("Originate");
+               ast_manager_unregister("Command");
+               ast_manager_unregister("ExtensionState");
+               ast_manager_unregister("PresenceState");
+               ast_manager_unregister("AbsoluteTimeout");
+               ast_manager_unregister("MailboxStatus");
+               ast_manager_unregister("MailboxCount");
+               ast_manager_unregister("ListCommands");
+               ast_manager_unregister("SendText");
+               ast_manager_unregister("UserEvent");
+               ast_manager_unregister("WaitEvent");
+               ast_manager_unregister("CoreSettings");
+               ast_manager_unregister("CoreStatus");
+               ast_manager_unregister("Reload");
+               ast_manager_unregister("CoreShowChannels");
+               ast_manager_unregister("ModuleLoad");
+               ast_manager_unregister("ModuleCheck");
+               ast_manager_unregister("AOCMessage");
+               ast_manager_unregister("Filter");
+               ast_custom_function_unregister(&managerclient_function);
+       }
+
+#ifdef AST_XML_DOCS
+       ao2_t_global_obj_release(event_docs, "Dispose of event_docs");
+#endif
+
+       if (sessions) {
+               ao2_ref(sessions, -1);
+               sessions = NULL;
+       }
+
+       while ((user = AST_LIST_REMOVE_HEAD(&users, list))) {
+               ao2_ref(user->whitefilters, -1);
+               ao2_ref(user->blackfilters, -1);
+               ast_free(user);
+       }
+}
+
 static int __init_manager(int reload, int by_external_config)
 {
        struct ast_config *ucfg = NULL, *cfg = NULL;
@@ -7295,13 +7355,13 @@ static int __init_manager(int reload, int by_external_config)
 #ifdef AST_XML_DOCS
        temp_event_docs = ast_xmldoc_build_documentation("managerEvent");
        if (temp_event_docs) {
-               temp_event_docs = ao2_global_obj_replace(event_docs, temp_event_docs);
-               if (temp_event_docs) {
-                       ao2_ref(temp_event_docs, -1);
-               }
+               ao2_t_global_obj_replace_unref(event_docs, temp_event_docs, "Toss old event docs");
+               ao2_t_ref(temp_event_docs, -1, "Remove creation ref - container holds only ref now");
        }
 #endif
 
+       ast_register_atexit(manager_shutdown);
+
        if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
                return 0;
        }
@@ -7700,6 +7760,7 @@ static int __init_manager(int reload, int by_external_config)
        } else if (ast_ssl_setup(amis_desc.tls_cfg)) {
                ast_tcptls_server_start(&amis_desc);
        }
+
        return 0;
 }
 
index c04413dc8fd47ef9c4dde056c7ef510e5329ef92..f764e2774b09991e3919eceac8a5867ac7afeb1b 100644 (file)
@@ -1302,6 +1302,30 @@ int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
        return 0;
 }
 
+void ast_msg_shutdown()
+{
+       if (msg_q_tp) {
+               msg_q_tp = ast_taskprocessor_unreference(msg_q_tp);
+       }
+}
+
+/*! \internal \brief Clean up other resources on Asterisk shutdown
+ * \note This does not include the msg_q_tp object, which must be disposed
+ * of prior to Asterisk checking for channel destruction in its shutdown
+ * sequence.  The atexit handlers are executed after this occurs. */
+static void message_shutdown(void)
+{
+       ast_custom_function_unregister(&msg_function);
+       ast_custom_function_unregister(&msg_data_function);
+       ast_unregister_application(app_msg_send);
+       ast_manager_unregister("MessageSend");
+
+       if (msg_techs) {
+               ao2_ref(msg_techs, -1);
+               msg_techs = NULL;
+       }
+}
+
 /*
  * \internal
  * \brief Initialize stuff during Asterisk startup.
@@ -1331,10 +1355,7 @@ int ast_msg_init(void)
        res |= ast_register_application2(app_msg_send, msg_send_exec, NULL, NULL, NULL);
        res |= ast_manager_register_xml_core("MessageSend", EVENT_FLAG_MESSAGE, action_messagesend);
 
-       return res;
-}
+       ast_register_atexit(message_shutdown);
 
-void ast_msg_shutdown(void)
-{
-       msg_q_tp = ast_taskprocessor_unreference(msg_q_tp);
+       return res;
 }
index cd6a8d68da1dea54ea07c6e34c68f1244fe88544..6c6d3aa615a5273c04d57a3bcdc56be9e6f27065 100644 (file)
@@ -545,6 +545,7 @@ int ast_named_acl_init()
        aco_option_register(&cfg_info, "deny", ACO_EXACT, named_acl_types, NULL, OPT_ACL_T, 0, FLDSET(struct named_acl, ha));
 
        if (aco_process_config(&cfg_info, 0)) {
+               aco_info_destroy(&cfg_info);
                return 0;
        }
 
index 165cb862befe1b5e3164ae8ed8f413cdb81360ef..fa38b1e2a3ef4184be3d31dd6fffffa9cb745cf4 100644 (file)
@@ -11481,6 +11481,32 @@ static const struct ast_data_entry pbx_data_providers[] = {
        AST_DATA_ENTRY("asterisk/core/hints", &hints_data_provider),
 };
 
+/*! \internal \brief Clean up resources on Asterisk shutdown.
+ * \note Cleans up resources allocated in load_pbx */
+static void unload_pbx(void)
+{
+       int x;
+
+       if (presence_state_sub) {
+               presence_state_sub = ast_event_unsubscribe(presence_state_sub);
+       }
+       if (device_state_sub) {
+               device_state_sub = ast_event_unsubscribe(device_state_sub);
+       }
+
+       /* Unregister builtin applications */
+       for (x = 0; x < ARRAY_LEN(builtins); x++) {
+               ast_unregister_application(builtins[x].name);
+       }
+       ast_manager_unregister("ShowDialPlan");
+       ast_custom_function_unregister(&exception_function);
+       ast_custom_function_unregister(&testtime_function);
+       ast_data_unregister(NULL);
+       if (extension_state_tps) {
+               extension_state_tps = ast_taskprocessor_unreference(extension_state_tps);
+       }
+}
+
 int load_pbx(void)
 {
        int x;
@@ -11519,6 +11545,7 @@ int load_pbx(void)
                return -1;
        }
 
+       ast_register_atexit(unload_pbx);
        return 0;
 }
 
@@ -11879,11 +11906,26 @@ static int statecbs_cmp(void *obj, void *arg, int flags)
        return (state_cb->change_cb == change_cb) ? CMP_MATCH | CMP_STOP : 0;
 }
 
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void pbx_shutdown(void)
+{
+       if (hints) {
+               ao2_ref(hints, -1);
+       }
+       if (hintdevices) {
+               ao2_ref(hintdevices, -1);
+       }
+       if (statecbs) {
+               ao2_ref(statecbs, -1);
+       }
+}
+
 int ast_pbx_init(void)
 {
        hints = ao2_container_alloc(HASH_EXTENHINT_SIZE, hint_hash, hint_cmp);
        hintdevices = ao2_container_alloc(HASH_EXTENHINT_SIZE, hintdevice_hash_cb, hintdevice_cmp_multiple);
        statecbs = ao2_container_alloc(1, NULL, statecbs_cmp);
 
+       ast_register_atexit(pbx_shutdown);
        return (hints && hintdevices && statecbs) ? 0 : -1;
 }
index e92b6948b82fabb1296fed0c0d249723be6fc885..912f891b17677f1580cfd8e4cd539c34dffcb1b2 100644 (file)
@@ -122,6 +122,12 @@ static struct ast_cli_entry taskprocessor_clis[] = {
        AST_CLI_DEFINE(cli_tps_report, "List instantiated task processors and statistics"),
 };
 
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void tps_shutdown(void)
+{
+       ao2_t_ref(tps_singletons, -1, "Unref tps_singletons in shutdown");
+}
+
 /* initialize the taskprocessor container and register CLI operations */
 int ast_tps_init(void)
 {
@@ -133,6 +139,9 @@ int ast_tps_init(void)
        ast_cond_init(&cli_ping_cond, NULL);
 
        ast_cli_register_multiple(taskprocessor_clis, ARRAY_LEN(taskprocessor_clis));
+
+       ast_register_atexit(tps_shutdown);
+
        return 0;
 }
 
index 3d110e21b6f0b6d7a8c65903817dddc4e8f70041..83dcd3d908cc8d4035d092bfb7fc008668b9a9aa 100644 (file)
@@ -1462,6 +1462,13 @@ int ast_udptl_reload(void)
        return 0;
 }
 
+/*! \internal \brief Clean up resources on Asterisk shutdown */
+static void udptl_shutdown(void)
+{
+       ao2_t_global_obj_release(globals, "Unref udptl global container in shutdown");
+       aco_info_destroy(&cfg_info);
+}
+
 void ast_udptl_init(void)
 {
        if (aco_info_init(&cfg_info)) {
@@ -1496,4 +1503,6 @@ void ast_udptl_init(void)
        ast_cli_register_multiple(cli_udptl, ARRAY_LEN(cli_udptl));
 
        __ast_udptl_reload(0);
+
+       ast_register_atexit(udptl_shutdown);
 }
index 0dc56c4b3204485d7b1f54c7140b2ff6f646666d..5d78102949e852bb76e20896ca441af986136f70 100644 (file)
@@ -2278,6 +2278,7 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
 
                        if (item) {
                                ao2_link(docs, item);
+                               ao2_t_ref(item, -1, "Dispose of creation ref");
                                item = NULL;
                        }
                }
index ec990d5d10c212fe9fb01d18aeaa1303655d84cf..4b1634020216cee2fda0cdc7b29e74f02f8a6878 100644 (file)
@@ -1820,7 +1820,11 @@ static int load_moh_classes(int reload)
 static void ast_moh_destroy(void)
 {
        ast_verb(2, "Destroying musiconhold processes\n");
-       ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback");
+       if (mohclasses) {
+               ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback");
+               ao2_ref(mohclasses, -1);
+               mohclasses = NULL;
+       }
 }
 
 static char *handle_cli_moh_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
index 01e391aa1325c783f59ed4ac20fd63ed2894831f..bcaf02f7bac870c5ece7d05b881541f8f92301a8 100644 (file)
@@ -4350,6 +4350,7 @@ static int load_module(void)
        aco_option_register_custom(&cfg_info, "buddy", ACO_EXACT, client_options, NULL, client_buddy_handler, 0);
 
        if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
+               aco_info_destroy(&cfg_info);
                return AST_MODULE_LOAD_DECLINE;
        }