From bbdd77ec3562d0fbe0590c38e339c8f4f0ec9ab8 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 28 Jun 2013 14:20:58 -0500 Subject: [PATCH] fix race condition on device state destroy --- src/mod/applications/mod_skel/mod_skel.c | 25 ++++++++++++++++++ src/switch_channel.c | 33 ++++++++++++++---------- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/mod/applications/mod_skel/mod_skel.c b/src/mod/applications/mod_skel/mod_skel.c index 4722b77d58..37f155aef6 100644 --- a/src/mod/applications/mod_skel/mod_skel.c +++ b/src/mod/applications/mod_skel/mod_skel.c @@ -214,6 +214,28 @@ SWITCH_STANDARD_API(skel_function) return SWITCH_STATUS_SUCCESS; } +static void mycb(switch_core_session_t *session, switch_channel_callstate_t callstate, switch_device_record_t *drec) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_CRIT, + "%s device: %s\nState: %s Dev State: %s/%s Total:%u Offhook:%u Active:%u Held:%u Hungup:%u Dur: %u %s\n", + switch_channel_get_name(channel), + drec->device_id, + switch_channel_callstate2str(callstate), + switch_channel_device_state2str(drec->last_state), + switch_channel_device_state2str(drec->state), + drec->stats.total, + drec->stats.offhook, + drec->stats.active, + drec->stats.held, + drec->stats.hup, + drec->active_stop ? (uint32_t)(drec->active_stop - drec->active_start) / 1000 : 0, + switch_channel_test_flag(channel, CF_FINAL_DEVICE_LEG) ? "FINAL LEG" : ""); + +} + + /* Macro expands to: switch_status_t mod_skel_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */ SWITCH_MODULE_LOAD_FUNCTION(mod_skel_load) { @@ -227,6 +249,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skel_load) SWITCH_ADD_API(api_interface, "skel", "Skel API", skel_function, "syntax"); + switch_channel_bind_device_state_handler(mycb, NULL); + /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; } @@ -237,6 +261,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skel_load) SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skel_shutdown) { /* Cleanup dynamically allocated config settings */ + switch_channel_unbind_device_state_handler(mycb); switch_xml_config_cleanup(instructions); return SWITCH_STATUS_SUCCESS; } diff --git a/src/switch_channel.c b/src/switch_channel.c index 429a48d73f..da41b92739 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -4701,31 +4701,36 @@ SWITCH_DECLARE(void) switch_channel_clear_device_record(switch_channel_t *channe static void process_device_hup(switch_channel_t *channel) { switch_hold_record_t *hr, *newhr, *last = NULL; + switch_device_record_t *drec = NULL; + switch_device_node_t *node; if (!channel->device_node) { return; } switch_mutex_lock(globals.device_mutex); - channel->device_node->hup_profile = switch_caller_profile_dup(channel->device_node->parent->pool, channel->caller_profile); - fetch_device_stats(channel->device_node->parent); + node = channel->device_node; + drec = channel->device_node->parent; - switch_ivr_generate_xml_cdr(channel->session, &channel->device_node->xml_cdr); - if (switch_event_create(&channel->device_node->event, SWITCH_EVENT_CALL_DETAIL) == SWITCH_STATUS_SUCCESS) { - switch_channel_event_set_extended_data(channel, channel->device_node->event); + node->hup_profile = switch_caller_profile_dup(drec->pool, channel->caller_profile); + fetch_device_stats(drec); + + switch_ivr_generate_xml_cdr(channel->session, &node->xml_cdr); + if (switch_event_create(&node->event, SWITCH_EVENT_CALL_DETAIL) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_extended_data(channel, node->event); } for (hr = channel->hold_record; hr; hr = hr->next) { - newhr = switch_core_alloc(channel->device_node->parent->pool, sizeof(*newhr)); + newhr = switch_core_alloc(drec->pool, sizeof(*newhr)); newhr->on = hr->on; newhr->off = hr->off; if (hr->uuid) { - newhr->uuid = switch_core_strdup(channel->device_node->parent->pool, hr->uuid); + newhr->uuid = switch_core_strdup(drec->pool, hr->uuid); } - if (!channel->device_node->hold_record) { - channel->device_node->hold_record = newhr; + if (!node->hold_record) { + node->hold_record = newhr; } else { last->next = newhr; } @@ -4733,15 +4738,17 @@ static void process_device_hup(switch_channel_t *channel) last = newhr; } - if (!channel->device_node->parent->stats.offhook) { /* this is final call */ + if (!drec->stats.offhook) { /* this is final call */ - switch_core_hash_delete(globals.device_hash, channel->device_node->parent->device_id); + switch_core_hash_delete(globals.device_hash, drec->device_id); switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Processing last call from device [%s]\n", - channel->device_node->parent->device_id); + drec->device_id); switch_channel_set_flag(channel, CF_FINAL_DEVICE_LEG); + } else { + channel->device_node = NULL; } - channel->device_node->parent->refs--; + drec->refs--; switch_mutex_unlock(globals.device_mutex);