skynet1.0閱讀筆記_skynet的啓動

 

 


首先看skynet的啓動,函數入口在 skynet_main.c 的main(),其中最重要的是:bootstrap

        skynet_start(&config);

在skynet_start中作了兩個啓動:socket

        //啓動了snlau服務,而後加載launch服務
        bootstrap(ctx, config->bootstrap);
        //建立monitor,timer,socket,worker線程等
        start(config->thread);


下面咱們逐步跟進函數函數

    static void
    bootstrap(struct skynet_context * logger, const char * cmdline) {
        ...
        sscanf(cmdline, "%s %s", name, args);
        struct skynet_context *ctx = skynet_context_new(name, args);
        ...
    }

這裏的cmdline就是 config配置裏面的bootstrap那行,默認是爲 "snlua bootstrap"ui


因此實際執行的是 skynet_context_new("snlua","bootstrap")
這裏的skynet_context_new是很重要的一個函數,skynet每一個lua服務建立,都是使用它來執行的。lua

    skynet_context_new(const char * name="snlua", const char *param="bootstrap") {
        //查詢mod對象是否已存在,不存在就根據name查找文件加載建立
        struct skynet_module * mod = skynet_module_query(name="snlua");
        ...
        //調用mod的create()方法,這裏調用了 snlua_create
        void *inst = skynet_module_instance_create(mod);
        //爲lua服務new一個skynet_context的c對象
        struct skynet_context * ctx = skynet_malloc(sizeof(*ctx));
        ...
        //爲服務的ctx建立一個message_queue
        struct message_queue * queue = ctx->queue = skynet_mq_create(ctx->handle);
        //調用對象的init方法,這裏是 snlua_init(snlua_create(),ctx,"bootstrap")
        int r = skynet_module_instance_init(mod, inst, ctx, param);
        if(r==0){        //0表示成功
            //成功之後,把服務的message_queue放入global_queue全局隊列中
            skynet_globalmq_push(queue);
        }
    }

就是說,bootstrap的啓動請求 如今交到service_snlua.c的snlua_init裏面了,因此接着咱們來看snlua_init的實現spa

    snlua_init(struct snlua *l,struct skynet_context *ctx,args="bootstrap"){
        ...
        //把ctx->cb=_launch, ctx->cb是worker線程取出skynet_message時的處理函數
        skynet_callback(ctx, l , _launch);
        //查詢本身的handle id
        const char * self = skynet_command(ctx, "REG", NULL);
        uint32_t handle_id = strtoul(self+1, NULL, 16);
        ...
        memcpy(tmp, args, sz);
        // it must be first message ,而後在這裏當即投遞第一個請求
        skynet_send(ctx, ... , tmp="bootstrap", sz);
        ...
    }

 

這裏須要注意的是,skynet_command這裏,實際上經過遍歷查找,最終調用了cmd_reg,因爲傳入的param是NULL,實際是線程

     skynet_command(ctx, "REG", NULL){
        sprintf(context->result, ":%x", context->handle);
        return context->result;
     }

//返回的是本身的ctx的handle id.code

也就是下面的skynet_send:對象

        skynet_send(ctx, ... , tmp="bootstrap", sz);

是往本身的隊列中投遞了一個消息,worker線程拿到這個消息後,根據ctx->cb,調用callback函數: _launchblog

跟進 _launch:

    _launch(..., const void* msg="bootstrap"){
        //把context->cb設爲NULL了
        skynet_callback(context, NULL, NULL);
        //_init這裏面實際上就是找到要加載的lua文件,而後加載到lua虛擬機中
        //在這裏就是把 bootstrap.lua文件加在進來
        _init(l, context, msg, sz);
        ...
    }

那咱們來看看 bootstrap.lua 這個文件

local skynet = require "skynet"
local harbor = require "skynet.harbor"
require "skynet.manager"    -- import skynet.launch, ...
local memory = require "memory"

skynet.start(function()
        ...
        -- 這裏面,使用skynet.newservice 啓動了不少個服務

    local launcher = assert(skynet.launch("snlua","launcher"))
    skynet.name(".launcher", launcher)

        ...

    if harbor_id == 0 then
        local ok, slave = pcall(skynet.newservice, "cdummy")
        skynet.name(".cslave", slave)
    else
        local ok, slave = pcall(skynet.newservice, "cslave")
        skynet.name(".cslave", slave)
    end
        ...

    if standalone then
        local datacenter = skynet.newservice "datacenterd"
        skynet.name("DATACENTER", datacenter)
    end
        ...
end)

這裏有兩點要注意:
1. skynet.start 的function裏面,用snlua啓動了launcher服務,並用skynet.name把本身註冊名字爲".launcher"的服務
".launcher" 的調用 skynet.call(".launcher",...)
在後面將常常看到。".launcher"服務就是在這裏註冊的。
以.開頭的名字,是表示這個服務只在當前skynet節點下有效,若是不帶點,須要支持跨節點的額外開銷,不必都會帶上它。

2.skynet.start 函數

    function skynet.start(start_func)
        //把回調函數註冊爲 skynet.dispatch_message
        c.callback(skynet.dispatch_message)
        //調用 skynet.init_service 調用了外面定義的 function 進行啓動
        skynet.timeout(0, function()
            skynet.init_service(start_func)
        end)
    end

到這裏,就能明白,經過skynet_context_new 中的 snlua_init 和_launch,skynet把請求的處理權從 c交到了 lua手上。

相關文章
相關標籤/搜索