[Asterisk-code-review] stasis: Don't hold app_registry and session locks unnecessarily (asterisk[17])
Friendly Automation
asteriskteam at digium.com
Thu Nov 14 11:20:46 CST 2019
Friendly Automation has submitted this change. ( https://gerrit.asterisk.org/c/asterisk/+/13189 )
Change subject: stasis: Don't hold app_registry and session locks unnecessarily
......................................................................
stasis: Don't hold app_registry and session locks unnecessarily
resource_events:stasis_app_message_handler() was locking the session,
then attempting to determine if the app had debug enabled which
locked the app_registry container. res_stasis:__stasis_app_register
was locking the app_registry container then calling app_update
which caused app_handler (which locks the session) to run.
The result was a deadlock.
* Updated resource_events:stasis_app_message_handler() to determine
if debug was set (which locks the app_registry) before obtaining the
session lock.
* Updated res_stasis:__stasis_app_register to release the app_registry
container lock before calling app_update (which locks the sesison).
ASTERISK-28423
Reported by Ross Beer
Change-Id: I58c69d08cb372852a63933608e4d6c3e456247b4
---
M res/ari/resource_events.c
M res/res_stasis.c
2 files changed, 38 insertions(+), 25 deletions(-)
Approvals:
Joshua Colp: Looks good to me, but someone else must approve
Benjamin Keith Ford: Looks good to me, but someone else must approve
George Joseph: Looks good to me, approved
Friendly Automation: Approved for Submit
diff --git a/res/ari/resource_events.c b/res/ari/resource_events.c
index d935da1..f70de43 100644
--- a/res/ari/resource_events.c
+++ b/res/ari/resource_events.c
@@ -81,9 +81,16 @@
{
struct event_session *session = data;
const char *msg_type, *msg_application;
+ int app_debug_enabled;
ast_assert(session != NULL);
+ /*
+ * We need to get the debug flag before lockinf session
+ * to help prevent a deadlock with the apps_registry container.
+ */
+ app_debug_enabled = stasis_app_get_debug_by_name(app_name);
+
ao2_lock(session);
msg_type = S_OR(ast_json_string_get(ast_json_object_get(message, "type")), "");
@@ -115,7 +122,7 @@
msg_type,
msg_application);
} else if (stasis_app_event_allowed(app_name, message)) {
- if (stasis_app_get_debug_by_name(app_name)) {
+ if (app_debug_enabled) {
char *str = ast_json_dump_string_format(message, ast_ari_json_format());
ast_verbose("<--- Sending ARI event to %s --->\n%s\n",
@@ -310,7 +317,6 @@
{
#ifdef AST_DEVMODE /* Avoid unused variable warning */
struct event_session *session = obj;
-
#endif
/* event_session_shutdown should have been called before now */
diff --git a/res/res_stasis.c b/res/res_stasis.c
index e635dc5..fe89da5 100644
--- a/res/res_stasis.c
+++ b/res/res_stasis.c
@@ -1704,7 +1704,7 @@
static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
{
- struct stasis_app *app;
+ RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
if (!apps_registry) {
return -1;
@@ -1713,36 +1713,43 @@
ao2_lock(apps_registry);
app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
if (app) {
+ /*
+ * We need to unlock the apps_registry before calling app_update to
+ * prevent the possibility of a deadlock with the session. We'll still
+ * run the lazy cleanup first though.
+ */
+ cleanup();
+ ao2_unlock(apps_registry);
app_update(app, handler, data);
- } else {
- app = app_create(app_name, handler, data, all_events ? STASIS_APP_SUBSCRIBE_ALL : STASIS_APP_SUBSCRIBE_MANUAL);
- if (!app) {
- ao2_unlock(apps_registry);
- return -1;
- }
-
- if (all_events) {
- struct stasis_app_event_source *source;
-
- AST_RWLIST_RDLOCK(&event_sources);
- AST_LIST_TRAVERSE(&event_sources, source, next) {
- if (!source->subscribe) {
- continue;
- }
-
- source->subscribe(app, NULL);
- }
- AST_RWLIST_UNLOCK(&event_sources);
- }
- ao2_link_flags(apps_registry, app, OBJ_NOLOCK);
+ return 0;
}
+ app = app_create(app_name, handler, data, all_events ? STASIS_APP_SUBSCRIBE_ALL : STASIS_APP_SUBSCRIBE_MANUAL);
+ if (!app) {
+ ao2_unlock(apps_registry);
+ return -1;
+ }
+
+ if (all_events) {
+ struct stasis_app_event_source *source;
+
+ AST_RWLIST_RDLOCK(&event_sources);
+ AST_LIST_TRAVERSE(&event_sources, source, next) {
+ if (!source->subscribe) {
+ continue;
+ }
+
+ source->subscribe(app, NULL);
+ }
+ AST_RWLIST_UNLOCK(&event_sources);
+ }
+ ao2_link_flags(apps_registry, app, OBJ_NOLOCK);
+
/* We lazily clean up the apps_registry, because it's good enough to
* prevent memory leaks, and we're lazy.
*/
cleanup();
ao2_unlock(apps_registry);
- ao2_ref(app, -1);
return 0;
}
--
To view, visit https://gerrit.asterisk.org/c/asterisk/+/13189
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: 17
Gerrit-Change-Id: I58c69d08cb372852a63933608e4d6c3e456247b4
Gerrit-Change-Number: 13189
Gerrit-PatchSet: 1
Gerrit-Owner: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Benjamin Keith Ford <bford at digium.com>
Gerrit-Reviewer: Friendly Automation
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20191114/14f58b1d/attachment-0001.html>
More information about the asterisk-code-review
mailing list