Files
skynet/skynet-src/skynet_module.c
2012-08-09 15:36:56 +08:00

148 lines
3.0 KiB
C

#include "skynet_module.h"
#include <assert.h>
#include <string.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#define MAX_MODULE_TYPE 32
struct modules {
int count;
int lock;
const char * path;
struct skynet_module m[MAX_MODULE_TYPE];
};
static struct modules * M = NULL;
static void *
_try_open(struct modules *m, const char * name) {
const char * path = m->path;
size_t path_size = strlen(path);
size_t name_size = strlen(name);
int sz = path_size + name_size;
char tmp[sz];
int i;
for (i=0;path[i]!='?' && path[i]!='\0';i++) {
tmp[i] = path[i];
}
memcpy(tmp+i,name,name_size);
if (path[i] == '?') {
strcpy(tmp+i+name_size,path+i+1);
} else {
fprintf(stderr,"Invalid C service path\n");
exit(1);
}
void * dl = dlopen(tmp, RTLD_NOW | RTLD_GLOBAL);
if (dl == NULL) {
fprintf(stderr, "try open %s failed : %s\n",tmp,dlerror());
}
return dl;
}
static struct skynet_module *
_query(const char * name) {
int i;
for (i=0;i<M->count;i++) {
if (strcmp(M->m[i].name,name)==0) {
return &M->m[i];
}
}
return NULL;
}
static int
_open_sym(struct skynet_module *mod) {
size_t name_size = strlen(mod->name);
char tmp[name_size + 9]; // create/init/release , longest name is release (7)
memcpy(tmp, mod->name, name_size);
strcpy(tmp+name_size, "_create");
mod->create = dlsym(mod->module, tmp);
strcpy(tmp+name_size, "_init");
mod->init = dlsym(mod->module, tmp);
strcpy(tmp+name_size, "_release");
mod->release = dlsym(mod->module, tmp);
return mod->init == NULL;
}
struct skynet_module *
skynet_module_query(const char * name) {
struct skynet_module * result = _query(name);
if (result)
return result;
while(__sync_lock_test_and_set(&M->lock,1)) {}
result = _query(name); // double check
if (result == NULL && M->count < MAX_MODULE_TYPE) {
int index = M->count;
void * dl = _try_open(M,name);
if (dl) {
M->m[index].name = name;
M->m[index].module = dl;
if (_open_sym(&M->m[index]) == 0) {
M->m[index].name = strdup(name);
M->count ++;
result = &M->m[index];
}
}
}
__sync_lock_release(&M->lock);
return result;
}
void
skynet_module_insert(struct skynet_module *mod) {
while(__sync_lock_test_and_set(&M->lock,1)) {}
struct skynet_module * m = _query(mod->name);
assert(m == NULL && M->count < MAX_MODULE_TYPE);
int index = M->count;
M->m[index] = *mod;
++M->count;
__sync_lock_release(&M->lock);
}
void *
skynet_module_instance_create(struct skynet_module *m) {
if (m->create) {
return m->create();
} else {
return (void *)(intptr_t)(~0);
}
}
int
skynet_module_instance_init(struct skynet_module *m, void * inst, struct skynet_context *ctx, const char * parm) {
return m->init(inst, ctx, parm);
}
void
skynet_module_instance_release(struct skynet_module *m, void *inst) {
if (m->release) {
m->release(inst);
}
}
void
skynet_module_init(const char *path) {
struct modules *m = malloc(sizeof(*m));
m->count = 0;
m->path = strdup(path);
m->lock = 0;
M = m;
}