]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
fix strange race moc experienced in uuid_bridge
authorAnthony Minessale <anthm@freeswitch.org>
Wed, 7 Dec 2011 21:13:59 +0000 (15:13 -0600)
committerAnthony Minessale <anthm@freeswitch.org>
Wed, 7 Dec 2011 21:14:08 +0000 (15:14 -0600)
src/include/switch_channel.h
src/switch_channel.c
src/switch_ivr_bridge.c

index 6facdf26f2466d5a61c89346a83608bd35919d54..94eb9e571d05680cd6bdf5254b6661f96950aae8 100644 (file)
@@ -389,6 +389,7 @@ SWITCH_DECLARE(uint32_t) switch_channel_test_flag_partner(switch_channel_t *chan
   \param flag flag to set
 */
 SWITCH_DECLARE(void) switch_channel_set_state_flag(switch_channel_t *channel, switch_channel_flag_t flag);
+SWITCH_DECLARE(void) switch_channel_clear_state_flag(switch_channel_t *channel, switch_channel_flag_t flag);
 
 /*!
   \brief Clear given flag(s) from a channel
index b12666dee9cbe6c66965b68b3f3513d888b38618..3a7ce9302380ae4d348425fecad7ec6fd026c8a4 100644 (file)
@@ -1674,6 +1674,15 @@ SWITCH_DECLARE(void) switch_channel_set_state_flag(switch_channel_t *channel, sw
        switch_mutex_unlock(channel->flag_mutex);
 }
 
+SWITCH_DECLARE(void) switch_channel_clear_state_flag(switch_channel_t *channel, switch_channel_flag_t flag)
+{
+       switch_assert(channel != NULL);
+
+       switch_mutex_lock(channel->flag_mutex);
+       channel->state_flags[flag] = 0;
+       switch_mutex_unlock(channel->flag_mutex);
+}
+
 SWITCH_DECLARE(void) switch_channel_clear_flag(switch_channel_t *channel, switch_channel_flag_t flag)
 {
        int ACTIVE = 0;
index 3c85c4b421e0104082beea4b7d12d85a7e2fc3ce..a8feb938daf9ae9f18acd612e97d4391c6090520 100644 (file)
@@ -763,21 +763,48 @@ static switch_status_t uuid_bridge_on_soft_execute(switch_core_session_t *sessio
                return SWITCH_STATUS_SUCCESS;
        }
 
-       switch_channel_clear_flag_recursive(channel, CF_BRIDGE_ORIGINATOR);
-
        if ((other_uuid = switch_channel_get_variable(channel, SWITCH_UUID_BRIDGE)) && (other_session = switch_core_session_locate(other_uuid))) {
                switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
                switch_event_t *event;
                int ready_a, ready_b;
-               switch_channel_state_t state;
+               switch_channel_state_t state, running_state;
+               int max = 1000, loops = max;
 
                switch_channel_set_variable(channel, SWITCH_UUID_BRIDGE, NULL);
+               
+               for (;;) {
+                       state = switch_channel_get_state(other_channel);
+                       running_state = switch_channel_get_running_state(other_channel);
+
+                       if (state == running_state) {
+                               
+                               if (--loops < 1) {
+                                       switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                                       switch_channel_hangup(other_channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                               }
+
+                               if (switch_channel_down_nosig(other_channel) || switch_channel_down_nosig(channel)) {
+                                       break;
+                               }
+
+                               if (running_state == CS_RESET) {
+                                       switch_channel_set_state(other_channel, CS_SOFT_EXECUTE);
+                               }
 
-               switch_channel_wait_for_state(other_channel, channel, CS_RESET);
+                               if (running_state == CS_SOFT_EXECUTE) {
 
-               if (switch_channel_get_state(other_channel) == CS_RESET) {
-                       switch_channel_set_state(other_channel, CS_SOFT_EXECUTE);
-                       switch_channel_wait_for_state(other_channel, channel, CS_SOFT_EXECUTE);
+                                       if (switch_channel_test_flag(other_channel, CF_BRIDGE_ORIGINATOR)) {
+                                               goto done;
+                                       } else {
+                                               break;
+                                       }
+                               }
+
+                       } else {
+                               loops = max;
+                       }
+
+                       switch_yield(20000);
                }
 
                switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
@@ -789,7 +816,7 @@ static switch_status_t uuid_bridge_on_soft_execute(switch_core_session_t *sessio
                        } else {
                                switch_channel_hangup(channel, SWITCH_CAUSE_ORIGINATOR_CANCEL);
                        }
-                       return SWITCH_STATUS_FALSE;
+                       goto done;
                }
 
                ready_a = switch_channel_ready(channel);
@@ -809,7 +836,7 @@ static switch_status_t uuid_bridge_on_soft_execute(switch_core_session_t *sessio
                                }
                        }
                        switch_core_session_rwunlock(other_session);
-                       return SWITCH_STATUS_FALSE;
+                       goto done;
                }
 
                /* fire events that will change the data table from "show channels" */
@@ -839,7 +866,9 @@ static switch_status_t uuid_bridge_on_soft_execute(switch_core_session_t *sessio
                switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
        }
 
+ done:
 
+       switch_channel_clear_flag_recursive(channel, CF_BRIDGE_ORIGINATOR);
 
        return SWITCH_STATUS_FALSE;
 }
@@ -1563,8 +1592,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(const char *originator_uu
                        //switch_channel_set_variable(originatee_channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, NULL);
                        switch_channel_clear_state_handler(originator_channel, NULL);
                        switch_channel_clear_state_handler(originatee_channel, NULL);
-                       switch_channel_set_state_flag(originator_channel, CF_BRIDGE_ORIGINATOR);
+                       switch_channel_clear_flag_recursive(originator_channel, CF_BRIDGE_ORIGINATOR);
                        switch_channel_clear_flag_recursive(originatee_channel, CF_BRIDGE_ORIGINATOR);
+                       switch_channel_set_state_flag(originator_channel, CF_BRIDGE_ORIGINATOR);
+                       switch_channel_clear_state_flag(originatee_channel, CF_BRIDGE_ORIGINATOR);
                        switch_channel_add_state_handler(originator_channel, &uuid_bridge_state_handlers);
                        switch_channel_add_state_handler(originatee_channel, &uuid_bridge_state_handlers);