#ifndef SKYNET_MODULE_H
#define SKYNET_MODULE_H
struct skynet_context;
typedef void * (*skynet_dl_create)(void);
typedef int (*skynet_dl_init)(void * inst, struct skynet_context *, const char * parm);
typedef void (*skynet_dl_release)(void * inst);
typedef void (*skynet_dl_signal)(void * inst, int signal);
//云风模块结构
struct skynet_module {
//当前模块名字
const char * name;
void * module;
//当前模块创建函数
skynet_dl_create create;
//当前模块初始化函数
skynet_dl_init init;
//当前模块释放函数
skynet_dl_release release;
//当前模块信号函数
skynet_dl_signal signal;
};
void skynet_module_insert(struct skynet_module *mod);
struct skynet_module * skynet_module_query(const char * name);
void * skynet_module_instance_create(struct skynet_module *);
int skynet_module_instance_init(struct skynet_module *, void * inst, struct skynet_context *ctx, const char * parm);
void skynet_module_instance_release(struct skynet_module *, void *inst);
void skynet_module_instance_signal(struct skynet_module *, void *inst, int signal);
void skynet_module_init(const char *path);
#endif
#include "skynet.h"
#include "skynet_module.h"
#include "spinlock.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;
struct spinlock lock;
const char * path; //模块路径
struct skynet_module m[MAX_MODULE_TYPE]; //skynet模块数组
};
//申请一个全局模块管理器,并置为空
static struct modules * M = NULL;
//尝试打开模块管理器下的动态链接库
static void *
_try_open(struct modules *m, const char * name) {
const char *l;
const char * path = m->path;
//获取模块地址长度
size_t path_size = strlen(path);
//获取尝试打开文件的长度
size_t name_size = strlen(name);
int sz = path_size + name_size;
//search path
void * dl = NULL;
char tmp[sz];
do
{
memset(tmp,0,sz);
while (*path == ';') path++;//当遇到分号就继续前进
if (*path == '\0') break; //遇到字符串末尾跳出
l = strchr(path, ';'); //查找当前路径第一个;号的位置
if (l == NULL) l = path + strlen(path); //当没有分号时(即只有一个地址),l设为path字符串末尾指针
int len = l - path; //len为当前路径的长度
int i;
for (i=0;path[i]!='?' && i < len ;i++) { //拷贝当前字符串到tmp内,知道遇到?或者到字符串尾
tmp[i] = path[i];
}
memcpy(tmp+i,name,name_size); //如果遇到问号或尾部,则拷贝传入的字符串name到path位置
//既为tmp = path/name路径
if (path[i] == '?') { //
strncpy(tmp+i+name_size,path+i+1,len - i - 1); //然后将?后面的字符串拷贝到tmp后面
} else {
fprintf(stderr,"Invalid C service path\n");
exit(1);
}
dl = dlopen(tmp, RTLD_NOW | RTLD_GLOBAL); //打开动态链接库,
path = l; //若有下个分号,则将path的起始位置置为下个分号的指针
}while(dl == NULL);
if (dl == NULL) {
fprintf(stderr, "try open %s failed : %s\n",name,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 void *
get_api(struct skynet_module *mod, const char *api_name) {
//获取模块名字长度
size_t name_size = strlen(mod->name);
//获取api_name长度
size_t api_size = strlen(api_name);
//建立一个临时的字符串,长度为模块名字长度+api_name长度
char tmp[name_size + api_size + 1];
//将模块名字和api_name联系放入该字符串内
memcpy(tmp, mod->name, name_size);
memcpy(tmp+name_size, api_name, api_size+1);
char *ptr = strrchr(tmp, '.');//查找tmp字符串中有没有'.',如果没有就整个拷贝tmp,如果有,就拷贝.后面的字符串
if (ptr == NULL) {
ptr = tmp;
} else {
ptr = ptr + 1;
}
return dlsym(mod->module, ptr);//根据模块句柄和关键字,返回函数指针
}
//获取到模块相应功能的函数指针拷贝到模块的函数指针上,失败返回1,成功返回0
static int
open_sym(struct skynet_module *mod) {
mod->create = get_api(mod, "_create");
mod->init = get_api(mod, "_init");
mod->release = get_api(mod, "_release");
mod->signal = get_api(mod, "_signal");
return mod->init == NULL;
}
//查询模块是否加载,如果未加载则直接加载
struct skynet_module *
skynet_module_query(const char * name) {
//查询相应模块是否已经载入,如果已载入则直接返回
struct skynet_module * result = _query(name);
if (result)
return result;
SPIN_LOCK(M)
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) {
//当打开指定单元成功,深拷贝名字到name上,和传入的名字
M->m[index].name = skynet_strdup(name);
//增加模块管理器计数
M->count ++;
//将返回值置为打开单元的地址
result = &M->m[index];
}
}
}
SPIN_UNLOCK(M)
return result;
}
//插入一个模块
void
skynet_module_insert(struct skynet_module *mod) {
SPIN_LOCK(M)
//查询模块是否已经加入
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;
SPIN_UNLOCK(M)
}
//创建模块实例
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_instance_signal(struct skynet_module *m, void *inst, int signal) {
if (m->signal) {
m->signal(inst, signal);
}
}
//模块管理器初始化
void
skynet_module_init(const char *path) {
struct modules *m = skynet_malloc(sizeof(*m));
m->count = 0;
m->path = skynet_strdup(path);
SPIN_INIT(m)
M = m;
}