diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index 121beddb61..cb4c2a2a49 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -41,6 +41,9 @@ #ifdef __cplusplus extern "C" { +#ifdef __FORMATBUG +} +#endif #endif #include @@ -48,6 +51,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -257,6 +261,12 @@ typedef apr_thread_cond_t switch_thread_cond_t; DoxyDefine(apr_status_t switch_thread_cond_create(switch_thread_cond_t **cond, switch_pool_t *pool);) #define switch_thread_cond_create apr_thread_cond_create +typedef apr_os_thread_t switch_thread_id; + +#define switch_thread_data_set apr_thread_data_set +#define switch_thread_data_get apr_thread_data_get +#define switch_thread_self apr_os_thread_current + /** * Put the active calling thread to sleep until signaled to wake up. Each * condition variable must be associated with a mutex, and that mutex must diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 89c7fa38a2..0dab55dc16 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -514,6 +514,7 @@ typedef enum { SWITCH_EVENT_UNPUBLISH - UnPublish SWITCH_EVENT_TALK - Talking Detected SWITCH_EVENT_NOTALK - Not Talking Detected + SWITCH_EVENT_SESSION_CRASH - Session Crashed SWITCH_EVENT_ALL - All events at once @@ -538,6 +539,7 @@ typedef enum { SWITCH_EVENT_UNPUBLISH, SWITCH_EVENT_TALK, SWITCH_EVENT_NOTALK, + SWITCH_EVENT_SESSION_CRASH, SWITCH_EVENT_ALL } switch_event_t; diff --git a/src/mod/applications/mod_ivrtest/mod_ivrtest.c b/src/mod/applications/mod_ivrtest/mod_ivrtest.c index 9884724c51..2617395999 100644 --- a/src/mod/applications/mod_ivrtest/mod_ivrtest.c +++ b/src/mod/applications/mod_ivrtest/mod_ivrtest.c @@ -48,6 +48,13 @@ static switch_status on_dtmf(switch_core_session *session, char *dtmf, void *buf } + +static void disast_function(switch_core_session *session, char *data) +{ + printf("%s WOOHOO\n", (char *) 42); +} + + static void dirtest_function(switch_core_session *session, char *data) { char *var, *val; @@ -194,11 +201,19 @@ static const switch_state_handler_table state_handlers = { /*.on_transmit */ NULL }; + +static const switch_application_interface disast_application_interface = { + /*.interface_name */ "disast", + /*.application_function */ disast_function, + NULL, NULL, NULL, + /*.next*/ NULL +}; + static const switch_application_interface tts_application_interface = { /*.interface_name */ "tts", /*.application_function */ tts_function, NULL, NULL, NULL, - /*.next*/ NULL + /*.next*/ &disast_application_interface }; static const switch_application_interface dirtest_application_interface = { diff --git a/src/switch_core.c b/src/switch_core.c index 3ab1385a78..f2fcd439f1 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -36,6 +36,7 @@ #define SWITCH_EVENT_QUEUE_LEN 256 #define SWITCH_SQL_QUEUE_LEN 2000 +#define SWITCH_THREAD_JMP_KEY "JMP_KEY" struct switch_core_session { uint32_t id; @@ -83,6 +84,7 @@ struct switch_core_runtime { uint32_t session_id; apr_pool_t *memory_pool; switch_hash *session_table; + switch_hash *stack_table; switch_core_db *db; switch_core_db *event_db; const struct switch_state_handler_table *state_handlers[SWITCH_MAX_STATE_HANDLERS]; @@ -1811,12 +1813,50 @@ SWITCH_DECLARE(unsigned int) switch_core_session_runing(switch_core_session *ses return session->thread_running; } +static int handle_fatality(int sig) +{ + switch_thread_id thread_id; + jmp_buf *env; + + if (sig && (thread_id = switch_thread_self()) && (env = (jmp_buf *) apr_hash_get(runtime.stack_table, &thread_id, sizeof(thread_id)))) { + longjmp(*env, sig); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Caught SEGV for unmapped thread!"); + abort(); + } + + return 0; +} + + SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session) { switch_channel_state state = CS_NEW, laststate = CS_HANGUP, midstate = CS_DONE; const switch_endpoint_interface *endpoint_interface; const switch_state_handler_table *driver_state_handler = NULL; const switch_state_handler_table *application_state_handler = NULL; + switch_thread_id thread_id = switch_thread_self(); + jmp_buf env; + int sig; + + signal(SIGSEGV, (void *) handle_fatality); + signal(SIGFPE, (void *) handle_fatality); +#ifndef WIN32 + signal(SIGBUS, (void *) handle_fatality); +#endif + + if ((sig = setjmp(env)) != 0) { + switch_event *event; + + if (switch_event_create(&event, SWITCH_EVENT_SESSION_CRASH) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(session->channel, event); + switch_event_fire(&event); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Thread has crashed for channel %s\n", switch_channel_get_name(session->channel)); + switch_channel_hangup(session->channel, SWITCH_CAUSE_CRASH); + } else { + apr_hash_set(runtime.stack_table, &thread_id, sizeof(thread_id), &env); + } /* Life of the channel. you have channel and pool in your session @@ -1850,7 +1890,6 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session) int proceed = 1; midstate = state; - switch (state) { case CS_NEW: /* Just created, Waiting for first instructions */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State NEW\n", switch_channel_get_name(session->channel)); @@ -2091,6 +2130,8 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session) } } + apr_hash_set(runtime.stack_table, &thread_id, sizeof(thread_id), NULL); + session->thread_running = 0; } @@ -2650,6 +2691,7 @@ SWITCH_DECLARE(switch_status) switch_core_init(char *console) runtime.session_id = 1; switch_core_hash_init(&runtime.session_table, runtime.memory_pool); + switch_core_hash_init(&runtime.stack_table, runtime.memory_pool); time(&runtime.initiated); return SWITCH_STATUS_SUCCESS; diff --git a/src/switch_event.c b/src/switch_event.c index 7cb50e675e..b5e45485ab 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -102,6 +102,7 @@ static char *EVENT_NAMES[] = { "UNPUBLISH", "TALK", "NOTALK", + "SESSION_CRASH", "ALL" };