evsignal_info 结构

这篇博客探讨了libevent库中evsignal_info结构的细节,包括evsignal_caught字段确保每次读取信号的最新状态,evsigevents数组用于存储每个信号的链表,以及ev_signal_pair用于信号传递的socket pair。文章提到了信号如何在event注册和激活过程中被处理,并在主循环中如何转换为就绪队列的一部分。最后,作者提醒读者回顾之前分析的信号处理位置,为后续深入分析做准备。

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

前面我们对整个event的功能做了比较全面的分析, 但是主要分析事件都是 IO或者定时事件, 却没有分析过信号又是怎么集成到就绪队列中的.

evsignal_info结构

evsignal_infoevsignal.h

typedef void (*ev_sighandler_t)(int);

struct evsignal_info {
	// 读事件使用的 event 结构
	struct event ev_signal;
	// ev_signal_pair[1] : 作为 read 放入事件到循环中监听, 当有信号时
	// 通过写入 ev_signal_pair[0], 这样就可以唤醒并回调与 ev_signal_pair[1] 关联并执行.
	// 这样的处理的好处就是不用关心中断的问题. 当同时有多个信号时这样的处理更加的高效迅速
	int ev_signal_pair[2];
	// 事件信号是否加入了 event_loop主循环中
	int ev_signal_added;
	// 表示捕捉到信号, 并且是 volatile 类型
	volatile sig_atomic_t evsignal_caught;
	// 信号队列. 这样设置成数组链表好处是可以响应相同信号
	struct event_list evsigevents[NSIG];

	// 每个信号捕捉到的次数
	sig_atomic_t evsigcaught[NSIG];

	// 保存之前的信号
#ifdef HAVE_SIGACTION
	struct sigaction **sh_old;
#else
	ev_sighandler_t **sh_old;
#endif

	// 信号类型的最大值
	int sh_old_max;
};

结构中主要三个成员参数

  • evsignal_caught : 表示有捕捉到到来的信号. volatile的特点就是每次都会从内存中读取, 而不是从缓冲区中读, 保证读取的数据都是更新过的.
  • evsigevents[NSIG] : 数组链表, 每一个链表表示一个信号, 之后排成链表就是每个信号都可以是一个信号队列
  • ev_signal_pair[2] : 两个文件描述符(socket pair). 后面我们会重点来分析.
信号在前面出现的地方

在分析event 注册和激活时, 其实evnt_add函数都是通过evsel->add(evbase, ev);将 IO, 定时或者信号都交给它来进行注册的并加入注册队列, 但是在主循环中我们并没有看到信号的是怎么加入就绪队列的, 在主循环我们只看到了信号默认交给了信号处理函数.

int event_add(struct event *ev, const struct timeval *tv)
{
  	// 该事件是处于读/写/信号并且没有处于就绪队列中
	if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
	    !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
		// 添加处理函数. 信号也是在这里被添加的, 都是统一的添加接口
		res = evsel->add(evbase, ev);
		if (res != -1)
			// 将设置的事件插入到注册链表中
			event_queue_insert(base, ev, EVLIST_INSERTED);
	}
}
int event_base_loop(struct event_base *base, int flags)
{
	// 如果设置有信号事件, 就将 base 交给专门处理信号的结构处理
    // 将信号单独作处理
	if (base->sig.ev_signal_added)
		evsignal_base = base;
	done = 0;
	while (!done) {
		/* You cannot use this interface for multi-threaded apps */
        // 这个我们不分析. 就是处理信号
		while (event_gotsig) {
			event_gotsig = 0;
			if (event_sigcb) {
				res = (*event_sigcb)();
				if (res == -1) {
					errno = EINTR;
					return (-1);
				}
			}
		}
    }
}

evsignal_baseevent_gotsig还有event_sigcb回调函数都是event.c中定义的全局变量

extern struct event_base *evsignal_base;

/* Handle signals - This is a deprecated interface */
int (*event_sigcb)(void);		/* Signal callback when gotsig is set */
volatile sig_atomic_t event_gotsig;	/* Set in signal handler */

还有event_base中也定义了信号成员哦

struct event_base {
	/* signal handling info */
	struct evsignal_info sig;	// 管理信号的成员
};

总结

本节其实就只是看了一下evsignal_info的结构并回忆了一下前面分析的时候出现过信号处理的地方, 希望下面分析你还能联想到前面对信号调用的地方.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值