skynet源码学习 - logger服务的工作原理


当skynet启动的时候,会根据配置文件制定的日志文件来创建一个logger context,具体过程就是找到logger.so动态链接文件,而后调用其logger_create函数(参数是配置的日志文件),而后构建这个服务对应的context(重要的是里面注册了该服务的回调函数_logger())和消息队列,最后执行logger_init函数,把logger的消息队列放入global queue.关键代码如下:
<span style="white-space:pre">	</span>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();    // 这个skynet节点服务数加1

	CHECKCALLING_BEGIN(ctx)
	int r = skynet_module_instance_init(mod, inst, ctx, param);
	CHECKCALLING_END(ctx)
	if (r == 0) {
		// xxx_init 成功返回,刚才的 ref-1 = 1
		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;
	}



代码中错误处理中的skynet_error() 就是日志输出函数,会将错误字符串构造为一个skynet_mssage,放入到logger的消息队列中,msg中会保存消息的来源handle。关键代码如下:
struct skynet_message smsg;
	if (context == NULL) {
		smsg.source = 0;
	} else {
		// msg source 是ctx的handle号
		smsg.source = skynet_context_handle(context);
	}
	smsg.session = 0;
	smsg.data = data;
	// sz低24位保存的是数据大小
	smsg.sz = len | (PTYPE_TEXT << HANDLE_REMOTE_SHIFT);
	// 把这个消息放到logger的队列中
	skynet_context_push(logger, &smsg);




那些消息何时输出呢?skynet启动时会新起一定的worker线程,它们的工作就是消费这些消息,执行对应的回调函数,对于logger来说就是把信息输出到对应的文件句柄中。代码如下:
static void
_dispatch_message(struct skynet_context *ctx, struct skynet_message *msg) {
	assert(ctx->init);
	CHECKCALLING_BEGIN(ctx)
	pthread_setspecific(G_NODE.handle_key, (void *)(uintptr_t)(ctx->handle));
	int type = msg->sz >> HANDLE_REMOTE_SHIFT;
	size_t sz = msg->sz & HANDLE_MASK;
	// 执行节点的回调接口_cb
	if (!ctx->cb(ctx, ctx->cb_ud, type, msg->session, msg->source, msg->data, sz)) {
		skynet_free(msg->data);
	} 
	CHECKCALLING_END(ctx)
}







郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。