[Asterisk-code-review] stasis: Don't hold app_registry and session locks unnecessarily (asterisk[13])

Friendly Automation asteriskteam at digium.com
Thu Nov 14 21:56:27 CST 2019


Friendly Automation has submitted this change. ( https://gerrit.asterisk.org/c/asterisk/+/13171 )

Change subject: stasis: Don't hold app_registry and session locks unnecessarily
......................................................................

stasis: Don't hold app_registry and session locks unnecessarily

resource_events:app_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:app_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, 35 insertions(+), 24 deletions(-)

Approvals:
  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 20d9eaa..b5dc3cb 100644
--- a/res/ari/resource_events.c
+++ b/res/ari/resource_events.c
@@ -124,6 +124,7 @@
 	const char *msg_application = S_OR(
 		ast_json_string_get(ast_json_object_get(message, "application")),
 		"");
+	int app_debug_enabled;
 
 	if (!session) {
 		return;
@@ -142,9 +143,12 @@
 		return;
 	}
 
+	/* Don't lock the app_registry container with session locked */
+	app_debug_enabled = stasis_app_get_debug_by_name(app_name);
+
 	ao2_lock(session);
 	if (session->ws_session && 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",
diff --git a/res/res_stasis.c b/res/res_stasis.c
index 114a43f..a8cc14c 100644
--- a/res/res_stasis.c
+++ b/res/res_stasis.c
@@ -1677,7 +1677,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;
@@ -1686,36 +1686,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/+/13171
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Change-Id: I58c69d08cb372852a63933608e4d6c3e456247b4
Gerrit-Change-Number: 13171
Gerrit-PatchSet: 2
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/2e015925/attachment.html>


More information about the asterisk-code-review mailing list