In Libevent, a convection pipe, or full-duplex pipe, is established by using Socketpair to unify the signal event with the handle event.
First look at the data structure:
struct evsignal_info {
struct event ev_signal; ///<所属的event
int ev_signal_pair[2]; ///<创建的流管道
int ev_signal_added; ///<信号是否已被加入到event中的标记。
volatile sig_atomic_t evsignal_caught; ///<事件触发标记,1表示有信号被触发
struct event_list evsigevents[NSIG]; ///<多个事件有可能注册到同一个信号,因此这里每个信号的事件都是一个event_list.
sig_atomic_t evsigcaught[NSIG]; ///<由于一个信号可能被注册多次,这里保存信号被捕捉的次数
#ifdef HAVE_SIGACTION
struct sigaction **sh_old;
#else
ev_sighandler_t **sh_old;
#endif
int sh_old_max;
};
Here are a few key functions to look at:
The Evsignal_init function is primarily used to initialize some data structures.
void
Evsignal_init (struct event_base *base)
{
int i;
///Create a convection pipeline
if (Evutil_socketpair (
Af_unix, Sock_stream, 0, base->sig.ev_signal_pair) = = 1)
Even T_err (1, "%s:socketpair", __func__);
///Set FD
Fd_closeonexec (base->sig.ev_signal_pair[0]);
Fd_closeonexec (base->sig.ev_signal_pair[1]);
///initialization SIG data structure
Base->sig.sh_old = NULL;
Base->sig.sh_old_max = 0;
Base->sig.evsignal_caught = 0;
memset (&base->sig.evsigcaught, 0, sizeof (sig_atomic_t) *nsig);
/* Initialize the queues for all events */
///in Libevent, all event queues are implemented with tail queue, which uses Linux with its own taile que UE, the specific use can go to the man manual.
for (i = 0; i < nsig ++i)
Tailq_init (&base->sig.evsigevents[i);
///Set non-blocking
evutil_make_socket_nonblocking (base->sig.ev_signal_pair[0]);
///Initialization Event structure
Event_set (&base->sig.ev_signal, base->sig.ev_signal_pair[1),
Ev_reAD | Ev_persist, EVSIGNAL_CB, &base->sig.ev_signal);
Base->sig.ev_signal.ev_base = base;
Base->sig.ev_signal.ev_flags |= evlist_internal;
}