初始化工作
鎖,線程,信號的處理。加載配置
skynet會開啟一個全局專門用來加載配置的lua虛擬機, 虛擬機加載配置文件,將配置項填充到一個配置數據結構skynet_config中,具體過程請看下篇skynet加載配置文件。-
調用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;
}
}
-
調用bootstrap啟動slua模塊
bootstrap函數中創建了一個新的服務--slua,過程與上面的一致,只是在初始化slua服務的時候,給他的消息隊列中發送了一條消息,參數為'bootstrap',是bootstrap函數傳入的。關于這條消息的作用,我們下篇再講。
根據配置線程數開啟一系列線程,包括工作線程,監控線程,socket線程等等。工作線程一直不停的抓取消息并執行消息。
清理釋放工作