mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-13 00:04:53 +00:00
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
This commit is contained in:
@@ -81,9 +81,16 @@ static void stasis_app_message_handler(
|
|||||||
{
|
{
|
||||||
struct event_session *session = data;
|
struct event_session *session = data;
|
||||||
const char *msg_type, *msg_application;
|
const char *msg_type, *msg_application;
|
||||||
|
int app_debug_enabled;
|
||||||
|
|
||||||
ast_assert(session != NULL);
|
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);
|
ao2_lock(session);
|
||||||
|
|
||||||
msg_type = S_OR(ast_json_string_get(ast_json_object_get(message, "type")), "");
|
msg_type = S_OR(ast_json_string_get(ast_json_object_get(message, "type")), "");
|
||||||
@@ -115,7 +122,7 @@ static void stasis_app_message_handler(
|
|||||||
msg_type,
|
msg_type,
|
||||||
msg_application);
|
msg_application);
|
||||||
} else if (stasis_app_event_allowed(app_name, message)) {
|
} 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());
|
char *str = ast_json_dump_string_format(message, ast_ari_json_format());
|
||||||
|
|
||||||
ast_verbose("<--- Sending ARI event to %s --->\n%s\n",
|
ast_verbose("<--- Sending ARI event to %s --->\n%s\n",
|
||||||
@@ -310,7 +317,6 @@ static void event_session_dtor(void *obj)
|
|||||||
{
|
{
|
||||||
#ifdef AST_DEVMODE /* Avoid unused variable warning */
|
#ifdef AST_DEVMODE /* Avoid unused variable warning */
|
||||||
struct event_session *session = obj;
|
struct event_session *session = obj;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* event_session_shutdown should have been called before now */
|
/* event_session_shutdown should have been called before now */
|
||||||
|
@@ -1704,7 +1704,7 @@ struct ao2_container *stasis_app_get_all(void)
|
|||||||
|
|
||||||
static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events)
|
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) {
|
if (!apps_registry) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1713,36 +1713,43 @@ static int __stasis_app_register(const char *app_name, stasis_app_cb handler, vo
|
|||||||
ao2_lock(apps_registry);
|
ao2_lock(apps_registry);
|
||||||
app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
|
app = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
|
||||||
if (app) {
|
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);
|
app_update(app, handler, data);
|
||||||
} else {
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
/* We lazily clean up the apps_registry, because it's good enough to
|
||||||
* prevent memory leaks, and we're lazy.
|
* prevent memory leaks, and we're lazy.
|
||||||
*/
|
*/
|
||||||
cleanup();
|
cleanup();
|
||||||
ao2_unlock(apps_registry);
|
ao2_unlock(apps_registry);
|
||||||
ao2_ref(app, -1);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user