skynet module分析

module初始化

skynet中每个C服务都是一个module。源码位于skynet_module.c在启动时设置module的默认查找路径为"./cservice/?.so",创建modules实例。

skynet_main.c
int
main(int argc, char *argv[]) {
    ....
    config.module_path = optstring("cpath","./cservice/?.so");
    ....
    skynet_start(&config);
}

skynet_start.c
void 
skynet_start(struct skynet_config * config) {
    ....
    skynet_module_init(config->module_path);
    ....
}
skynet_module.c
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;
}

基本数据结构:

skynet_module.c
#define MAX_MODULE_TYPE 32
struct modules {
    int count;              //已加载动态库数量
    struct spinlock lock;
    const char * path;        //动态库查找路径
    struct skynet_module m[MAX_MODULE_TYPE];  //已加载动态库数组
};
struct skynet_module {
    const char * name;             //动态库名
    void * module;                 //动态库句柄
    skynet_dl_create create;     //动态库create函数地址
    skynet_dl_init init;         //动态库init函数地址
    skynet_dl_release release;   //动态库release函数地址
    skynet_dl_signal signal;     //动态库signal函数地址
};

跟踪logger 服务的创建流程:

void 
skynet_start(struct skynet_config * config) {
    ....
    struct skynet_context *ctx = skynet_context_new(config->logservice, config->logger);
    ....
}

struct skynet_context * 
skynet_context_new(const char * name, const char *param) {
    struct skynet_module * mod = skynet_module_query(name);
    ....
}

struct skynet_module * 
skynet_module_query(const char * name) {
    //查找是动态库是否已经加载在modules缓存中
    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;
        //加载动态库 调用dlopen
        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) {
                //获取dlsym 动态库函数地址
                M->m[index].name = skynet_strdup(name);
                M->count ++;
                result = &M->m[index];
            }
        }
    }
    SPIN_UNLOCK(M)
    return result;
}

创建logger C服务首先查找logger.so 是否已经加载在modules缓存中。已经加载直接返回logger.so的skynet_module对象。否则加载logger.so,保存create、init等函数的地址。添加到modules中。

skynet_module 返回后,再分别用缓存的logger.so中的create init函数指针,执行动态库中的create init函数。

struct skynet_context * 
skynet_context_new(const char * name, const char *param) {
    ...
    void *inst = skynet_module_instance_create(mod);
    int r = skynet_module_instance_init(mod, inst, ctx, param);
    ...
}

动态库函数的命名规则:modulename_funcname 
XXX_create:创建实例
XXX_init:初始实例,设置实例的回调函数
XXX_release:释放实例

在lua中通过skynet.launch加载C服务。

总结:module就是一个动态库,动态库中定义了用户自定义的逻辑数据结构,和数据结构的处理函数。通过dlopen加载动态库,dlsym 获取动态库中约定的函数指针。然后通过函数指针执行动态库中的create函数创建数据结构和init初始化函数。当底层向服务投递消息是,通过在init中设置的回调来进行处理。


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值