fix race condition when hangup happends after answer indication but before the session thread is started
This commit is contained in:
parent
652d2fdfb3
commit
9096501ee4
|
@ -92,7 +92,9 @@ typedef enum {
|
|||
SSF_NONE = 0,
|
||||
SSF_DESTROYED = (1 << 0),
|
||||
SSF_WARN_TRANSCODE = (1 << 1),
|
||||
SSF_HANGUP = (1 << 2)
|
||||
SSF_HANGUP = (1 << 2),
|
||||
SSF_THREAD_STARTED = (1 << 3),
|
||||
SSF_THREAD_RUNNING = (1 << 4)
|
||||
} switch_session_flag_t;
|
||||
|
||||
|
||||
|
@ -103,7 +105,6 @@ struct switch_core_session {
|
|||
switch_endpoint_interface_t *endpoint_interface;
|
||||
switch_size_t id;
|
||||
switch_session_flag_t flags;
|
||||
int thread_running;
|
||||
switch_channel_t *channel;
|
||||
|
||||
switch_io_event_hooks_t event_hooks;
|
||||
|
|
|
@ -479,6 +479,7 @@ SWITCH_DECLARE(void) switch_core_session_run(_In_ switch_core_session_t *session
|
|||
\param session the session on which to check
|
||||
*/
|
||||
SWITCH_DECLARE(unsigned int) switch_core_session_running(_In_ switch_core_session_t *session);
|
||||
SWITCH_DECLARE(unsigned int) switch_core_session_started(_In_ switch_core_session_t *session);
|
||||
|
||||
SWITCH_DECLARE(void *) switch_core_perform_permanent_alloc(_In_ switch_size_t memory, _In_z_ const char *file, _In_z_ const char *func, _In_ int line);
|
||||
|
||||
|
|
|
@ -106,6 +106,10 @@ static struct switch_cause_table CAUSE_CHART[] = {
|
|||
{NULL, 0}
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
OCF_HANGUP = (1 << 0)
|
||||
} opaque_channel_flag_t;
|
||||
|
||||
struct switch_channel {
|
||||
char *name;
|
||||
switch_call_direction_t direction;
|
||||
|
@ -132,6 +136,7 @@ struct switch_channel {
|
|||
int vi;
|
||||
int event_count;
|
||||
int profile_index;
|
||||
opaque_channel_flag_t opaque_flags;
|
||||
};
|
||||
|
||||
SWITCH_DECLARE(const char *) switch_channel_cause2str(switch_call_cause_t cause)
|
||||
|
@ -2090,29 +2095,44 @@ SWITCH_DECLARE(void) switch_channel_set_hangup_time(switch_channel_t *channel)
|
|||
SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_hangup(switch_channel_t *channel,
|
||||
const char *file, const char *func, int line, switch_call_cause_t hangup_cause)
|
||||
{
|
||||
int ok = 0;
|
||||
|
||||
switch_assert(channel != NULL);
|
||||
|
||||
/* one per customer */
|
||||
switch_mutex_lock(channel->state_mutex);
|
||||
if (!(channel->opaque_flags & OCF_HANGUP)) {
|
||||
channel->opaque_flags |= OCF_HANGUP;
|
||||
ok = 1;
|
||||
}
|
||||
switch_mutex_unlock(channel->state_mutex);
|
||||
|
||||
if (!ok) {
|
||||
return channel->state;
|
||||
}
|
||||
|
||||
switch_channel_clear_flag(channel, CF_BLOCK_STATE);
|
||||
|
||||
if (channel->state < CS_HANGUP) {
|
||||
switch_channel_state_t last_state;
|
||||
switch_event_t *event;
|
||||
|
||||
if (hangup_cause == SWITCH_CAUSE_LOSE_RACE) {
|
||||
switch_channel_set_variable(channel, "presence_call_info", NULL);
|
||||
}
|
||||
|
||||
switch_mutex_lock(channel->state_mutex);
|
||||
last_state = channel->state;
|
||||
channel->state = CS_HANGUP;
|
||||
switch_mutex_unlock(channel->state_mutex);
|
||||
|
||||
|
||||
if (hangup_cause == SWITCH_CAUSE_LOSE_RACE) {
|
||||
switch_channel_set_variable(channel, "presence_call_info", NULL);
|
||||
}
|
||||
|
||||
channel->hangup_cause = hangup_cause;
|
||||
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_channel_get_uuid(channel), SWITCH_LOG_NOTICE, "Hangup %s [%s] [%s]\n",
|
||||
channel->name, state_names[last_state], switch_channel_cause2str(channel->hangup_cause));
|
||||
|
||||
|
||||
if (!switch_core_session_running(channel->session)) {
|
||||
if (!switch_core_session_running(channel->session) && !switch_core_session_started(channel->session)) {
|
||||
switch_core_session_thread_launch(channel->session);
|
||||
}
|
||||
|
||||
|
|
|
@ -1024,7 +1024,12 @@ SWITCH_DECLARE(void) switch_core_session_signal_state_change(switch_core_session
|
|||
|
||||
SWITCH_DECLARE(unsigned int) switch_core_session_running(switch_core_session_t *session)
|
||||
{
|
||||
return session->thread_running;
|
||||
return switch_test_flag(session, SSF_THREAD_RUNNING) ? 1 : 0;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(unsigned int) switch_core_session_started(switch_core_session_t *session)
|
||||
{
|
||||
return switch_test_flag(session, SSF_THREAD_STARTED) ? 1 : 0;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t **session, const char *file, const char *func, int line)
|
||||
|
@ -1197,17 +1202,22 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_thread_launch(switch_core_se
|
|||
|
||||
switch_mutex_lock(session->mutex);
|
||||
|
||||
if (!session->thread_running) {
|
||||
session->thread_running = 1;
|
||||
if (switch_test_flag(session, SSF_THREAD_RUNNING)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot double-launch thread!\n");
|
||||
} else if (switch_test_flag(session, SSF_THREAD_STARTED)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot launch thread again after it has already been run!\n");
|
||||
} else {
|
||||
switch_set_flag(session, SSF_THREAD_RUNNING);
|
||||
switch_set_flag(session, SSF_THREAD_STARTED);
|
||||
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
||||
if (switch_thread_create(&thread, thd_attr, switch_core_session_thread, session, session->pool) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_set_flag(session, SSF_THREAD_STARTED);
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
session->thread_running = 0;
|
||||
switch_clear_flag(session, SSF_THREAD_RUNNING);
|
||||
switch_clear_flag(session, SSF_THREAD_STARTED);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot create thread!\n");
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Cannot double-launch thread!\n");
|
||||
}
|
||||
|
||||
switch_mutex_unlock(session->mutex);
|
||||
|
|
|
@ -291,7 +291,7 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
|
|||
*/
|
||||
switch_assert(session != NULL);
|
||||
|
||||
session->thread_running = 1;
|
||||
switch_set_flag(session, SSF_THREAD_RUNNING);
|
||||
endpoint_interface = session->endpoint_interface;
|
||||
switch_assert(endpoint_interface != NULL);
|
||||
|
||||
|
@ -409,7 +409,7 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
|
|||
done:
|
||||
switch_mutex_unlock(session->mutex);
|
||||
|
||||
session->thread_running = 0;
|
||||
switch_clear_flag(session, SSF_THREAD_RUNNING);
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_core_session_destroy_state(switch_core_session_t *session)
|
||||
|
@ -429,7 +429,6 @@ SWITCH_DECLARE(void) switch_core_session_destroy_state(switch_core_session_t *se
|
|||
switch_channel_clear_flag(session->channel, CF_TRANSFER);
|
||||
switch_channel_clear_flag(session->channel, CF_REDIRECT);
|
||||
|
||||
session->thread_running = 1;
|
||||
endpoint_interface = session->endpoint_interface;
|
||||
switch_assert(endpoint_interface != NULL);
|
||||
|
||||
|
@ -567,7 +566,6 @@ SWITCH_DECLARE(void) switch_core_session_reporting_state(switch_core_session_t *
|
|||
|
||||
switch_assert(session != NULL);
|
||||
|
||||
session->thread_running = 1;
|
||||
endpoint_interface = session->endpoint_interface;
|
||||
switch_assert(endpoint_interface != NULL);
|
||||
|
||||
|
|
Loading…
Reference in New Issue