【Skynet】開始創建服務的代碼流程

【Skynet】開始創建服務的流程

參考大神鏈接:
GitHub wiki LuaAPI
Githu wiki APIList
skynet 創建 lua 服務流程
探索skynet(二):skynet如何啓動一個服務

一、skynet 中 main 的 start()

->main.lua

skynet.start(function()
    ...newservice()
...end)

–> [ skynet_start.c ]

void 
skynet_start(struct skynet_config * config) {
    ....
    bootstrap(ctx, config->bootstrap);  // 啓動bootstrap服務
    ...
}

​ 一般默認,config->bootstrap項就是snlua bootstrap

二、newservice() 創建一個服務

–> [ skynet.lua ] – .launcher 一個服務

function skynet.newservice(name, ...)
	return skynet.call(".launcher", "lua" , "LAUNCH", "snlua", name, ...)
end

–> [ bootstrap.lua入口函數 ]

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

–> [ manager.lua ]

local c = require "skynet.core"
function skynet.launch(...)
	local addr = c.command("LAUNCH", table.concat({...}," "))
 .....

–> [ lua_skynet.c ]

lcommand(lua_State *L) {
    .....
    result = skynet_command(context, cmd, parm); 
    //  cmd應該是LAUNCH , parm應該是 snlua launcher
}

–> [ skynet_server.c ]

(1)skynet_command -》cmd_launch

static struct command_func cmd_funcs[] = {
	{ "LAUNCH", cmd_launch },
	...
	{ NULL, NULL },
};

const char * 
skynet_command(struct skynet_context * context, const char * cmd , const char * param) {
	struct command_func * method = &cmd_funcs[0];
	while(method->name) {
		if (strcmp(cmd, method->name) == 0) {
			return method->func(context, param);
		}
		++method;
	}
	return NULL;
}

(2)進入 cmd_launch

static const char *
cmd_launch(struct skynet_context * context, const char * param) {
	size_t sz = strlen(param);
	char tmp[sz+1];
	strcpy(tmp,param);
	char * args = tmp;
	char * mod = strsep(&args, " \t\r\n");
	args = strsep(&args, "\r\n");
	struct skynet_context * inst = skynet_context_new(mod,args);
	if (inst == NULL) {
		return NULL;
	} else {
		id_to_hex(context->result, inst->handle);
		return context->result;
	}
}

(3)skynet_context_new (mod,args);

​ mod是snlua,args是“snlua launcher”,根據這個參數構造一個skynet_context 出來

struct skynet_context * 
skynet_context_new(const char * name, const char *param) {
    struct skynet_module * mod = skynet_module_query(name); //① 獲得snlua模塊
    ..... // 創建消息隊列等等
    void *inst = skynet_module_instance_create(mod); // ② 創建服務
    ....
    int r = skynet_module_instance_init(mod, inst, ctx, param); // ③ 初始化snlua
    ...
}

–> service.snlua.c

​ 先看一下結構

struct snlua {
    lua_State * L;
    struct skynet_context * ctx;
    size_t mem;
    size_t mem_report;
    size_t mem_limit;
};

​ 語句①:獲得snlua模塊創建實例 snlua_create

struct snlua *
snlua_create(void) {
    struct snlua * l = skynet_malloc(sizeof(*l));
    memset(l,0,sizeof(*l));
    l->mem_report = MEMORY_WARNING_REPORT;
    l->mem_limit = 0;
    l->L = lua_newstate(lalloc, l);
    return l;
}

​ 語句③:初始化snlua 其實就是 snlua_init

int
snlua_init(struct snlua *l, struct skynet_context *ctx, const char * args) {
    int sz = strlen(args);
    char * tmp = skynet_malloc(sz);
    memcpy(tmp, args, sz);
    skynet_callback(ctx, l , launch_cb); //回調
    const char * self = skynet_command(ctx, "REG", NULL);
    uint32_t handle_id = strtoul(self+1, NULL, 16);
    // it must be first message
    skynet_send(ctx, 0, handle_id, PTYPE_TAG_DONTCOPY,0, tmp, sz);
    return 0;
}

​ 設置了當前模塊的callback爲 launch_cb,之後skynet_send消息,將由launch_cb處理

static int
launch_cb(struct skynet_context * context, void *ud, int type, int session, uint32_t source , const void * msg, size_t sz) {
    assert(type == 0 && session == 0);
    struct snlua *l = ud;
    skynet_callback(context, NULL, NULL);
    int err = init_cb(l, context, msg, sz); //回調給lua層
    if (err) {
        skynet_command(context, "EXIT", NULL);
    }

    return 0;
}

​ launch_cb重置了服務的回調callback ,調用init_cb

static int
init_cb(struct snlua *l, struct skynet_context *ctx, const char * args, size_t sz) {
    .... // 設置各種路徑、棧數據
    const char * loader = optstring(ctx, "lualoader", "./lualib/loader.lua");
    int r = luaL_loadfile(L,loader);
    if (r != LUA_OK) {
        skynet_error(ctx, "Can't load %s : %s", loader, lua_tostring(L, -1));
        report_launcher_error(ctx);
        return 1;
    }
    lua_pushlstring(L, args, sz);
    r = lua_pcall(L,1,0,1); // 回調給lua層
    ....
}

–> skynet.lua

function skynet.start(start_func)
    c.callback(skynet.dispatch_message) //回調信息返回在這
    skynet.timeout(0, function()
        skynet.init_service(start_func)
    end)
end

​ 即 啓動了這個服務,即,這個服務掛載到消息隊列(skynet_context的mq)裏面 等待 消息的處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章