diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index bddfb0f2d2..cd8cbb47f0 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -643,6 +643,8 @@ SWITCH_DECLARE(switch_caller_extension_t *) switch_channel_get_queued_extension( SWITCH_DECLARE(void) switch_channel_transfer_to_extension(switch_channel_t *channel, switch_caller_extension_t *caller_extension); SWITCH_DECLARE(const char *) switch_channel_get_partner_uuid(switch_channel_t *channel); 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_END_EXTERN_C #endif diff --git a/src/include/switch_core.h b/src/include/switch_core.h index ead85fdf4a..210b676b1e 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -722,6 +722,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_thread_pool_launch(switch_co /*! \brief Signal a session's state machine thread that a state change has occured */ +SWITCH_DECLARE(switch_mutex_t *) switch_core_session_get_mutex(switch_core_session_t *session); SWITCH_DECLARE(switch_status_t) switch_core_session_wake_session_thread(_In_ switch_core_session_t *session); SWITCH_DECLARE(void) switch_core_session_signal_state_change(_In_ switch_core_session_t *session); diff --git a/src/switch_channel.c b/src/switch_channel.c index 9e40829f82..a057f9deb8 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -129,6 +129,7 @@ struct switch_channel { switch_mutex_t *dtmf_mutex; switch_mutex_t *flag_mutex; switch_mutex_t *state_mutex; + switch_mutex_t *thread_mutex; switch_mutex_t *profile_mutex; switch_core_session_t *session; switch_channel_state_t state; @@ -352,6 +353,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_alloc(switch_channel_t **channel, switch_mutex_init(&(*channel)->dtmf_mutex, SWITCH_MUTEX_NESTED, pool); switch_mutex_init(&(*channel)->flag_mutex, SWITCH_MUTEX_NESTED, pool); switch_mutex_init(&(*channel)->state_mutex, SWITCH_MUTEX_NESTED, pool); + switch_mutex_init(&(*channel)->thread_mutex, SWITCH_MUTEX_NESTED, pool); switch_mutex_init(&(*channel)->profile_mutex, SWITCH_MUTEX_NESTED, pool); (*channel)->hangup_cause = SWITCH_CAUSE_NONE; (*channel)->name = ""; @@ -1925,6 +1927,32 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_name_state(const char *nam return CS_DESTROY; } +static inline void careful_set(switch_channel_t *channel, switch_channel_state_t *state, switch_channel_state_t val) { + + if (switch_mutex_trylock(channel->thread_mutex)) { + *state = val; + switch_mutex_unlock(channel->thread_mutex); + } else { + switch_mutex_t *mutex = switch_core_session_get_mutex(channel->session); + int x = 0; + + for (x = 0; x < 100; x++) { + if (switch_mutex_trylock(mutex) == SWITCH_STATUS_SUCCESS) { + *state = val; + switch_mutex_unlock(mutex); + break; + } else { + switch_cond_next(); + } + } + + if (x == 100) { + *state = val; + } + + } +} + SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_running_state(switch_channel_t *channel, switch_channel_state_t state, const char *file, const char *func, int line) { @@ -1950,7 +1978,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_running_state( switch_mutex_lock(channel->state_mutex); - channel->running_state = state; + careful_set(channel, &channel->running_state, state); if (state <= CS_DESTROY) { switch_event_t *event; @@ -2218,7 +2246,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_channel_get_uuid(channel), SWITCH_LOG_DEBUG, "(%s) State Change %s -> %s\n", channel->name, state_names[last_state], state_names[state]); - channel->state = state; + careful_set(channel, &channel->state, state); if (state == CS_HANGUP && !channel->hangup_cause) { channel->hangup_cause = SWITCH_CAUSE_NORMAL_CLEARING; @@ -2240,6 +2268,16 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c return channel->state; } +SWITCH_DECLARE(void) switch_channel_state_thread_lock(switch_channel_t *channel) +{ + switch_mutex_lock(channel->thread_mutex); +} + +SWITCH_DECLARE(void) switch_channel_state_thread_unlock(switch_channel_t *channel) +{ + switch_mutex_unlock(channel->thread_mutex); +} + SWITCH_DECLARE(void) switch_channel_event_set_basic_data(switch_channel_t *channel, switch_event_t *event) { switch_caller_profile_t *caller_profile, *originator_caller_profile = NULL, *originatee_caller_profile = NULL; diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 449cd1c3c4..eb250b8dea 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -1245,6 +1245,11 @@ SWITCH_DECLARE(switch_channel_t *) switch_core_session_get_channel(switch_core_s return session->channel; } +SWITCH_DECLARE(switch_mutex_t *) switch_core_session_get_mutex(switch_core_session_t *session) +{ + return session->mutex; +} + SWITCH_DECLARE(switch_status_t) switch_core_session_wake_session_thread(switch_core_session_t *session) { switch_status_t status; diff --git a/src/switch_core_state_machine.c b/src/switch_core_state_machine.c index 87b8a32a20..daa5bf37d4 100644 --- a/src/switch_core_state_machine.c +++ b/src/switch_core_state_machine.c @@ -521,11 +521,13 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session) 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); switch_channel_set_flag(session->channel, CF_THREAD_SLEEPING); if (switch_channel_get_state(session->channel) == switch_channel_get_running_state(session->channel)) { switch_thread_cond_wait(session->cond, session->mutex); } switch_channel_clear_flag(session->channel, CF_THREAD_SLEEPING); + switch_channel_state_thread_unlock(session->channel); } switch_ivr_parse_all_events(session);