add rwlocks to module parents

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@10362 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2008-11-12 17:10:20 +00:00
parent 2fbe2fd1cf
commit c62253405f
5 changed files with 121 additions and 46 deletions

View File

@ -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 */

View File

@ -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;
};

View File

@ -888,20 +888,47 @@ SWITCH_STANDARD_API(load_function)
return SWITCH_STATUS_SUCCESS;
}
#define UNLOAD_SYNTAX "[-f] <mod_name>"
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);

View File

@ -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);

View File

@ -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; }