Only load plugins once and never unload them

Its expensive to load and unload plugins all the time, so lets stop doing that.
Run over the plugin directory and load all plugins and remember them all.
In the future, something should watch the directory and if it changes,
load the new plugins that was put there.
This commit is contained in:
Love Hornquist Astrand
2009-07-17 15:18:00 -07:00
parent de5110c05a
commit d4ca938866

View File

@@ -40,19 +40,28 @@
struct krb5_plugin {
void *symbol;
void *dsohandle;
struct krb5_plugin *next;
};
struct plugin {
enum krb5_plugin_type type;
void *name;
void *symbol;
enum { DSO, SYMBOL } type;
union {
struct {
char *path;
void *dsohandle;
} dso;
struct {
enum krb5_plugin_type type;
char *name;
char *symbol;
} symbol;
} u;
struct plugin *next;
};
static HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER;
static struct plugin *registered = NULL;
static int plugins_needs_scan = 1;
static const char *sysplugin_dirs[] = {
LIBDIR "/plugin/krb5",
@@ -85,14 +94,12 @@ _krb5_plugin_get_next(struct krb5_plugin *p)
#ifdef HAVE_DLOPEN
static krb5_error_code
loadlib(krb5_context context,
enum krb5_plugin_type type,
const char *name,
const char *lib,
struct krb5_plugin **e)
loadlib(krb5_context context, char *path)
{
*e = calloc(1, sizeof(**e));
if (*e == NULL) {
struct plugin *e;
e = calloc(1, sizeof(*e));
if (e == NULL) {
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
@@ -103,24 +110,13 @@ loadlib(krb5_context context,
#ifndef RTLD_LOCAL
#define RTLD_LOCAL 0
#endif
e->type = DSO;
/* ignore error from dlopen, and just keep it as negative cache entry */
e->u.dso.dsohandle = dlopen(path, RTLD_LOCAL|RTLD_LAZY);
e->u.dso.path = path;
(*e)->dsohandle = dlopen(lib, RTLD_LOCAL|RTLD_LAZY);
if ((*e)->dsohandle == NULL) {
free(*e);
*e = NULL;
krb5_set_error_message(context, ENOMEM, "Failed to load %s: %s",
lib, dlerror());
return ENOMEM;
}
/* dlsym doesn't care about the type */
(*e)->symbol = dlsym((*e)->dsohandle, name);
if ((*e)->symbol == NULL) {
dlclose((*e)->dsohandle);
free(*e);
krb5_clear_error_message(context);
return ENOMEM;
}
e->next = registered;
registered = e->next;
return 0;
}
@@ -146,26 +142,35 @@ krb5_plugin_register(krb5_context context,
{
struct plugin *e;
HEIMDAL_MUTEX_lock(&plugin_mutex);
/* check for duplicates */
for (e = registered; e != NULL; e = e->next)
if (e->type == type && strcmp(e->name,name)== 0 && e->symbol == symbol)
for (e = registered; e != NULL; e = e->next) {
if (e->type == SYMBOL &&
strcmp(e->u.symbol.name, name) == 0 &&
e->u.symbol.type == type && e->u.symbol.symbol == symbol) {
HEIMDAL_MUTEX_unlock(&plugin_mutex);
return 0;
}
}
e = calloc(1, sizeof(*e));
if (e == NULL) {
HEIMDAL_MUTEX_unlock(&plugin_mutex);
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
e->type = type;
e->name = strdup(name);
if (e->name == NULL) {
e->type = SYMBOL;
e->u.symbol.type = type;
e->u.symbol.name = strdup(name);
if (e->u.symbol.name == NULL) {
HEIMDAL_MUTEX_unlock(&plugin_mutex);
free(e);
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
e->symbol = symbol;
e->u.symbol.symbol = symbol;
HEIMDAL_MUTEX_lock(&plugin_mutex);
e->next = registered;
registered = e;
HEIMDAL_MUTEX_unlock(&plugin_mutex);
@@ -173,41 +178,19 @@ krb5_plugin_register(krb5_context context,
return 0;
}
krb5_error_code
_krb5_plugin_find(krb5_context context,
enum krb5_plugin_type type,
const char *name,
struct krb5_plugin **list)
static krb5_error_code
load_plugins(krb5_context context)
{
struct krb5_plugin *e;
struct plugin *p;
struct plugin *e;
krb5_error_code ret;
char **dirs = NULL, **di;
struct dirent *entry;
char *path;
DIR *d = NULL;
*list = NULL;
HEIMDAL_MUTEX_lock(&plugin_mutex);
for (p = registered; p != NULL; p = p->next) {
if (p->type != type || strcmp(p->name, name) != 0)
continue;
e = calloc(1, sizeof(*e));
if (e == NULL) {
HEIMDAL_MUTEX_unlock(&plugin_mutex);
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
}
e->symbol = p->symbol;
e->dsohandle = NULL;
e->next = *list;
*list = e;
}
HEIMDAL_MUTEX_unlock(&plugin_mutex);
if (!plugins_needs_scan)
return 0;
plugins_needs_scan = 0;
#ifdef HAVE_DLOPEN
@@ -244,21 +227,83 @@ _krb5_plugin_find(krb5_context context,
if (path == NULL) {
ret = ENOMEM;
krb5_set_error_message(context, ret, "malloc: out of memory");
goto out;
return ret;
}
/* check if already tried */
for (e = registered; e != NULL; e = e->next)
if (e->type == DSO && strcmp(e->u.dso.path, path) == 0)
break;
if (e == NULL) {
ret = loadlib(context, path);
if (ret)
free(path);
}
ret = loadlib(context, type, name, path, &e);
free(path);
if (ret)
continue;
e->next = *list;
*list = e;
}
closedir(d);
}
if (dirs != rk_UNCONST(sysplugin_dirs))
krb5_config_free_strings(dirs);
#endif /* HAVE_DLOPEN */
return 0;
}
static krb5_error_code
add_symbol(krb5_context context, struct krb5_plugin **list, void *symbol)
{
struct krb5_plugin *e;
e = calloc(1, sizeof(*e));
if (e == NULL) {
krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
return ENOMEM;
}
e->symbol = symbol;
e->next = *list;
*list = e;
return 0;
}
krb5_error_code
_krb5_plugin_find(krb5_context context,
enum krb5_plugin_type type,
const char *name,
struct krb5_plugin **list)
{
struct plugin *e;
krb5_error_code ret;
*list = NULL;
HEIMDAL_MUTEX_lock(&plugin_mutex);
load_plugins(context);
for (ret = 0, e = registered; e != NULL; e = e->next) {
switch(e->type) {
case DSO: {
void *sym;
if (e->u.dso.dsohandle == NULL)
continue;
sym = dlsym(e->u.dso.dsohandle, name);
if (sym)
ret = add_symbol(context, list, sym);
break;
}
case SYMBOL:
if (strcmp(e->u.symbol.name, name) == 0 && e->u.symbol.type == type)
ret = add_symbol(context, list, e->u.symbol.symbol);
break;
}
if (ret) {
_krb5_plugin_free(*list);
*list = NULL;
}
}
HEIMDAL_MUTEX_unlock(&plugin_mutex);
if (ret)
return ret;
if (*list == NULL) {
krb5_set_error_message(context, ENOENT, "Did not find a plugin for %s", name);
@@ -266,16 +311,6 @@ _krb5_plugin_find(krb5_context context,
}
return 0;
out:
if (dirs != rk_UNCONST(sysplugin_dirs))
krb5_config_free_strings(dirs);
if (d)
closedir(d);
_krb5_plugin_free(*list);
*list = NULL;
return ret;
}
void
@@ -284,8 +319,6 @@ _krb5_plugin_free(struct krb5_plugin *list)
struct krb5_plugin *next;
while (list) {
next = list->next;
if (list->dsohandle)
dlclose(list->dsohandle);
free(list);
list = next;
}