summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2012-10-02 01:47:16 +0000
committerMatthew Jordan <mjordan@digium.com>2012-10-02 01:47:16 +0000
commita094707d5156a005fb6e9277bd4a14f9d7e7ab1c (patch)
tree26a15c7ef864995e2f2d89d09294024bad0145cb /main
parent4e228fce0382550136e5c34cb4d9fd400b8d4ad3 (diff)
Fix a variety of ref counting issues
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 ........ Merged revisions 374196 from http://svn.asterisk.org/svn/asterisk/branches/11 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@374197 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r--main/asterisk.c3
-rw-r--r--main/astobj2.c34
-rw-r--r--main/ccss.c27
-rw-r--r--main/cel.c4
-rw-r--r--main/channel.c11
-rw-r--r--main/config_options.c2
-rw-r--r--main/data.c10
-rw-r--r--main/db.c6
-rw-r--r--main/event.c42
-rw-r--r--main/features.c21
-rw-r--r--main/format.c37
-rw-r--r--main/format_pref.c1
-rw-r--r--main/indications.c10
-rw-r--r--main/manager.c69
-rw-r--r--main/message.c31
-rw-r--r--main/named_acl.c1
-rw-r--r--main/pbx.c42
-rw-r--r--main/taskprocessor.c9
-rw-r--r--main/udptl.c9
-rw-r--r--main/xmldoc.c1
20 files changed, 349 insertions, 21 deletions
diff --git a/main/asterisk.c b/main/asterisk.c
index f586a3764..03c9962b3 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -1787,6 +1787,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) {
diff --git a/main/astobj2.c b/main/astobj2.c
index 9b5f8420e..eb4ab8e5e 100644
--- a/main/astobj2.c
+++ b/main/astobj2.c
@@ -544,7 +544,14 @@ int __ao2_ref(void *user_data, int delta)
return internal_ao2_ref(user_data, delta, __FILE__, __LINE__, __FUNCTION__);
}
-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);
@@ -1347,7 +1354,11 @@ static void *internal_ao2_traverse(struct ao2_container *self, enum search_flags
node->obj = NULL;
/* Unref the node from the container. */
- __ao2_ref(node, -1);
+ if (tag) {
+ __ao2_ref_debug(node, -1, tag, file, line, func);
+ } else {
+ __ao2_ref(node, -1);
+ }
}
}
@@ -1488,7 +1499,11 @@ void ao2_iterator_destroy(struct ao2_iterator *iter)
ao2_iterator_restart(iter);
/* Release the iterated container reference. */
+#if defined(REF_DEBUG)
+ __ao2_ref_debug(iter->c, -1, "ao2_iterator_destroy", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+#else
ao2_ref(iter->c, -1);
+#endif
iter->c = NULL;
/* Free the malloced iterator. */
@@ -2002,7 +2017,12 @@ static struct hash_bucket_node *hash_ao2_new_node(struct ao2_container_hash *sel
struct hash_bucket_node *node;
int i;
+#if defined(REF_DEBUG)
+ node = __ao2_alloc_debug(sizeof(*node), hash_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK,
+ "hash_ao2_new_node", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1);
+#else
node = __ao2_alloc(sizeof(*node), hash_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
+#endif
if (!node) {
return NULL;
}
@@ -3366,12 +3386,22 @@ static struct ast_cli_entry cli_astobj2[] = {
};
#endif /* defined(AO2_DEBUG) || defined(AST_DEVMODE) */
+#if defined(AST_DEVMODE)
+static void astobj2_cleanup(void)
+{
+ ao2_ref(reg_containers, -1);
+}
+#endif
int astobj2_init(void)
{
#if defined(AST_DEVMODE)
reg_containers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK,
AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, ao2_reg_sort_cb, NULL);
+ if (!reg_containers) {
+ return -1;
+ }
+ ast_register_atexit(astobj2_cleanup);
#endif /* defined(AST_DEVMODE) */
#if defined(AO2_DEBUG) || defined(AST_DEVMODE)
ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
diff --git a/main/ccss.c b/main/ccss.c
index 9553321c3..a45ed2844 100644
--- a/main/ccss.c
+++ b/main/ccss.c
@@ -4520,6 +4520,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;
@@ -4557,5 +4582,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;
}
diff --git a/main/cel.c b/main/cel.c
index 35f78cadf..3301e81e7 100644
--- a/main/cel.c
+++ b/main/cel.c
@@ -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)
diff --git a/main/channel.c b/main/channel.c
index 751cbdd52..b0761e185 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -8553,6 +8553,15 @@ 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_container_unregister("channels");
+ ao2_ref(channels, -1);
+ }
+}
+
void ast_channels_init(void)
{
channels = ao2_container_alloc(NUM_CHANNEL_BUCKETS,
@@ -8566,6 +8575,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 ---*/
diff --git a/main/config_options.c b/main/config_options.c
index c350ee5f6..5e76a7a7b 100644
--- a/main/config_options.c
+++ b/main/config_options.c
@@ -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;
}
diff --git a/main/data.c b/main/data.c
index c5a34543c..7a19b1f8f 100644
--- a/main/data.c
+++ b/main/data.c
@@ -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;
}
diff --git a/main/db.c b/main/db.c
index 05ae26cc9..2a19ce931 100644
--- 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;
diff --git a/main/event.c b/main/event.c
index 12d3abb7f..4c231fe91 100644
--- a/main/event.c
+++ b/main/event.c
@@ -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)
diff --git a/main/features.c b/main/features.c
index f89ca816d..e84a2a271 100644
--- a/main/features.c
+++ b/main/features.c
@@ -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;
}
diff --git a/main/format.c b/main/format.c
index 2d37eb458..139dfd331 100644
--- a/main/format.c
+++ b/main/format.c
@@ -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;
}
diff --git a/main/format_pref.c b/main/format_pref.c
index 9cb513c22..8b495ba56 100644
--- a/main/format_pref.c
+++ b/main/format_pref.c
@@ -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;
}
diff --git a/main/indications.c b/main/indications.c
index 4f0fc2948..f3356d603 100644
--- a/main/indications.c
+++ b/main/indications.c
@@ -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;
}
diff --git a/main/manager.c b/main/manager.c
index 4807dca82..1f25f379d 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -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;
}
diff --git a/main/message.c b/main/message.c
index c04413dc8..f764e2774 100644
--- a/main/message.c
+++ b/main/message.c
@@ -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;
}
diff --git a/main/named_acl.c b/main/named_acl.c
index 1638459fe..fce6aa88e 100644
--- a/main/named_acl.c
+++ b/main/named_acl.c
@@ -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;
}
diff --git a/main/pbx.c b/main/pbx.c
index 6c1fbcdbb..1e8f1a33b 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -11488,6 +11488,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;
@@ -11526,6 +11552,7 @@ int load_pbx(void)
return -1;
}
+ ast_register_atexit(unload_pbx);
return 0;
}
@@ -11886,11 +11913,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;
}
diff --git a/main/taskprocessor.c b/main/taskprocessor.c
index e92b6948b..912f891b1 100644
--- a/main/taskprocessor.c
+++ b/main/taskprocessor.c
@@ -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;
}
diff --git a/main/udptl.c b/main/udptl.c
index 3d110e21b..83dcd3d90 100644
--- a/main/udptl.c
+++ b/main/udptl.c
@@ -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);
}
diff --git a/main/xmldoc.c b/main/xmldoc.c
index 3c01d4300..0a8da5896 100644
--- a/main/xmldoc.c
+++ b/main/xmldoc.c
@@ -2279,6 +2279,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;
}
}