Libevent, as the network IO library in unix/linux, efficiently integrates IO events, Timeout events, and signal events. This article mainly describes the ins and outs of Integrated signal events. First paste the code of the client application signal event: static void signal_cb (int fd, short event, void * arg) {struct event * signal = arg; printf ("% s: got signal % d \ n ", _ func __, EVENT_SIGNAL (signal); if (called> = 2) event_del (signal); called ++ ;} int main (int argc, char ** argv) {struct event signal_int;/* Initalize the event library */struct event_base * base = event_base_new (); /* Initalize one event */event_set (& signal_int, SIGINT, E V_SIGNAL | EV_PERSIST, signal_cb, & signal_int); event_base_set (base, & signal_int); event_add (& signal_int, NULL); event_base_dispatch (base); event_base_free (base ); return (0);} event_init () initializes an event_base (reactor instance), sets the callback function of the timer event by evtimer_set (), and then event_add () add the timer event to the reactor instance. finally, enter event_dispatch () Main Loop. the event is represented by the First Ancestor: (event, fd, flag, handler) that is (event, file descriptor, flag, callback function). In the above Code, the signal event can be expressed as (signal_int, SIGINT, EV_SIGNAL | EV_PERSIST, Signal_cb), where the SIG_INT signal is generated by ctrl + c. First, initialize the reactor instance. The core code allocates storage space for the struct event_base instance and initializes the event IO reuse mechanism (select, epoll, etc.) for (I = 0; eventops [I] &! Base-> evbase; I ++) {base-> evsel = eventops [I]; base-> evbase = base-> evsel-> init (base ); // struct selectop *} assume that the IO reuse mechanism is select. base-> evsel-> init (base) calls select_init, which calls evsignal_init (base) back ), initialize base-> sig. the ev_signal_pair [] array. The libevent is base-> sig. ev_signal event registers evsignal_cb callback function, base-> sig. the ev_signal event is represented as (base-> sig. ev_signal, base-> sig. ev_signal_pair [1], evsignal_cb), where evsignal_cb indicates that when a signal is generated, it starts from base-> sig. ev_signal _ Pair [1] reads 1 byte of data, converts the event to a common IO event, and then adds it to the Inserted linked list. After adding signal_int to the Inserted linked list, event_add is called. select_add is actually called. Because this event is an EV_SIGNAL event, evsignal_add is called, in this function, the callback function evsignal_handler of the signal event is re-registered, and the event four tuples are changed to (signal_int, SIGINT, EV_SIGNAL | EV_PERSIST, evsignal_handler). evsignal_base-> sig. evsigcaught [sig] ++; evsignal_base-> sig. evsignal_caught = 1; and directed to evsignal_base-> sig. ev_signal_pair [0] writes one byte of data. Here, the signal processing function registered with sigaction is for the SIGINT signal. That is, when you press ctrl + c, here, the (base-> sig. ev _ Signal, base-> sig. ev_signal_pair [1], evsignal_cb) is added to the Inserted linked list. if (! Sig-> ev_signal_added) {if (event_add (& sig-> ev_signal, NULL) return (-1); sig-> ev_signal_added = 1, TAILQ_INSERT_TAIL (& sig-> evsigevents [evsignal], ev, ev_signal_next) is called, and signal_int is added to the sig queue. The above is the initialization and registration process, and then the callback function of the event is called for the corresponding event (the process of executing event_base_loop ). There are two main processes: evsel-> dispatch (base, evbase, TV _p) that is, execute the select statement to wait until the descriptor is ready to add the corresponding event to the active queue and scan the active queue to execute the corresponding callback function of the event in sequence. When the select round robin file descriptor is in the select_dispatch loop, pressing ctrl + c will interrupt the execution of the select statement to return-1, that is, execute the following code: if (res =-1) {if (errno! = EINTR) {event_warn ("select"); return (-1);} evsignal_process (base); return (0);} In evsignal_process, base-> sig is enabled. evsignal_caught = 0; and add events in the sig queue to the active queue, for (I = 1; I <NSIG; ++ I) {ncballs = sig-> evsigcaught [I]; if (ncballs = 0) continue; sig-> evsigcaught [I]-= ncballs; for (ev = TAILQ_FIRST (& sig-> evsigevents [I]); ev! = NULL; ev = next_ev) {next_ev = TAILQ_NEXT (ev, ev_signal_next); if (! (Ev-> ev_events & EV_PERSIST) event_del (ev); event_active (ev, EV_SIGNAL, ncils) ;}} returned, and then continued into the event loop. We found evsignal_base-> sig. ev_signal_pair [1] is readable and can be added to the active Queue for scheduling. The following shows the call sequence of the callback function and main function after debug is Enabled: [debug] event_add: event: 0xbff320b8, call 0x8048780
[Debug] evsignal_add: 0xbff320b8: changing signal handler
[Debug] _ evsignal_set_handler: evsignal (2)> = sh_old_max (0), resizing
[Debug] event_add: event: 0x99d8028, EV_READ call 0xb7753d50
^ C [debug] evsignal_handler: received signal 2, called
[Debug] epoll_dispatch: epoll_wait reports --- res =-1-1
Signal_cb: got signal 2
[Debug] epoll_dispatch: epoll_wait reports 1
[Debug] evsignal_cb: evsignal_cb callded fd = 5 wherein ^ C is displayed after pressing ctrl + c. The function call sequence is displayed.