初始化工作
鎖,線程,信號的處理。加載配置
skynet會開啟一個(gè)全局專門用來加載配置的lua虛擬機(jī), 虛擬機(jī)加載配置文件,將配置項(xiàng)填充到一個(gè)配置數(shù)據(jù)結(jié)構(gòu)skynet_config中,具體過程請看下篇skynet加載配置文件。-
調(diào)用skynet_start(skynet_config*)啟動日志模塊
- a) 根據(jù)skynet_config初始化模塊路徑,time,socket,harbor等。
- b) 根據(jù)日志配置啟動一個(gè)logger服務(wù),這是skynet進(jìn)程創(chuàng)建的第一個(gè)服務(wù)。
加載服務(wù)的過程是:skynet_module_query('mod_name'),先查找該模塊是否已經(jīng)存在,不存在就根據(jù)路徑和名字加載該模塊,并確定所有的函數(shù)地址,放入modules這個(gè)全局變量中,他來管理所有的模塊加載,調(diào)用事宜。
加載了模塊就需要通過skynet_module_instance_create創(chuàng)建一個(gè)模塊的實(shí)例,他會調(diào)用模塊的create函數(shù),對應(yīng)各個(gè)模塊一般就是創(chuàng)建相應(yīng)的結(jié)構(gòu)體。例如日志模塊log結(jié)構(gòu)體有文件句柄,slua模塊有l(wèi)ua虛擬機(jī)實(shí)例等。
一個(gè)服務(wù)對應(yīng)一個(gè)skynet_context,一般模塊創(chuàng)建時(shí)也會創(chuàng)建一個(gè)skynet_context,然后進(jìn)行關(guān)聯(lián)。skynet_context結(jié)構(gòu)體有模塊和其實(shí)例字段。通過skynet_handle_register為每個(gè)skynet_context生成一個(gè)全局唯一的handle。然后就是為這個(gè)skynet_context創(chuàng)建并關(guān)聯(lián)一個(gè)消息隊(duì)列。
接下來就是模塊實(shí)例進(jìn)行初始化:skynet_module_instance_init(mod, inst, ctx, param)。初始化時(shí)帶上ctx是為了給他設(shè)置回調(diào)函數(shù),以及在用skynet_command把全局handle_storage中的ctx.handler綁定一個(gè)名字。
最后就是把生成的消息隊(duì)列加入到全局隊(duì)列中,這樣消息泵才能一直從里面獲取消息。以上就是創(chuàng)建一個(gè)服務(wù)的過程,代碼如下:
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;
}
}
-
調(diào)用bootstrap啟動slua模塊
bootstrap函數(shù)中創(chuàng)建了一個(gè)新的服務(wù)--slua,過程與上面的一致,只是在初始化slua服務(wù)的時(shí)候,給他的消息隊(duì)列中發(fā)送了一條消息,參數(shù)為'bootstrap',是bootstrap函數(shù)傳入的。關(guān)于這條消息的作用,我們下篇再講。
根據(jù)配置線程數(shù)開啟一系列線程,包括工作線程,監(jiān)控線程,socket線程等等。工作線程一直不停的抓取消息并執(zhí)行消息。
清理釋放工作