Libevent信号event的处理

来源:互联网 发布:tv域名多少钱 编辑:程序博客网 时间:2024/05/16 17:45

Libevent信号event的处理

event_signal_map中数组元素的值它要么是信号值sig,要么是文件描述符fd,

而event_signal_map要求的数组长度一定要大于slot。
那么之后给定一个sig或者fd,就可以直接通过下标操作快速定位了。
这是因为一个sig或者fd就对应在数组中占有一个位置,并且sig或者fd的值等于其在数组位置的下标值。

把信号也转换成IO事件,集成到Libevent中
(1)创建一个管道(Libevent实际上使用的是socketpair)
(2)为这个socketpair的一个读端创建一个event,并将之加入到多路IO复用函数的监听之中
(3)设置信号捕抓函数
(4)有信号发生,就往socketpair写入一个字节

//event-internal.h文件  
struct event_base {  
  
    const struct eventop *evsigsel;  
    struct evsig_info sig;  
    ...  
    struct event_signal_map sigmap;  
    ...  
};  
  
//evsignal-internal.h文件  
struct evsig_info {  
    //用于监听socketpair读端的event. ev_signal_pair[1]为读端  
    struct event ev_signal;  
    //socketpair  
    evutil_socket_t ev_signal_pair[2];  
    //用来标志是否已经将ev_signal这个event加入到event_base中了  
    int ev_signal_added;  
    //用户一共要监听多少个信号  
    int ev_n_signals_added;  
  
    //数组。用户可能已经设置过某个信号的信号捕抓函数。但  
    //Libevent还是要为这个信号设置另外一个信号捕抓函数,  
    //此时,就要保存用户之前设置的信号捕抓函数。当用户不要  
    //监听这个信号时,就能够恢复用户之前的捕抓函数。  
    //因为是有多个信号,所以得用一个数组保存。  
#ifdef _EVENT_HAVE_SIGACTION  
    struct sigaction **sh_old;   
#else//保存的是捕抓函数的函数指针,又因为是数组。所以是二级指针  
    ev_sighandler_t **sh_old;   
#endif  
    /* Size of sh_old. */  
    int sh_old_max; //数组的长度  
};  

初始化:
Libevent在初始化时会选择一个多路I/O复用函数
base->evbase = base->evsel->init(base);
以poll的init函数为例
poll_init()->evsig_init();
evsig_init函数完成了创建socketpair,设置各种属性,并将socketpair的一个读端与ev_signal相关联。
event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[1],EV_READ | EV_PERSIST, evsig_cb, base);

将信号event加入到event_base
event_add()->event_add_internal()->evmap_signal_add(){evsel->add实质是evsig_add}
evsig_add()->_evsig_set_handler(){sigaction或signal}设置evsig_handler

假如要对一个绑定了某个信号的event调用event_add函数,那么在event_add的内部会调用event_add_internal函数。
而event_add_internal函数又会调用evmap_signal_add函数
在evmap_signal_add函数中调用(evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL),实质调用evsig_add函数
evsig_add函数设置信号捕抓函数_evsig_set_handler(base, (int)evsignal, evsig_handler),evsig_handler抓捕信号
若用户第一次监听一个信号。要ev_signal这个event添加到event_base中。
{
只需一个event即可完成工作,即使用户要监听多个不同的信号,因为这个event已经和socketpair的读端相关联了。
如果要监听多个信号,那么就在信号处理函数中往这个socketpair写入不同的值即可。
event_base能监听到可读,并可以从读到的内容可以判断是哪个信号发生了。
从代码中也可得知,Libevent并不会为每一个信号监听创建一个event。
它只会创建一个全局的专门用于监听信号的event。这个也是“统一事件源”的工作原理。
}
在_evsig_set_handler函数中使用sigaction和signal设置信号处理函数
信号处理函数evsig_handler,抓捕到信号后,调用函数evsig_handler,向socketpair写端写入一个与信号相关的字节

我们在event_assign中设置了回调函数evsig_cb,用来处理信号对socketpair的I/O事件
evsig_cb这个回调函数并不是用户为监听一个信号调用event_new时设置的用户回调函数,而是Libevent内部为了处理信号而设置的内部回调函数
回调函数的作用是读取socketpair的所有数据,并将数据当作信号,再根据信号值调用evmap_signal_active。
evmap_signal_active()->event_active_nolock()->event_queue_insert(,,EVLIST_ACTIVE);
最后从激活的队列中取出元素进行处理:event_process_active()->event_process_active_single_queue()
0 0
原创粉丝点击