[Asterisk-code-review] stasis: Fix crash at shutdown. (...asterisk[13])
Benjamin Keith Ford
asteriskteam at digium.com
Tue Apr 23 11:08:48 CDT 2019
Benjamin Keith Ford has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/11304
Change subject: stasis: Fix crash at shutdown.
......................................................................
stasis: Fix crash at shutdown.
When compiling in dev mode, stasis statistics are enabled and can cause
a crash at shutdown due to the following:
- Containers are freed
- Topics and subscriptions remain
- When those topics and subscriptions are deallocated, they go to do
things with the container
This changes the containers to global ao2 objects, and whenever needed
in the code, a reference must be obtained and checked before any
operations can be done.
ASTERISK-28353 #close
Change-Id: Ie7d5e907fcfcb4d65bd36d5e4eb923126fde8d33
---
M main/stasis.c
1 file changed, 92 insertions(+), 22 deletions(-)
git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/04/11304/1
diff --git a/main/stasis.c b/main/stasis.c
index 3fee6ba..13cdb71 100644
--- a/main/stasis.c
+++ b/main/stasis.c
@@ -317,11 +317,11 @@
/*! The number of buckets to use for subscription statistics */
#define SUBSCRIPTION_STATISTICS_BUCKETS 57
-/*! Container which stores statistics for topics */
-static struct ao2_container *topic_statistics;
+/*! Global container which stores statistics for topics */
+static AO2_GLOBAL_OBJ_STATIC(topic_statistics);
-/*! Container which stores statistics for subscriptions */
-static struct ao2_container *subscription_statistics;
+/*! Global container which stores statistics for subscriptions */
+static AO2_GLOBAL_OBJ_STATIC(subscription_statistics);
/*! \internal */
struct stasis_message_type_statistics {
@@ -395,6 +395,9 @@
static void topic_dtor(void *obj)
{
struct stasis_topic *topic = obj;
+#ifdef AST_DEVMODE
+ struct ao2_container *topic_stats;
+#endif
/* Subscribers hold a reference to topics, so they should all be
* unsubscribed before we get here. */
@@ -405,10 +408,12 @@
ast_debug(1, "Topic '%s': %p destroyed\n", topic->name, topic);
#ifdef AST_DEVMODE
- if (topic->statistics) {
- ao2_unlink(topic_statistics, topic->statistics);
+ topic_stats = ao2_global_obj_ref(topic_statistics);
+ if (topic->statistics && topic_stats) {
+ ao2_unlink(topic_stats, topic->statistics);
ao2_ref(topic->statistics, -1);
}
+ ao2_cleanup(topic_stats);
#endif
}
@@ -423,6 +428,11 @@
static struct stasis_topic_statistics *stasis_topic_statistics_create(struct stasis_topic *topic)
{
struct stasis_topic_statistics *statistics;
+ RAII_VAR(struct ao2_container *, topic_stats, ao2_global_obj_ref(topic_statistics), ao2_cleanup);
+
+ if (!topic_stats) {
+ return NULL;
+ }
statistics = ao2_alloc(sizeof(*statistics) + strlen(topic->name) + 1, topic_statistics_destroy);
if (!statistics) {
@@ -438,7 +448,7 @@
/* This is strictly used for the pointer address when showing the topic */
statistics->topic = topic;
strcpy(statistics->name, topic->name); /* SAFE */
- ao2_link(topic_statistics, statistics);
+ ao2_link(topic_stats, statistics);
return statistics;
}
@@ -552,6 +562,9 @@
static void subscription_dtor(void *obj)
{
struct stasis_subscription *sub = obj;
+#ifdef AST_DEVMODE
+ struct ao2_container *subscription_stats;
+#endif
/* Subscriptions need to be manually unsubscribed before destruction
* b/c there's a cyclic reference between topics and subscriptions */
@@ -570,10 +583,12 @@
AST_VECTOR_FREE(&sub->accepted_message_types);
#ifdef AST_DEVMODE
- if (sub->statistics) {
- ao2_unlink(subscription_statistics, sub->statistics);
+ subscription_stats = ao2_global_obj_ref(subscription_statistics);
+ if (sub->statistics && subscription_stats) {
+ ao2_unlink(subscription_stats, sub->statistics);
ao2_ref(sub->statistics, -1);
}
+ ao2_cleanup(subscription_stats);
#endif
}
@@ -655,6 +670,11 @@
const char *func)
{
struct stasis_subscription_statistics *statistics;
+ RAII_VAR(struct ao2_container *, subscription_stats, ao2_global_obj_ref(subscription_statistics), ao2_cleanup);
+
+ if (!subscription_stats) {
+ return NULL;
+ }
statistics = ao2_alloc(sizeof(*statistics) + strlen(sub->uniqueid) + 1, subscription_statistics_destroy);
if (!statistics) {
@@ -674,7 +694,7 @@
statistics->uses_threadpool = use_thread_pool;
strcpy(statistics->uniqueid, sub->uniqueid); /* SAFE */
statistics->sub = sub;
- ao2_link(subscription_statistics, statistics);
+ ao2_link(subscription_stats, statistics);
return statistics;
}
@@ -2152,6 +2172,7 @@
int count = 0;
int dropped = 0;
int passed = 0;
+ RAII_VAR(struct ao2_container *, subscription_stats, ao2_global_obj_ref(subscription_statistics), ao2_cleanup);
#define FMT_HEADERS "%-64s %10s %10s %16s %16s\n"
#define FMT_FIELDS "%-64s %10d %10d %16ld %16ld\n"
#define FMT_FIELDS2 "%-64s %10d %10d\n"
@@ -2178,7 +2199,13 @@
return CLI_SUCCESS;
}
- if (ao2_container_dup(sorted_subscriptions, subscription_statistics, 0)) {
+ if (!subscription_stats) {
+ ao2_ref(sorted_subscriptions, -1);
+ ast_cli(a->fd, "Could not fetch subscription_statistics container\n");
+ return CLI_FAILURE;
+ }
+
+ if (ao2_container_dup(sorted_subscriptions, subscription_stats, 0)) {
ao2_ref(sorted_subscriptions, -1);
ast_cli(a->fd, "Could not sort subscription statistics\n");
return CLI_SUCCESS;
@@ -2216,12 +2243,18 @@
static char *subscription_statistics_complete_name(const char *word, int state)
{
struct stasis_subscription_statistics *statistics;
+ struct ao2_container *subscription_stats;
struct ao2_iterator it_statistics;
int wordlen = strlen(word);
int which = 0;
char *result = NULL;
- it_statistics = ao2_iterator_init(subscription_statistics, 0);
+ subscription_stats = ao2_global_obj_ref(subscription_statistics);
+ if (!subscription_stats) {
+ return result;
+ }
+
+ it_statistics = ao2_iterator_init(subscription_stats, 0);
while ((statistics = ao2_iterator_next(&it_statistics))) {
if (!strncasecmp(word, statistics->uniqueid, wordlen)
&& ++which > state) {
@@ -2233,6 +2266,7 @@
}
}
ao2_iterator_destroy(&it_statistics);
+ ao2_ref(subscription_stats, -1);
return result;
}
@@ -2245,6 +2279,7 @@
struct stasis_subscription_statistics *statistics;
struct ao2_iterator i;
char *name;
+ RAII_VAR(struct ao2_container *, subscription_stats, ao2_global_obj_ref(subscription_statistics), ao2_cleanup);
switch (cmd) {
case CLI_INIT:
@@ -2265,7 +2300,12 @@
return CLI_SHOWUSAGE;
}
- statistics = ao2_find(subscription_statistics, a->argv[4], OBJ_SEARCH_KEY);
+ if (!subscription_stats) {
+ ast_cli(a->fd, "Could not fetch subcription_statistics container\n");
+ return CLI_FAILURE;
+ }
+
+ statistics = ao2_find(subscription_stats, a->argv[4], OBJ_SEARCH_KEY);
if (!statistics) {
ast_cli(a->fd, "Specified subscription '%s' does not exist\n", a->argv[4]);
return CLI_FAILURE;
@@ -2318,6 +2358,7 @@
int count = 0;
int not_dispatched = 0;
int dispatched = 0;
+ RAII_VAR(struct ao2_container *, topic_stats, ao2_global_obj_ref(topic_statistics), ao2_cleanup);
#define FMT_HEADERS "%-64s %10s %10s %10s %16s %16s\n"
#define FMT_FIELDS "%-64s %10d %10d %10d %16ld %16ld\n"
#define FMT_FIELDS2 "%-64s %10s %10d %10d\n"
@@ -2344,7 +2385,13 @@
return CLI_SUCCESS;
}
- if (ao2_container_dup(sorted_topics, topic_statistics, 0)) {
+ if (!topic_stats) {
+ ao2_ref(sorted_topics, -1);
+ ast_cli(a->fd, "Could not fetch topic_statistics container\n");
+ return CLI_FAILURE;
+ }
+
+ if (ao2_container_dup(sorted_topics, topic_stats, 0)) {
ao2_ref(sorted_topics, -1);
ast_cli(a->fd, "Could not sort topic statistics\n");
return CLI_SUCCESS;
@@ -2383,12 +2430,18 @@
static char *topic_statistics_complete_name(const char *word, int state)
{
struct stasis_topic_statistics *statistics;
+ struct ao2_container *topic_stats;
struct ao2_iterator it_statistics;
int wordlen = strlen(word);
int which = 0;
char *result = NULL;
- it_statistics = ao2_iterator_init(topic_statistics, 0);
+ topic_stats = ao2_global_obj_ref(topic_statistics);
+ if (!topic_stats) {
+ return result;
+ }
+
+ it_statistics = ao2_iterator_init(topic_stats, 0);
while ((statistics = ao2_iterator_next(&it_statistics))) {
if (!strncasecmp(word, statistics->name, wordlen)
&& ++which > state) {
@@ -2400,6 +2453,7 @@
}
}
ao2_iterator_destroy(&it_statistics);
+ ao2_ref(topic_stats, -1);
return result;
}
@@ -2412,6 +2466,7 @@
struct stasis_topic_statistics *statistics;
struct ao2_iterator i;
char *uniqueid;
+ RAII_VAR(struct ao2_container *, topic_stats, ao2_global_obj_ref(topic_statistics), ao2_cleanup);
switch (cmd) {
case CLI_INIT:
@@ -2432,7 +2487,11 @@
return CLI_SHOWUSAGE;
}
- statistics = ao2_find(topic_statistics, a->argv[4], OBJ_SEARCH_KEY);
+ if (!topic_stats) {
+ ast_cli(a->fd, "Could not fetch topic_statistics container\n");
+ return CLI_FAILURE;
+ }
+ statistics = ao2_find(topic_stats, a->argv[4], OBJ_SEARCH_KEY);
if (!statistics) {
ast_cli(a->fd, "Specified topic '%s' does not exist\n", a->argv[4]);
return CLI_FAILURE;
@@ -2645,8 +2704,8 @@
#ifdef AST_DEVMODE
ast_cli_unregister_multiple(cli_stasis_statistics, ARRAY_LEN(cli_stasis_statistics));
AST_VECTOR_FREE(&message_type_statistics);
- ao2_cleanup(subscription_statistics);
- ao2_cleanup(topic_statistics);
+ ao2_global_obj_release(subscription_statistics);
+ ao2_global_obj_release(topic_statistics);
#endif
ast_threadpool_shutdown(pool);
pool = NULL;
@@ -2661,6 +2720,10 @@
struct stasis_config *cfg;
int cache_init;
struct ast_threadpool_options threadpool_opts = { 0, };
+#ifdef AST_DEVMODE
+ struct ao2_container *subscription_stats;
+ struct ao2_container *topic_stats;
+#endif
/* Be sure the types are cleaned up after the message bus */
ast_register_cleanup(stasis_cleanup);
@@ -2746,15 +2809,22 @@
/* Statistics information is stored separately so that we don't alter or interrupt the lifetime of the underlying
* topic or subscripton.
*/
- subscription_statistics = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, SUBSCRIPTION_STATISTICS_BUCKETS,
+ subscription_stats = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, SUBSCRIPTION_STATISTICS_BUCKETS,
subscription_statistics_hash, 0, subscription_statistics_cmp);
- if (!subscription_statistics) {
+ if (!subscription_stats) {
return -1;
}
+ ao2_global_obj_replace_unref(subscription_statistics, subscription_stats);
+ ao2_cleanup(subscription_stats);
- topic_statistics = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, TOPIC_STATISTICS_BUCKETS,
+ topic_stats = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, TOPIC_STATISTICS_BUCKETS,
topic_statistics_hash, 0, topic_statistics_cmp);
- if (!topic_statistics) {
+ if (!topic_stats) {
+ return -1;
+ }
+ ao2_global_obj_replace_unref(topic_statistics, topic_stats);
+ ao2_cleanup(topic_stats);
+ if (!topic_stats) {
return -1;
}
--
To view, visit https://gerrit.asterisk.org/c/asterisk/+/11304
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Change-Id: Ie7d5e907fcfcb4d65bd36d5e4eb923126fde8d33
Gerrit-Change-Number: 11304
Gerrit-PatchSet: 1
Gerrit-Owner: Benjamin Keith Ford <bford at digium.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20190423/6facf20e/attachment-0001.html>
More information about the asterisk-code-review
mailing list