From: Matthew Jordan Date: Tue, 2 Oct 2012 00:31:14 +0000 (+0000) Subject: Fix a variety of ref counting issues X-Git-Tag: 1.8.18.0-rc1~16 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c61f7e7995cb69d6572df72b3a463a58aa0f044f;p=thirdparty%2Fasterisk.git 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 git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@374177 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/main/ccss.c b/main/ccss.c index 0ec08b1644..69bcd154fa 100644 --- a/main/ccss.c +++ b/main/ccss.c @@ -4310,6 +4310,30 @@ 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_thread) { + cc_sched_thread = ast_sched_thread_destroy(cc_sched_thread); + } + 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; @@ -4338,5 +4362,6 @@ int ast_cc_init(void) cc_logger_level = ast_logger_register_level(CC_LOGGER_LEVEL_NAME); dialed_cc_interface_counter = 1; initialize_cc_max_requests(); + ast_register_atexit(cc_shutdown); return res; } diff --git a/main/cel.c b/main/cel.c index a5d82a606f..117c5de4a3 100644 --- a/main/cel.c +++ b/main/cel.c @@ -711,6 +711,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 e69cde0c26..661b601211 100644 --- a/main/channel.c +++ b/main/channel.c @@ -8062,6 +8062,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_ref(channels, -1); + channels = NULL; + } +} + void ast_channels_init(void) { channels = ao2_container_alloc(NUM_CHANNEL_BUCKETS, @@ -8072,6 +8081,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/data.c b/main/data.c index 9f7ef9a9da..37829798f8 100644 --- a/main/data.c +++ b/main/data.c @@ -3282,6 +3282,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; @@ -3301,5 +3309,7 @@ int ast_data_init(void) AST_TEST_REGISTER(test_data_get); #endif + ast_register_atexit(data_shutdown); + return res; } diff --git a/main/event.c b/main/event.c index 4e1c28cecd..c9acb70229 100644 --- a/main/event.c +++ b/main/event.c @@ -1777,6 +1777,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; @@ -1793,17 +1825,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 7cb66bff7e..2b2ccb57e5 100644 --- a/main/features.c +++ b/main/features.c @@ -6644,7 +6644,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); @@ -8221,6 +8220,22 @@ exit_features_test: } #endif /* defined(TEST_FRAMEWORK) */ +/*! \internal \brief Clean up resources on Asterisk shutdown */ +static void features_shutdown(void) +{ + ast_devstate_prov_del("Park"); + 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; @@ -8253,5 +8268,7 @@ 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/indications.c b/main/indications.c index 94e25aaa06..98de5a7297 100644 --- a/main/indications.c +++ b/main/indications.c @@ -1149,6 +1149,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) { @@ -1163,6 +1172,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 ed0bacd617..0285407d3d 100644 --- a/main/manager.c +++ b/main/manager.c @@ -6584,6 +6584,61 @@ 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("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"); + } + + 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) { struct ast_config *ucfg = NULL, *cfg = NULL; @@ -6641,6 +6696,9 @@ static int __init_manager(int reload) /* Append placeholder event so master_eventq never runs dry */ append_event("Event: Placeholder\r\n\r\n", 0); } + + ast_register_atexit(manager_shutdown); + if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) { return 0; } @@ -7017,6 +7075,7 @@ static int __init_manager(int reload) } else if (ast_ssl_setup(amis_desc.tls_cfg)) { ast_tcptls_server_start(&amis_desc); } + return 0; } diff --git a/main/pbx.c b/main/pbx.c index 9636b7be8a..68afbe0044 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -10301,6 +10301,26 @@ 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 (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); +} + int load_pbx(void) { int x; @@ -10334,6 +10354,7 @@ int load_pbx(void) return -1; } + ast_register_atexit(unload_pbx); return 0; } diff --git a/main/taskprocessor.c b/main/taskprocessor.c index dd2a1c68c6..3a79f21dec 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/res/res_musiconhold.c b/res/res_musiconhold.c index 69b3c3396b..e9dcaf19a5 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -1776,7 +1776,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)