]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-11379: [freeswitch-core] Rare race condition in state machine #resolve
authorAnthony Minessale <anthm@freeswitch.org>
Wed, 5 Sep 2018 22:10:26 +0000 (17:10 -0500)
committerMike Jerris <mike@signalwire.com>
Wed, 5 Sep 2018 22:20:58 +0000 (18:20 -0400)
src/include/switch_types.h
src/switch_core_session.c
src/switch_core_state_machine.c

index 7ad71768f4f9074d0912da75e648f2298611daa7..93f50a97a3f1dc6e924a21a5bb7717932990b5f7 100644 (file)
@@ -1570,6 +1570,7 @@ typedef enum {
        CF_PROCESSING_STREAM_CHANGE,
        CF_STREAM_CHANGED,
        CF_ARRANGED_BRIDGE,
+       CF_STATE_REPEAT,
        /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
        /* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */
        CF_FLAG_MAX
index dec61f3917fd421830be9d998d6ea9ca42fdf14f..23307bf81af9b29af2e39a6ba86b17e2b886df0e 100644 (file)
@@ -1439,6 +1439,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_wake_session_thread(switch_c
        } else {
                if (switch_channel_state_thread_trylock(session->channel) == SWITCH_STATUS_SUCCESS) {
                        /* We've beat them for sure, as soon as we release this lock, they will be checking their queue on the next line. */
+                       switch_channel_set_flag(session->channel, CF_STATE_REPEAT);
                        switch_channel_state_thread_unlock(session->channel);
                } else {
                        /* What luck!  The channel has already started going to sleep *after* we checked if we need to wake it up.
index ca362844e03956f647e7ff50f3001295b003321e..500ea3c549c798cf4ac01a53d8d82dfe2df253d1 100644 (file)
@@ -690,29 +690,26 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
                                        switch_channel_hangup(session->channel, SWITCH_CAUSE_WRONG_CALL_STATE);
                                }
                        } else {
-                               switch_ivr_parse_all_events(session);
+                               switch_channel_state_thread_lock(session->channel);
+
                                switch_ivr_parse_all_events(session);
 
-                               if (switch_channel_get_state(session->channel) == switch_channel_get_running_state(session->channel)) {
-                                       switch_channel_state_thread_lock(session->channel);
+                               if (switch_channel_test_flag(session->channel, CF_STATE_REPEAT)) {
+                                       switch_channel_clear_flag(session->channel, CF_STATE_REPEAT);
+                               } else if (switch_channel_get_state(session->channel) == switch_channel_get_running_state(session->channel)) {
                                        switch_channel_set_flag(session->channel, CF_THREAD_SLEEPING);
-                                       if (switch_channel_get_state(session->channel) == switch_channel_get_running_state(session->channel)) {
-                                               switch_ivr_parse_all_events(session);
-                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s session thread sleep state: %s!\n",
-                                                                                 switch_channel_get_name(session->channel),
-                                                                                 switch_channel_state_name(switch_channel_get_running_state(session->channel)));
-                                               switch_thread_cond_wait(session->cond, session->mutex);
-                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s session thread wake state: %s!\n",
-                                                                                 switch_channel_get_name(session->channel),
-                                                                                 switch_channel_state_name(switch_channel_get_running_state(session->channel)));
-
-
-                                       }
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s session thread sleep state: %s!\n",
+                                                                         switch_channel_get_name(session->channel),
+                                                                         switch_channel_state_name(switch_channel_get_running_state(session->channel)));
+                                       switch_thread_cond_wait(session->cond, session->mutex);
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s session thread wake state: %s!\n",
+                                                                         switch_channel_get_name(session->channel),
+                                                                         switch_channel_state_name(switch_channel_get_running_state(session->channel)));                                       
                                        switch_channel_clear_flag(session->channel, CF_THREAD_SLEEPING);
-                                       switch_channel_state_thread_unlock(session->channel);
                                }
 
-                               switch_ivr_parse_all_events(session);
+                               switch_channel_state_thread_unlock(session->channel);
+
                                switch_ivr_parse_all_events(session);
                        }
                }