初始化工作
锁,线程,信号的处理。加载配置
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线程等等。工作线程一直不停的抓取消息并执行消息。
清理释放工作