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. 清理釋放工作

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容