You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libsxmp/ydaemon/module.c

242 lines
5.6 KiB
C

/*
* Yet another daemon library especially designed to be used
* with libsxmp based daemons.
*
* (c) Alexander Vdolainen 2016 <avdolainen@zoho.com>
*
* libsxmp is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libsxmp 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <ctype.h>
#include <dlfcn.h>
#include <tdata/usrtc.h>
#include <sexpr/sexp.h>
#include <ydaemon/ydaemon.h>
int yd_mod_add(yd_context_t *ctx, const char *name, yd_mod_type_t type)
{
yd_mod_t *mod = malloc(sizeof(yd_mod_t));
usrtc_node_t *node = NULL;
int r = 0;
if(!mod) return ENOMEM;
else if(!(mod->name = strdup(name))) {
free(mod);
return ENOMEM;
}
mod->type = type;
usrtc_node_init(&mod->node, mod);
yd_mod_ctx_wrlock(ctx);
node = usrtc_lookup(ctx->modules, mod->name);
if(node) r = EEXIST;
else usrtc_insert(ctx->modules, &mod->node, mod->name);
yd_mod_ctx_unlock(ctx);
return r;
}
int yd_mod_load(yd_context_t *ctx, yd_mod_t *mod)
{
char buf[256];
int r = 0;
/* let's try to find it and load */
if(!mod->pathname || !mod->name) return EINVAL;
if(!(mod->dlhandle = dlopen(mod->pathname, RTLD_LAZY|RTLD_GLOBAL)))
return ENOENT;
/* ok now we can resolve all symbols */
snprintf(buf, 256, "%s_preinit", mod->prefix);
mod->preinit = dlsym(mod->dlhandle, buf);
if(!mod->preinit) {
__einval:
dlclose(mod->dlhandle);
return EINVAL;
}
snprintf(buf, 256, "%s_init", mod->prefix);
if(!(mod->init = dlsym(mod->dlhandle, buf))) goto __einval;
snprintf(buf, 256, "%s_run", mod->prefix);
if(!(mod->run = dlsym(mod->dlhandle, buf))) goto __einval;
snprintf(buf, 256, "%s_shutdown", mod->prefix);
if(!(mod->shutdown = dlsym(mod->dlhandle, buf))) goto __einval;
snprintf(buf, 256, "%s_getobject", mod->prefix);
if(!(mod->getobject = dlsym(mod->dlhandle, buf))) goto __einval;
if((r = mod->preinit(ctx))) {
blub;
__fail:
dlclose(mod->dlhandle);
return r;
}
if(mod->cnfname) {
blub;
r = yd_eval_ctx(ctx, (const char *)mod->cnfname);
if(r) goto __fail;
}
if((r = mod->init(ctx))) goto __fail;
if(mod->type == YD_SERVICE_MUX) {
if((r = mod->run(ctx))) goto __fail;
}
return 0;
}
int yd_mod_get(yd_context_t *ctx, const char *name, yd_mod_t **rmod)
{
int r = 0;
usrtc_node_t *node;
yd_mod_ctx_rdlock(ctx);
node = usrtc_lookup(ctx->modules, name);
if(!node) r = ENOENT;
else *rmod = (yd_mod_t *)usrtc_node_getdata(node);
yd_mod_ctx_unlock(ctx);
return r;
}
int yd_mod_run(yd_context_t *ctx, yd_mod_t *mod)
{
return mod->run(ctx);
}
int yd_mod_shutdown(yd_context_t *ctx, yd_mod_t *mod)
{
return mod->shutdown(ctx);
}
void *yd_mod_getobject(yd_context_t *ctx, yd_mod_t *mod,
void *priv, const char *name)
{
return mod->getobject(priv, name);
}
void *yd_mod_getsym(yd_context_t *ctx, yd_mod_t *mod, const char *name)
{
return dlsym(mod->dlhandle, name);
}
/* object store */
static long __cmp_cstr(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
#define __obs_wrlock(s) pthread_rwlock_wrlock(&((s)->rwlock))
#define __obs_rdlock(s) pthread_rwlock_rdlock(&((s)->rwlock))
#define __obs_unlock(s) pthread_rwlock_unlock(&((s)->rwlock))
#define __obs_tree(s) &((s)->objects)
int obj_store_init(obj_store_t *st)
{
usrtc_t *tree = &st->objects;
if(pthread_rwlock_init(&(st->rwlock), NULL)) return ENOMEM;
else usrtc_init(tree, USRTC_SPLAY, MAX_OBJECTS, __cmp_cstr);
return 0;
}
int obj_store_set(obj_store_t *st, const char *nm, void *od)
{
usrtc_node_t *node = NULL;
obj_store_node_t *onode = NULL;
__obs_rdlock(st);
node = usrtc_lookup(__obs_tree(st), nm);
__obs_unlock(st);
if(!node) {
if(!(onode = malloc(sizeof(obj_store_node_t)))) return ENOMEM;
else memset(onode, 0, sizeof(obj_store_node_t));
if(!(onode->name = strdup(nm))) {
free(onode);
return ENOMEM;
}
onode->objdata = od;
node = &(onode->node);
usrtc_node_init(node, onode);
__obs_wrlock(st);
usrtc_insert(__obs_tree(st), node, (const void *)onode->name);
__obs_unlock(st);
} else {
onode = (obj_store_node_t *)usrtc_node_getdata(node);
__obs_wrlock(st);
onode->objdata = od;
__obs_unlock(st);
}
return 0;
}
int obj_store_get(obj_store_t *st, const char *nm, void **rod)
{
usrtc_node_t *node = NULL;
obj_store_node_t *onode = NULL;
__obs_rdlock(st);
node = usrtc_lookup(__obs_tree(st), nm);
__obs_unlock(st);
if(!node) return ENOENT;
else onode = (obj_store_node_t *)usrtc_node_getdata(node);
*rod = onode->objdata;
return 0;
}
int obj_store_remove(obj_store_t *st, const char *nm)
{
usrtc_node_t *node = NULL;
obj_store_node_t *onode = NULL;
__obs_rdlock(st);
node = usrtc_lookup(__obs_tree(st), nm);
__obs_unlock(st);
if(!node) return ENOENT;
else {
__obs_wrlock(st);
usrtc_delete(__obs_tree(st), node);
__obs_unlock(st);
onode = (obj_store_node_t *)usrtc_node_getdata(node);
if(onode->name) free(onode->name);
free(onode);
}
return 0;
}