diff --git a/src/include/switch_loadable_module.h b/src/include/switch_loadable_module.h index 50664d1343..9896725629 100644 --- a/src/include/switch_loadable_module.h +++ b/src/include/switch_loadable_module.h @@ -80,6 +80,7 @@ SWITCH_BEGIN_EXTERN_C switch_asr_interface_t *asr_interface; /*! the table of management interfaces the module has implmented */ switch_management_interface_t *management_interface; + switch_thread_rwlock_t *rwlock; switch_memory_pool_t *pool; }; @@ -255,7 +256,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_exists(const char *mod); \param err pointer to error message \return the status */ -SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(char *dir, char *fname, const char **err); +SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(char *dir, char *fname, switch_bool_t force, const char **err); /* Prototypes of module interface functions */ diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index 36f16bb4ca..a144c333fb 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -30,10 +30,10 @@ * */ /*! \file switch_module_interfaces.h - \brief Module Interface Definitions + \brief Module Interface Definitions - This module holds the definition of data abstractions used to implement various pluggable - interfaces and pluggable event handlers. + This module holds the definition of data abstractions used to implement various pluggable + interfaces and pluggable event handlers. */ #ifndef SWITCH_MODULE_INTERFACES_H @@ -44,8 +44,8 @@ SWITCH_BEGIN_EXTERN_C /*! \brief A table of functions to execute at various states -*/ - typedef enum { + */ +typedef enum { SWITCH_SHN_ON_INIT, SWITCH_SHN_ON_ROUTING, SWITCH_SHN_ON_EXECUTE, @@ -99,31 +99,7 @@ struct switch_io_event_hooks; typedef switch_call_cause_t (*switch_io_outgoing_channel_t) - - - - - - - - - - - - - - - - - - - - - - - - - (switch_core_session_t *, switch_event_t *, switch_caller_profile_t *, switch_core_session_t **, switch_memory_pool_t **, switch_originate_flag_t); +(switch_core_session_t *, switch_event_t *, switch_caller_profile_t *, switch_core_session_t **, switch_memory_pool_t **, switch_originate_flag_t); typedef switch_status_t (*switch_io_read_frame_t) (switch_core_session_t *, switch_frame_t **, switch_io_flag_t, int); typedef switch_status_t (*switch_io_write_frame_t) (switch_core_session_t *, switch_frame_t *, switch_io_flag_t, int); typedef switch_status_t (*switch_io_kill_channel_t) (switch_core_session_t *, int); @@ -197,6 +173,8 @@ struct switch_endpoint_interface { switch_thread_rwlock_t *rwlock; + /* parent */ + switch_loadable_module_interface_t *parent; /* to facilitate linking */ struct switch_endpoint_interface *next; }; @@ -248,6 +226,7 @@ struct switch_timer_interface { /*! function to deallocate the timer */ switch_status_t (*timer_destroy) (switch_timer_t *); switch_thread_rwlock_t *rwlock; + switch_loadable_module_interface_t *parent; struct switch_timer_interface *next; }; @@ -258,6 +237,7 @@ struct switch_dialplan_interface { /*! the function to read an extension and set a channels dialpan */ switch_dialplan_hunt_function_t hunt_function; switch_thread_rwlock_t *rwlock; + switch_loadable_module_interface_t *parent; struct switch_dialplan_interface *next; }; @@ -282,6 +262,7 @@ struct switch_file_interface { /*! list of supported file extensions */ char **extens; switch_thread_rwlock_t *rwlock; + switch_loadable_module_interface_t *parent; struct switch_file_interface *next; }; @@ -359,6 +340,7 @@ struct switch_asr_interface { /*! function to read results from the ASR */ switch_status_t (*asr_get_results) (switch_asr_handle_t *ah, char **xmlstr, switch_asr_flag_t *flags); switch_thread_rwlock_t *rwlock; + switch_loadable_module_interface_t *parent; struct switch_asr_interface *next; }; @@ -400,6 +382,7 @@ struct switch_speech_interface { void (*speech_numeric_param_tts) (switch_speech_handle_t *sh, char *param, int val); void (*speech_float_param_tts) (switch_speech_handle_t *sh, char *param, double val); switch_thread_rwlock_t *rwlock; + switch_loadable_module_interface_t *parent; struct switch_speech_interface *next; }; @@ -433,6 +416,7 @@ struct switch_say_interface { /*! function to pass down to the module */ switch_say_callback_t say_function; switch_thread_rwlock_t *rwlock; + switch_loadable_module_interface_t *parent; struct switch_say_interface *next; }; @@ -443,6 +427,7 @@ struct switch_chat_interface { /*! function to open the directory interface */ switch_status_t (*chat_send) (char *proto, char *from, char *to, char *subject, char *body, char *hint); switch_thread_rwlock_t *rwlock; + switch_loadable_module_interface_t *parent; struct switch_chat_interface *next; }; @@ -453,6 +438,7 @@ struct switch_management_interface { /*! function to open the directory interface */ switch_status_t (*management_function) (char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen); switch_thread_rwlock_t *rwlock; + switch_loadable_module_interface_t *parent; struct switch_management_interface *next; }; @@ -471,6 +457,7 @@ struct switch_directory_interface { /*! function to advance to the next name/value pair in the current record */ switch_status_t (*directory_next_pair) (switch_directory_handle_t *dh, char **var, char **val); switch_thread_rwlock_t *rwlock; + switch_loadable_module_interface_t *parent; struct switch_directory_interface *next; }; @@ -595,6 +582,7 @@ struct switch_codec_interface { switch_codec_implementation_t *implementations; uint32_t codec_id; switch_thread_rwlock_t *rwlock; + switch_loadable_module_interface_t *parent; struct switch_codec_interface *next; }; @@ -613,6 +601,7 @@ struct switch_application_interface { /*! flags to control behaviour */ uint32_t flags; switch_thread_rwlock_t *rwlock; + switch_loadable_module_interface_t *parent; struct switch_application_interface *next; }; @@ -627,6 +616,7 @@ struct switch_api_interface { /*! an example of the api syntax */ const char *syntax; switch_thread_rwlock_t *rwlock; + switch_loadable_module_interface_t *parent; struct switch_api_interface *next; }; diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index ecc635a32d..5679173dd0 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -888,20 +888,47 @@ SWITCH_STANDARD_API(load_function) return SWITCH_STATUS_SUCCESS; } +#define UNLOAD_SYNTAX "[-f] " SWITCH_STANDARD_API(unload_function) { const char *err; + switch_bool_t force = SWITCH_FALSE; + const char *p = cmd; if (session) { return SWITCH_STATUS_FALSE; } if (switch_strlen_zero(cmd)) { - stream->write_function(stream, "-USAGE: %s\n", LOAD_SYNTAX); + stream->write_function(stream, "-USAGE: %s\n", UNLOAD_SYNTAX); return SWITCH_STATUS_SUCCESS; } - if (switch_loadable_module_unload_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, &err) == SWITCH_STATUS_SUCCESS) { + + if (*p == '-') { + p++; + while(p && *p) { + switch (*p) { + case ' ': + cmd = p+1; + goto end; + case 'f': + force = SWITCH_TRUE; + break; + default: + break; + } + p++; + } + } + end: + + if (switch_strlen_zero(cmd)) { + stream->write_function(stream, "-USAGE: %s\n", UNLOAD_SYNTAX); + return SWITCH_STATUS_SUCCESS; + } + + if (switch_loadable_module_unload_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, force, &err) == SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "+OK\n"); } else { stream->write_function(stream, "-ERR [%s]\n", err); @@ -913,20 +940,46 @@ SWITCH_STANDARD_API(unload_function) SWITCH_STANDARD_API(reload_function) { const char *err; + switch_bool_t force = SWITCH_FALSE; + const char *p = cmd; if (session) { return SWITCH_STATUS_FALSE; } if (switch_strlen_zero(cmd)) { - stream->write_function(stream, "-USAGE: %s\n", LOAD_SYNTAX); + stream->write_function(stream, "-USAGE: %s\n", UNLOAD_SYNTAX); return SWITCH_STATUS_SUCCESS; } - if (switch_loadable_module_unload_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, &err) == SWITCH_STATUS_SUCCESS) { + if (*p == '-') { + p++; + while(p && *p) { + switch (*p) { + case ' ': + cmd = p+1; + goto end; + case 'f': + force = SWITCH_TRUE; + break; + default: + break; + } + p++; + } + } + end: + + if (switch_strlen_zero(cmd)) { + stream->write_function(stream, "-USAGE: %s\n", UNLOAD_SYNTAX); + return SWITCH_STATUS_SUCCESS; + } + + if (switch_loadable_module_unload_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, force, &err) == SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "+OK module unloaded\n"); } else { stream->write_function(stream, "-ERR unloading module [%s]\n", err); + return SWITCH_STATUS_SUCCESS; } if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, SWITCH_TRUE, &err) == SWITCH_STATUS_SUCCESS) { @@ -2889,8 +2942,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "reloadacl", "Reload ACL", reload_acl_function, "[reloadxml]"); switch_console_set_complete("add reloadacl reloadxml"); SWITCH_ADD_API(commands_api_interface, "reloadxml", "Reload XML", reload_xml_function, ""); - SWITCH_ADD_API(commands_api_interface, "unload", "Unload Module", unload_function, LOAD_SYNTAX); - SWITCH_ADD_API(commands_api_interface, "reload", "Reload Module", reload_function, LOAD_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "unload", "Unload Module", unload_function, UNLOAD_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "reload", "Reload Module", reload_function, UNLOAD_SYNTAX); SWITCH_ADD_API(commands_api_interface, "load", "Load Module", load_function, LOAD_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_transfer", "Transfer a session", transfer_function, TRANSFER_SYNTAX); SWITCH_ADD_API(commands_api_interface, "pause", "Pause", pause_function, PAUSE_SYNTAX); diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 6449444f9d..debcb4a487 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -827,7 +827,7 @@ SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t * switch_core_destroy_memory_pool(&pool); switch_thread_rwlock_unlock(endpoint_interface->rwlock); - + switch_thread_rwlock_unlock(endpoint_interface->parent->rwlock); } SWITCH_STANDARD_SCHED_FUNC(sch_heartbeat_callback) @@ -1031,6 +1031,7 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_uuid(const s return NULL; } + switch_thread_rwlock_rdlock(endpoint_interface->parent->rwlock); switch_thread_rwlock_rdlock(endpoint_interface->rwlock); if (pool && *pool) { @@ -1281,9 +1282,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(switch_core_session_t * switch_channel_set_variable(session->channel, SWITCH_CURRENT_APPLICATION_VARIABLE, application_interface->interface_name); + switch_thread_rwlock_rdlock(application_interface->parent->rwlock); switch_thread_rwlock_rdlock(application_interface->rwlock); application_interface->application_function(session, arg); switch_thread_rwlock_unlock(application_interface->rwlock); + switch_thread_rwlock_unlock(application_interface->parent->rwlock); if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(session->channel, event); diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index e65e3e6db2..ad448ad572 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -74,7 +74,7 @@ struct switch_loadable_module_container { }; static struct switch_loadable_module_container loadable_modules; -static void do_shutdown(switch_loadable_module_t *module, switch_bool_t shutdown, switch_bool_t unload); +static switch_status_t do_shutdown(switch_loadable_module_t *module, switch_bool_t shutdown, switch_bool_t unload, switch_bool_t fail_if_busy, const char **err); static switch_status_t switch_loadable_module_load_module_ex(char *dir, char *fname, switch_bool_t runtime, switch_bool_t global, const char **err); static void *switch_loadable_module_exec(switch_thread_t *thread, void *obj) @@ -416,7 +416,7 @@ static switch_status_t switch_loadable_module_unprocess(switch_loadable_module_t switch_event_t *event; switch_mutex_lock(loadable_modules.mutex); - + if (old_module->module_interface->endpoint_interface) { const switch_endpoint_interface_t *ptr; @@ -670,6 +670,7 @@ static switch_status_t switch_loadable_module_unprocess(switch_loadable_module_t } } } + switch_mutex_unlock(loadable_modules.mutex); return SWITCH_STATUS_SUCCESS; @@ -882,11 +883,15 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_exists(const char *mod) return status; } -SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(char *dir, char *fname, const char **err) +SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(char *dir, char *fname, switch_bool_t force, const char **err) { switch_loadable_module_t *module = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; + if (force) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Spin the barrel and pull the trigger.......!\n"); + } + switch_mutex_lock(loadable_modules.mutex); if ((module = switch_core_hash_find(loadable_modules.module_hash, fname))) { if (module->perm) { @@ -895,7 +900,9 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(char *dir, status = SWITCH_STATUS_NOUNLOAD; goto end; } else { - do_shutdown(module, SWITCH_TRUE, SWITCH_TRUE); + if ((status = do_shutdown(module, SWITCH_TRUE, SWITCH_TRUE, !force, err) != SWITCH_STATUS_SUCCESS)) { + goto end; + } } switch_core_hash_delete(loadable_modules.module_hash, fname); } else { @@ -905,6 +912,10 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(char *dir, end: switch_mutex_unlock(loadable_modules.mutex); + if (force) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "PHEW!\n"); + } + return status; } @@ -1140,11 +1151,19 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init() return SWITCH_STATUS_SUCCESS; } -static void do_shutdown(switch_loadable_module_t *module, switch_bool_t shutdown, switch_bool_t unload) +static switch_status_t do_shutdown(switch_loadable_module_t *module, switch_bool_t shutdown, switch_bool_t unload, switch_bool_t fail_if_busy, const char **err) { int32_t flags = switch_core_flags(); switch_assert(module != NULL); + if (fail_if_busy && module->module_interface->rwlock && switch_thread_rwlock_trywrlock(module->module_interface->rwlock) != SWITCH_STATUS_SUCCESS) { + if (err) { + *err = "Module in use."; + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Module %s is in use, cannot unload.\n", module->module_interface->module_name); + return SWITCH_STATUS_FALSE; + } + if (shutdown) { switch_loadable_module_unprocess(module); if (module->switch_module_shutdown) { @@ -1155,6 +1174,10 @@ static void do_shutdown(switch_loadable_module_t *module, switch_bool_t shutdown } } + if (fail_if_busy && module->module_interface->rwlock) { + switch_thread_rwlock_unlock(module->module_interface->rwlock); + } + if (unload && module->status != SWITCH_STATUS_NOUNLOAD && !(flags & SCF_VG)) { switch_memory_pool_t *pool; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s unloaded.\n", module->module_interface->module_name); @@ -1165,6 +1188,8 @@ static void do_shutdown(switch_loadable_module_t *module, switch_bool_t shutdown } } + return SWITCH_STATUS_SUCCESS; + } SWITCH_DECLARE(void) switch_loadable_module_shutdown(void) @@ -1177,7 +1202,7 @@ SWITCH_DECLARE(void) switch_loadable_module_shutdown(void) switch_hash_this(hi, NULL, NULL, &val); module = (switch_loadable_module_t *) val; if (!module->perm) { - do_shutdown(module, SWITCH_TRUE, SWITCH_FALSE); + do_shutdown(module, SWITCH_TRUE, SWITCH_FALSE, SWITCH_FALSE, NULL); } } @@ -1187,7 +1212,7 @@ SWITCH_DECLARE(void) switch_loadable_module_shutdown(void) switch_hash_this(hi, NULL, NULL, &val); module = (switch_loadable_module_t *) val; if (!module->perm) { - do_shutdown(module, SWITCH_FALSE, SWITCH_TRUE); + do_shutdown(module, SWITCH_FALSE, SWITCH_TRUE, SWITCH_FALSE, NULL); } } @@ -1447,11 +1472,13 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char * if (cmd && (api = switch_loadable_module_get_api_interface(cmd)) != 0) { + switch_thread_rwlock_rdlock(api->parent->rwlock); switch_thread_rwlock_rdlock(api->rwlock); if ((status = api->function(arg, session, stream)) != SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "COMMAND RETURNED ERROR!\n"); } switch_thread_rwlock_unlock(api->rwlock); + switch_thread_rwlock_unlock(api->parent->rwlock); } else { status = SWITCH_STATUS_FALSE; stream->write_function(stream, "INVALID COMMAND!\n"); @@ -1476,7 +1503,7 @@ SWITCH_DECLARE(switch_loadable_module_interface_t *) switch_loadable_module_crea mod->pool = pool; mod->module_name = switch_core_strdup(mod->pool, name); - + switch_thread_rwlock_create(&mod->rwlock, mod->pool); return mod; } @@ -1491,6 +1518,7 @@ SWITCH_DECLARE(switch_loadable_module_interface_t *) switch_loadable_module_crea mod->_TYPE_##_interface = i; \ } \ switch_thread_rwlock_create(&i->rwlock, mod->pool); \ + i->parent = mod; \ return i; }