libevent之signal

来源:互联网 发布:带着淘宝混异世文汇吧 编辑:程序博客网 时间:2024/05/29 03:00

在了解libevent实现如何实现侦听signal事件以及调用其回调函数前,需要明确如何创建一个signal事件:

(一)signal事件创建方法:

(1)struct event *   event_new(struct event_base * base, evutil_socket_t  fd, short event, event_callback_fn callback, void *callback_args);

可以通过调用上面的函数创建一个新的event,新的event可以通过event_add()或者event_del()加入侦听队列中或删除,下面是这个函数参数介绍

           1、base    这个时间将要关联的event_base,每一个event同一时刻只能关联一个event_base

           2、fd 如果监听一个套接口或文件描述符,这fd表示一个socket或者文件描述符字,如果是一个signal,则fd表示此signal的信号值,fd为-1,那

                 么此时间可以表示超时事件,在加入监听队列后,当且仅当超时或者调用event_active()才能进入激活队列,等待调用其注册的回调函数

           3、event  表示希望监听发生事件的类型,事件类型包括:EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT, EV_PERSIST , EV_ET,意义如

                 如同其名字,其中EV_ET(edge_trigger)需要多路复用机制支持,当指定EV_PERSIST时,在事件发生后,并不将事件从侦听队列移除而是继续

                 侦听(对于指定了timeout的事件,在事件发生后timeout被重置为0?????)

           4、callback 为此事件注册的回调函数,在事件发生并加入激活队列后将被调用,注意回调函数的声明方式:

                 typedef void (*event_callback_fn)(evutil_socket_t, short, void *); 回调函数中接受三个参数,第一个对应fd,第二个对应event,第三个对应

event_new 的最后一个参数callback_args

            5、callback_args   提供给回调函数的参数

(2)还可一通过  evsignal_new(b, x, cb, arg),这是一个宏定义,实际上也是调用event_new(),其原型如下:

          #define evsignal_new(b, x, cb, arg)        event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))  

  销毁一个通过event_new创建的event:

             void event_free(struct event *),调用此函数时,如果传递的参数event已经在侦听队列,激活队列的,则先从队列中删除,在释放其空间


  创建好一个新的event后,就可以将其加入监听队列,等待事件发生,并被调度,方法如下:

        int event_add(struct event *ev, const struct timeval *timeout);

      参数event就是加入的event,参数timeout可以为空,表示只有在希望发生的事件发生是才会被激活,如果参数timeout不为空,且先前已经设置过

      timeout,先前的timeout被替代为新的timeout


(二)signal事件在libevent处理方式

         signal事件要想同统一到libevent事件机制中去,并不是一件很自然的就能完成的事,不想timer事件那样可以直接利用现有的io复用机制就能轻松完成(例如:select和epoll中 设置timeout),signal是典型的异步事件,当signal发生时需要调用为其注册的回调函数,但是libevent中用来实现io复用的方式(select,kqueue,epoll等,windows不了解),不能直接侦听信号的发生。libevent采用另一种方式:当信号发生时,并不立即调用为其注册的回调函数,而是通知系统的IO机制,然后和IO时间以及timer事件一起处理。

          signal事件集成具体实现:

          (1)socket pair

               前面曾经提到signal发生时,想法通知系统的IO机制,做法就是通过socketpair实现,socketpair分为读端以及写端(事实上两端可同时读写,但在系统中用不着

               同时读写),系统通过为读端注册一个EV_PERSIST|EV_READ的事件来侦听读端,当信号来临时,向socketpair写端写如数据,则系统就知道有信号来临,接着

              会根据信号的类型调用其注册的回调函数,具体细节会在后面讲到。

        (2)(1)中说道信号发生时想socketpair写端写入数据,其实现方式是:当我们向系统中注册一个signal事件时,系统会为其选择一个统一的信号处理函数:

                         static void evsig_handler(int sig),这个信号处理函数所作的事情很简单,向socketpair写端写入信号值,随后系统就能检测到socketpair读端可读,

                         知道有信号发生

        (3)socketpair读端知道有信号发生后,就会调用系统为socketpair读端注册的回调函数:static void   evsig_cb(evutil_socket_t fd, short what, void *arg)

                  这个函数所作的工作是:读入信号值,并将信号发生次数加一,信号发生次数通过数组 :int ncaught[NSIG];实现,NSIG是信号种类数,数组下表即为信号值,

                  数组元素值为信号发生次数。接着调用函数:evmap_signal_active将此信号事件加入激活队列,传递给此函数的参数包括信号值以及信号发生次数。


 

0 0
原创粉丝点击