]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
fix race condition in state thread
authorAnthony Minessale <anthm@freeswitch.org>
Fri, 22 Feb 2013 23:46:54 +0000 (17:46 -0600)
committerAnthony Minessale <anthm@freeswitch.org>
Fri, 22 Feb 2013 23:46:54 +0000 (17:46 -0600)
src/include/switch_channel.h
src/switch_channel.c
src/switch_core_session.c
src/switch_core_state_machine.c
src/switch_ivr.c

index 4225a9bd88ebc26d367a367a8ce8194e34c90653..73eb7f102603c0d828a8857eaf68003a598bf2ec 100644 (file)
@@ -649,6 +649,7 @@ SWITCH_DECLARE(const char *) switch_channel_get_partner_uuid(switch_channel_t *c
 SWITCH_DECLARE(switch_hold_record_t *) switch_channel_get_hold_record(switch_channel_t *channel);
 SWITCH_DECLARE(void) switch_channel_state_thread_lock(switch_channel_t *channel);
 SWITCH_DECLARE(void) switch_channel_state_thread_unlock(switch_channel_t *channel);
+SWITCH_DECLARE(switch_status_t) switch_channel_state_thread_trylock(switch_channel_t *channel);
 
 SWITCH_END_EXTERN_C
 #endif
index 9ac36c589a5e60412eb680e844a002deab79c219..0cdf2eaa1347cfb434a62a258a56b2a92f7931e6 100644 (file)
@@ -2288,6 +2288,13 @@ SWITCH_DECLARE(void) switch_channel_state_thread_lock(switch_channel_t *channel)
        switch_mutex_lock(channel->thread_mutex);
 }
 
+
+SWITCH_DECLARE(switch_status_t) switch_channel_state_thread_trylock(switch_channel_t *channel)
+{
+       return switch_mutex_trylock(channel->thread_mutex);
+}
+
+
 SWITCH_DECLARE(void) switch_channel_state_thread_unlock(switch_channel_t *channel)
 {
        switch_mutex_unlock(channel->thread_mutex);
index b0073e670e3919dfbe1bf0a50a790f0c1b4f543d..3c0672276fef51e522d0272a18661e3d7749a4b2 100644 (file)
@@ -927,7 +927,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_dequeue_message(switch_core_
 
        switch_assert(session != NULL);
 
-       if (session->message_queue && switch_queue_size(session->message_queue)) {
+       if (session->message_queue) {
                if ((status = (switch_status_t) switch_queue_trypop(session->message_queue, &pop)) == SWITCH_STATUS_SUCCESS) {
                        *message = (switch_core_session_message_t *) pop;
                        if ((*message)->delivery_time && (*message)->delivery_time > switch_epoch_time_now(NULL)) {
@@ -968,7 +968,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_queue_signal_data(switch_cor
        switch_assert(session != NULL);
 
        if (session->signal_data_queue) {
-               if (switch_queue_trypush(session->signal_data_queue, signal_data) == SWITCH_STATUS_SUCCESS) {
+               if (switch_queue_push(session->signal_data_queue, signal_data) == SWITCH_STATUS_SUCCESS) {
                        status = SWITCH_STATUS_SUCCESS;
                }
 
@@ -988,7 +988,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_dequeue_signal_data(switch_c
 
        switch_assert(session != NULL);
 
-       if (session->signal_data_queue && switch_queue_size(session->signal_data_queue)) {
+       if (session->signal_data_queue) {
                if ((status = (switch_status_t) switch_queue_trypop(session->signal_data_queue, &pop)) == SWITCH_STATUS_SUCCESS) {
                        *signal_data = pop;
                }
@@ -1257,14 +1257,33 @@ SWITCH_DECLARE(switch_mutex_t *) switch_core_session_get_mutex(switch_core_sessi
 SWITCH_DECLARE(switch_status_t) switch_core_session_wake_session_thread(switch_core_session_t *session)
 {
        switch_status_t status;
+       int tries = 0;
 
-       /* If trylock fails the signal is already awake so we needn't bother */
+       /* If trylock fails the signal is already awake so we needn't bother ..... or do we????*/
 
-       status = switch_mutex_trylock(session->mutex);
+ top:
 
+       status = switch_mutex_trylock(session->mutex);
+       
        if (status == SWITCH_STATUS_SUCCESS) {
                switch_thread_cond_signal(session->cond);
                switch_mutex_unlock(session->mutex);
+       } 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_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.
+                          It will miss any messages in its queue because they were inserted after *it* checked its queue.  (catch-22)
+                          So, it's not asleep yet, but it's too late for us to be sure they know we want them to stay awake and check its queue again.
+                          Now *we* need to sleep instead but just for 1ms so we can circle back and try again.
+                          This is so rare (yet possible) to happen that we can be fairly certian it will not happen 2x in a row but we'll try 10x just in case.
+                        */
+                       if (++tries < 10) {
+                               switch_cond_next();
+                               goto top;
+                       }
+               }
        }
 
        return status;
index daa5bf37d4c8b16cfe012ed1661dffede36f981c..6cbf2d3f716b15de625c388647af26b1a0e7a0e0 100644 (file)
@@ -524,7 +524,16 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
                                        switch_channel_state_thread_lock(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_channel_clear_flag(session->channel, CF_THREAD_SLEEPING);
                                        switch_channel_state_thread_unlock(session->channel);
index f216c37ec8fe8c7d573c673e3c28cbfd2bfaaac0..c57ace9be49b3b6bd40324741c7ff4ee35e0449d 100644 (file)
@@ -851,10 +851,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_events(switch_core_session_
                x++;
        }
 
-       if (x) {
-               switch_ivr_sleep(session, 0, SWITCH_TRUE, NULL);
-       }
-
        return SWITCH_STATUS_SUCCESS;
 }