上一节看了skynet_start() 的一部分代码,那部分代码主要做了下面几件事。
- 如果当前进程收到 SIGHUP 信号,则调用 handle_hup 函数,将 SIG 设为 1
- 检查配置文件内的 deamon 配置,这个配置对应一个文件路径,文件内的记录进程的pid号,防止重复启动skynet进程,第一次启动将自动将进程号写入文件。
- 重定向了文件描述符,把文件描述符0,1,2 重定向到了 /dev/null,相当于当前进程忽略了标准输入,标准输出,标准错误。
- 初始化了 HARBOR 的值,HARBOR的值为配置文件内 harbor 配置的值左移 24位。
- 初始化了一个 handle_storage 结构体,结构体内包含一个 harbor 成员,其中限定了 harbor 最高为 0xff, 也就是 (2^8)-1, 所以 harbor 的取值在 1-255 之间,之后再左移 24 位,和 HARBOR 保持一致。
- 初始化了一个全局消息队列,全局消息队列里的每一个元素都是一个子消息队列,其中子消息队列的元素内包含具体的消息。
- 初始化了一个 modules 结构体 M,结构体内包含一个 path 成员,保存着配置文件内的 cpath 配置,一个 skynet_module 类型的数组 m, 数组长度为 32。
- 初始化了定时器模块,暂时不细节功能实现,但是我们知道模块里定时器的时间单位是 1 / 100 秒。
- 初始化了 socket 模块,暂时不细节,不影响我们捋顺框架。
- 把配置文件的 profile 配置保存在 G_NODE 中。
以上就是 skynet_start() 前半段代码做的一些事了。
今天的内容主要梳理了一下 skynet_context_new
这个函数都做了什么。
接着 skynet_start() 的内容看:
struct skynet_context *ctx = skynet_context_new(config->logservice, config->logger);
if (ctx == NULL) {
fprintf(stderr, "Can't launch %s service\n", config->logservice);
exit(1);
}
可以看到,这段代码无非是尝试去创建一个 skynet_context 结构体。
如果创建失败了,整个进程就退出了。
下面我们看看 skynet_context_new() 函数。
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;
ATOM_INIT(&ctx->ref , 2);
ctx->cb = NULL;
ctx->cb_ud = NULL;
ctx->session_id = 0;
ATOM_INIT(&ctx->logfile, (uintptr_t)NULL);
ctx->init = false;
ctx->endless = false;
ctx->cpu_cost = 0;
ctx->cpu_start = 0;
ctx->message_count = 0;
ctx->profile = G_NODE.profile;
// 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;
}
}
好长…
不急,我们一点点看。
struct skynet_module * mod = skynet_module_query(name);