snlua_init
skynet前面啟動(dòng)流程類似logger,我們就不贅述了
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);//注冊(cè)回調(diào)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);//這里給自己發(fā)了個(gè)消息,用于觸發(fā)第一次的launch_cb
return 0;
}
然后是第一次launch_cb的時(shí)候可以看到把注冊(cè)的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);
if (err) {
skynet_command(context, "EXIT", NULL);
}
return 0;
}
那么這時(shí)候就會(huì)產(chǎn)生疑問(wèn)了,那么真相就是skynet.start的時(shí)候調(diào)用了c.callback,我們來(lái)看看 這個(gè)callback做了什么
function skynet.start(start_func)
c.callback(skynet.dispatch_message)
init_thread = skynet.timeout(0, function()
skynet.init_service(start_func)
init_thread = nil
end)
end
代碼位置在lua-skynet.c:lcallback
static int
lcallback(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
int forward = lua_toboolean(L, 2);
luaL_checktype(L,1,LUA_TFUNCTION);
lua_settop(L,1);// 設(shè)置棧頂大小為1
struct callback_context * cb_ctx = (struct callback_context *)lua_newuserdatauv(L, sizeof(*cb_ctx), 2);// 創(chuàng)建一個(gè)cb_ctx并壓棧此時(shí)棧大小為2
cb_ctx->L = lua_newthread(L); //創(chuàng)建一個(gè)協(xié)程并壓棧,此時(shí)棧大小為3
lua_pushcfunction(cb_ctx->L, traceback);//在協(xié)程中壓入一個(gè)c函數(shù)traceback 此時(shí)cb_ctx->L中的堆棧大小為1
lua_setiuservalue(L, -2, 1);//設(shè)置第一個(gè)關(guān)聯(lián)uservalue cb_ctx[1] = newthread,此時(shí)L中堆棧大小為2
lua_getfield(L, LUA_REGISTRYINDEX, "callback_context");//把lua寄存器中 "callback_context"中的值壓入堆棧,此時(shí)L中堆棧大小為3
lua_setiuservalue(L, -2, 2);//設(shè)置cb_ctx[2] = LUA_REGISTRYINDEX["callback_context"], 此時(shí)堆棧大小為2
lua_setfield(L, LUA_REGISTRYINDEX, "callback_context");//把cb_ctx存放到LUA_REGISTRYINDEX["callback_context"],此時(shí)L堆棧大小為1
lua_xmove(L, cb_ctx->L, 1);//把L中第一個(gè)數(shù)據(jù)出棧(也就是入?yún)unction),壓入cb_ctx->L中,此時(shí)L堆棧大小為為0,cb_ctx->L中堆棧大小為2
skynet_callback(context, cb_ctx, (forward)?(_forward_pre):(_cb_pre));
return 0;
}
只挑一個(gè)_cb_pre看看
這里首先獲取cb_ctx,然后把 LUA_REGISTRYINDEX["callback_context"]置空,并把_cb設(shè)置為新的cb
static int
_cb_pre(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
struct callback_context *cb_ctx = (struct callback_context *)ud;
clear_last_context(cb_ctx->L);
skynet_callback(context, ud, _cb);
return _cb(context, cb_ctx, type, session, source, msg, sz);
}
下面來(lái)看看_cb的實(shí)現(xiàn)
還記得之前的最后cb_ctx->L中的堆棧情況嗎
第一層:traceback
第二層:從lua層傳入的回調(diào)function
static int
_cb(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
struct callback_context *cb_ctx = (struct callback_context *)ud;
lua_State *L = cb_ctx->L;
int trace = 1;
int r;
lua_pushvalue(L,2);//把lua傳入function壓棧
lua_pushinteger(L, type);
lua_pushlightuserdata(L, (void *)msg);
lua_pushinteger(L,sz);
lua_pushinteger(L, session);
lua_pushinteger(L, source);//總共push了5個(gè)參數(shù)
r = lua_pcall(L, 5, 0 , trace);//執(zhí)行pcall,異常情況下調(diào)用棧第一層的traceback
if (r == LUA_OK) {
return 0;
}
const char * self = skynet_command(context, "REG", NULL);
switch (r) {
case LUA_ERRRUN:
skynet_error(context, "lua call [%x to %s : %d msgsz = %d] error : " KRED "%s" KNRM, source , self, session, sz, lua_tostring(L,-1));
break;
case LUA_ERRMEM:
skynet_error(context, "lua memory error : [%x to %s : %d]", source , self, session);
break;
case LUA_ERRERR:
skynet_error(context, "lua error in error : [%x to %s : %d]", source , self, session);
break;
};
lua_pop(L,1);
return 0;
}
skynet 相關(guān)分析完畢