/************************************************************************
* IRC - Internet Relay Chat, src/loader.c
*
* Copyright (C) 2000-2003 TR-IRCD Development
*
* Copyright (C) 1990 Jarkko Oikarinen and
* University of Oulu, Co Center
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: loader.c,v 1.6 2003/06/14 13:55:52 tr-ircd Exp $
*/
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "confitem.h"
#include "h.h"
#include "hook.h"
#include "s_conf.h"
#include "msg.h"
#include "numeric.h"
#include "tools.h"
#include "modules.h"
#ifndef STATIC_MODULES
static int loader_initcheck = 0;
static int envoke_exit_loader = 0;
void do_queue(void);
extern void *dynlink_load_element(char *path, int logevent);
extern void *dynlink_extract_symbol(void *library, char *symbolname, void *symbol);
pthread_t loader_thread;
pthread_attr_t loader_attributes;
pthread_cond_t loader_condition;
pthread_condattr_t loader_condition_attributes;
/* Do not reorder the following elements, they are
* required for the mutex to work correctly
* -TimeMr14C
*/
int modlist_action_add = 0;
int modlist_action_del = 0;
pthread_mutex_t loader_mutex;
pthread_mutexattr_t loader_mutex_attributes;
static int hookid_load_module = 0;
static int hookid_unload_module = 0;
static int undef_symbol = -1;
static int toomany_symbols = -1;
static int link_editor = -1;
static int module_error = -1;
dlink_list loaded_module_list;
dlink_list load_queue;
dlink_list unload_queue;
void init_loader(void *unused)
{
int loader_main_return = 0;
hookid_load_module = hook_add_event("load module");
hookid_unload_module = hook_add_event("unload module");
undef_symbol =
logevent_register("undefined symbol", LOG_ON_LOG, LOG_ERRORLOG, LOG_ERROR,
"Undefined symbol: %s");
toomany_symbols =
logevent_register("too many symbols", LOG_ON_LOG, LOG_ERRORLOG, LOG_ERROR,
"Symbol `%s' found in `%s' and `%s'");
link_editor =
logevent_register("link editor error", LOG_ON_LOG, LOG_ERRORLOG, LOG_ERROR,
"Link editor error: %s for %s");
module_error =
logevent_register("module load error", LOG_ON_LOG, LOG_ERRORLOG, LOG_ERROR,
"Error loading module %s: %s");
if (pthread_attr_init(&loader_attributes)) {
logevent_personal("Failed in initializing module loader: INIT ATTRIBUTES");
return;
}
if (pthread_attr_setdetachstate(&loader_attributes, PTHREAD_CREATE_JOINABLE) != 0) {
logevent_personal("Failed in setting detachstate for the module loader thread");
return;
}
if (pthread_attr_setschedpolicy(&loader_attributes, SCHED_OTHER) != 0) {
logevent_personal("Failed in setting scheduling policy for the module loader thread");
return;
}
if (pthread_attr_setinheritsched(&loader_attributes, PTHREAD_INHERIT_SCHED) != 0) {
logevent_personal("Failed in setting interit scheduling for the module loader thread");
return;
}
if (pthread_mutexattr_init(&loader_mutex_attributes) != 0) {
logevent_personal("Failed in initializing module loader mutex attributes");
return;
}
if (pthread_mutex_init(&loader_mutex, &loader_mutex_attributes) != 0) {
logevent_personal("Failed in initializing module loader mutex");
return;
}
pthread_condattr_init(&loader_condition_attributes);
if (pthread_cond_init(&loader_condition, &loader_condition_attributes) != 0) {
logevent_personal("Failed in initializing module loader conditional predicate");
return;
}
if (pthread_create(&loader_thread, &loader_attributes, loader_main, &loader_main_return) != 0) {
logevent_personal("Failed in creating thread for the module loader");
return;
}
memset(&loaded_module_list, 0, sizeof(loaded_module_list));
memset(&load_queue, 0, sizeof(load_queue));
memset(&unload_queue, 0, sizeof(unload_queue));
loaded_module_list.head = loaded_module_list.tail = NULL;
load_queue.head = load_queue.tail = NULL;
unload_queue.head = unload_queue.tail = NULL;
}
static void loader_init_begin(int check)
{
if (check)
return;
if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) {
logevent_personal("Unable to set cancel state for the loader thread");
pthread_exit(0);
}
if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) != 0) {
logevent_personal("Unable to set cancel type for loader thread");
pthread_exit(0);
}
loader_initcheck = 1;
}
void *loader_main(void *unused)
{
loader_init_begin(loader_initcheck);
while (1) {
pthread_mutex_lock(&loader_mutex);
while ((modlist_action_add < 1) && (modlist_action_del < 1))
pthread_cond_wait(&loader_condition, &loader_mutex);
do_queue();
pthread_mutex_unlock(&loader_mutex);
if (envoke_exit_loader == 1)
break;
}
pthread_mutex_destroy(&loader_mutex);
pthread_mutexattr_destroy(&loader_mutex_attributes);
pthread_cond_destroy(&loader_condition);
pthread_condattr_destroy(&loader_condition_attributes);
pthread_attr_destroy(&loader_attributes);
pthread_exit(0);
return NULL;
}
void do_queue(void)
{
dlink_node *ptr, *prev_ptr;
struct module *mod;
int val;
if (modlist_action_del > 0) {
for (ptr = unload_queue.tail; ptr; ptr = prev_ptr) {
prev_ptr = ptr->prev;
mod = ptr->data;
val = unload_queued_module(mod);
dlinkDeleteNode(ptr, &unload_queue);
modlist_action_del--;
}
}
if (modlist_action_add > 0) {
for (ptr = load_queue.tail; ptr; ptr = prev_ptr) {
prev_ptr = ptr->prev;
mod = ptr->data;
val = load_queued_module(mod);
dlinkDeleteNode(ptr, &load_queue);
modlist_action_add--;
}
}
return;
}
struct module *enqueue_one_module_to_load(char *path, int flags)
{
dlink_node *ptr;
struct module *new_module, *mod;
struct hook_data thisdata;
char *mod_basename;
mod_basename = irc_basename(path);
for (ptr = loaded_module_list.head; ptr; ptr = ptr->next) {
mod = ptr->data;
if (irc_strcmp(mod->name, mod_basename) == 0)
return mod;
}
for (ptr = load_queue.head; ptr; ptr = ptr->next) {
mod = ptr->data;
if (irc_strcmp(mod->name, mod_basename) == 0)
return mod;
}
thisdata.name = mod_basename;
if (hook_call_event(hookid_load_module, &thisdata))
return NULL;
new_module = (struct module *) MyMalloc(sizeof(struct module));
if (!new_module)
return NULL;
memset(new_module, 0, sizeof(new_module));
new_module->name = mod_basename;
DupString(new_module->pathname, path);
new_module->flags = flags;
ptr = make_dlink_node();
pthread_mutex_lock(&loader_mutex);
dlinkAdd(new_module, ptr, &load_queue);
modlist_action_add++;
pthread_cond_signal(&loader_condition);
pthread_mutex_unlock(&loader_mutex);
return new_module;
}
struct module *enqueue_one_module_to_unload(char *name)
{
struct module *mod;
struct hook_data thisdata;
dlink_node *ptr, *next_ptr, *m;
for (ptr = loaded_module_list.head; ptr; ptr = next_ptr) {
next_ptr = ptr->next;
mod = ptr->data;
if (irc_strcmp(mod->name, name) == 0) {
thisdata.name = mod->name;
if (hook_call_event(hookid_unload_module, &thisdata)) {
sendto_ops("Module %s has been denied usage.", mod->name);
return NULL;
}
if (mod->flags & MODULE_PERSISTENT) {
sendto_ops("Module %s cannot be unloaded.", mod->name);
return NULL;
}
m = make_dlink_node();
pthread_mutex_lock(&loader_mutex);
dlinkAdd(mod, m, &unload_queue);
modlist_action_del++;
pthread_cond_signal(&loader_condition);
pthread_mutex_unlock(&loader_mutex);
return mod;
}
}
return NULL;
}
void enqueue_all_modules_to_unload(void)
{
struct module *mod;
struct hook_data thisdata;
dlink_node *ptr, *next_ptr, *m;
pthread_mutex_lock(&loader_mutex);
for (ptr = loaded_module_list.head; ptr; ptr = next_ptr) {
next_ptr = ptr->next;
mod = ptr->data;
thisdata.name = mod->name;
if (mod->flags & MODULE_PERSISTENT)
continue;
if (hook_call_event(hookid_unload_module, &thisdata))
continue;
m = make_dlink_node();
dlinkAdd(mod, m, &unload_queue);
modlist_action_del++;
}
if (modlist_action_del)
pthread_cond_signal(&loader_condition);
pthread_mutex_unlock(&loader_mutex);
}
void terminate_loader(void)
{
struct module *mod;
dlink_node *ptr, *next_ptr, *m;
pthread_mutex_lock(&loader_mutex);
for (ptr = loaded_module_list.head; ptr; ptr = next_ptr) {
next_ptr = ptr->next;
mod = ptr->data;
m = make_dlink_node();
dlinkAdd(mod, m, &unload_queue);
modlist_action_del++;
}
if (modlist_action_del)
pthread_cond_signal(&loader_condition);
pthread_mutex_unlock(&loader_mutex);
envoke_exit_loader = 1;
}
#else
void init_loader(void *unused)
{
return;
}
void terminate_loader(void)
{
return;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1