skynet主体流程

  1. 初始化工作
    锁,线程,信号的处理。

  2. 加载配置
    skynet会开启一个全局专门用来加载配置的lua虚拟机, 虚拟机加载配置文件,将配置项填充到一个配置数据结构skynet_config中,具体过程请看下篇skynet加载配置文件。

  3. 调用skynet_start(skynet_config*)启动日志模块

    • a) 根据skynet_config初始化模块路径,time,socket,harbor等。
    • b) 根据日志配置启动一个logger服务,这是skynet进程创建的第一个服务。

    加载服务的过程是:skynet_module_query('mod_name'),先查找该模块是否已经存在,不存在就根据路径和名字加载该模块,并确定所有的函数地址,放入modules这个全局变量中,他来管理所有的模块加载,调用事宜。

    加载了模块就需要通过skynet_module_instance_create创建一个模块的实例,他会调用模块的create函数,对应各个模块一般就是创建相应的结构体。例如日志模块log结构体有文件句柄,slua模块有lua虚拟机实例等。

    一个服务对应一个skynet_context,一般模块创建时也会创建一个skynet_context,然后进行关联。skynet_context结构体有模块和其实例字段。通过skynet_handle_register为每个skynet_context生成一个全局唯一的handle。然后就是为这个skynet_context创建并关联一个消息队列。

    接下来就是模块实例进行初始化:skynet_module_instance_init(mod, inst, ctx, param)。初始化时带上ctx是为了给他设置回调函数,以及在用skynet_command把全局handle_storage中的ctx.handler绑定一个名字。

    最后就是把生成的消息队列加入到全局队列中,这样消息泵才能一直从里面获取消息。以上就是创建一个服务的过程,代码如下:

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

    if (mod == NULL)
        return NULL;

    void *inst = skynet_module_instance_create(mod);
    if (inst == NULL)
        return NULL;
    struct skynet_context * ctx = skynet_malloc(sizeof(*ctx));
    CHECKCALLING_INIT(ctx)

    ctx->mod = mod;
    ctx->instance = inst;
    ctx->ref = 2;
    ctx->cb = NULL;
    ctx->cb_ud = NULL;
    ctx->session_id = 0;
    ctx->logfile = NULL;

    ctx->init = false;
    ctx->endless = false;
    // Should set to 0 first to avoid skynet_handle_retireall get an uninitialized handle
    ctx->handle = 0;    
    ctx->handle = skynet_handle_register(ctx);
    struct message_queue * queue = ctx->queue = skynet_mq_create(ctx->handle);
    // init function maybe use ctx->handle, so it must init at last
    context_inc();

    CHECKCALLING_BEGIN(ctx)
    int r = skynet_module_instance_init(mod, inst, ctx, param);
    CHECKCALLING_END(ctx)
    if (r == 0) {
        struct skynet_context * ret = skynet_context_release(ctx);
        if (ret) {
            ctx->init = true;
        }
        skynet_globalmq_push(queue);
        if (ret) {
            skynet_error(ret, "LAUNCH %s %s", name, param ? param : "");
        }
        return ret;
    } else {
        skynet_error(ctx, "FAILED launch %s", name);
        uint32_t handle = ctx->handle;
        skynet_context_release(ctx);
        skynet_handle_retire(handle);
        struct drop_t d = { handle };
        skynet_mq_release(queue, drop_message, &d);
        return NULL;
    }
}
  1. 调用bootstrap启动slua模块

    bootstrap函数中创建了一个新的服务--slua,过程与上面的一致,只是在初始化slua服务的时候,给他的消息队列中发送了一条消息,参数为'bootstrap',是bootstrap函数传入的。关于这条消息的作用,我们下篇再讲。

  2. 根据配置线程数开启一系列线程,包括工作线程,监控线程,socket线程等等。工作线程一直不停的抓取消息并执行消息。

  3. 清理释放工作

你可能感兴趣的:(skynet主体流程)