libevent源码学习(1):日志及错误处理

本文详细介绍了libevent源码中日志及错误处理的实现,包括错误处理函数的声明和定义,如event_err,使用了__attribute__指令进行函数修饰,以及可变参数宏。日志处理部分涉及event_log日志处理入口和日志处理回调函数指针。错误处理部分介绍了event_exit错误处理入口和错误处理回调函数。文章还阐述了日志及错误处理的流程,以及如何自定义日志和错误处理回调函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

错误处理函数

函数声明

__attribute__指令

函数定义

可变参数宏

_warn_helper函数

日志处理

event_log日志处理入口

日志处理回调函数指针log_fn

设置日志处理回调函数event_set_log_callback

错误处理

event_exit错误处理入口

错误处理回调函数指针fatal_fn

设置错误处理回调函数event_set_fatal_callback

日志及错误处理流程


以下源码均基于libevent-2.0.21-stable。

        日志及错误处理,虽说不是libevent的核心,甚至说是有些“简陋”,但其也是必不可少的部分。在libevent的源码中,仔细观察可以发现,很多函数中都调用了event_warn、event_err之类的函数,而这些函数就是在日志与错误处理模块中实现的,除此之外,在libevent的日志及错误处理的实现中,还使用到了反应堆中回调函数的思想,因此,个人觉得,在分析libevent的核心部分之前,先看看比较容易的日志及错误处理这一块还是有些必要的。

错误处理函数

函数声明

        libevent的日志及错误处理模块在log.c和log-internal.h中。日志及错误处理函数声明位于log-internal.h中,主要包含以下内容:

         这些都是错误处理函数的声明,无需多说,需要注意的是,这里的函数末尾还多了一些语句,如EV_CHECK_FMT(2,3) EV_NORETURN,很明显,这些都是宏定义,那这些宏定义有什么作用呢?

__attribute__指令

        跳转到宏定义处,如下所示:

        也就是说,这里的宏定义实际上是定义的__attribute__,使用了GNU C的__attribute__机制。它实际上是对编译器进行指示,对于函数相当于是一个修饰作用。比如说这里的

#define EV_CHECK_FMT(a,b) __attribute__((format(printf, a, b)))
#define EV_NORETURN __attribute__((noreturn))

        对于event_err函数来说,参数中含有可变参数,函数由EV_CHECK_FMT(2,3)  和EV_NORETURN修饰,

        其中EV_CHECK_FMT(2,3)  对应与__attribute__((format(printf, 2, 3))),提示编译器按照printf函数格式化的形式来对event_err函数进行编译,2表示第2个参数为格式化字符串,3表示格式化的可变参数从第3个参数开始。简单来说,就是提示编译器从第3个参数开始按照第2个参数字符串的格式进行格式化;

         EV_NORETURN表示event_err函数没有返回值,也不能有返回值。

函数定义

         先来看看上述声明的处理函数的定义,位于log.c文件中,如下所示:

void
event_err(int eval, const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	_warn_helper(_EVENT_LOG_ERR, strerror(errno), fmt, ap);
	va_end(ap);
	event_exit(eval);
}

void
event_warn(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	_warn_helper(_EVENT_LOG_WARN, strerror(errno), fmt, ap);
	va_end(ap);
}

void
event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...)
{
	va_list ap;
	int err = evutil_socket_geterror(sock);   //宏定义为errno

	va_start(ap, fmt);
	_warn_helper(_EVENT_LOG_ERR, evutil_socket_error_to_string(err), fmt, ap);
	va_end(ap);
	event_exit(eval);
}

void
event_sock_warn(evutil_socket_t sock, const char *fmt, ...)
{
	va_list ap;
	int err = evutil_socket_geterror(sock);

	va_start(ap, fmt);
	_warn_helper(_EVENT_LOG_WARN, evutil_socket_error_to_string(err), fmt, ap);
	va_end(ap);
}

void
event_errx(int eval, const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	_warn_helper(_EVENT_LOG_ERR, NULL, fmt, ap);
	va_end(ap);
	event_exit(eval);
}

void
event_warnx(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	_warn_helper(_EVENT_LOG_WARN, NULL, fmt, ap);
	va_end(ap);
}

void
event_msgx(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	_warn_helper(_EVENT_LOG_MSG, NULL, fmt, ap);
	va_end(ap);
}

void
_event_debugx(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	_warn_helper(_EVENT_LOG_DEBUG, NULL, fmt, ap);
	va_end(ap);
}

         以上都是错误处理函数,可以发现,这些函数都是有共同点的:它们的参数除了一个用于格式化的字符串fmt,其他都是可变参数。而在函数体内,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值