libev-signal watcher
signal watcher
signal watcher是需要io watcher来完成的。
signalwatcher通过evpipe_init来创建管道和iowatcher(管道的fd赋值给io watcher),当收到某信号后ev_sighandler会调用并会往管道写数据。
主循环体通过backend_poll检测管道的fd可读/写时就会把对应的io watcher放到loop->pending上。
主循环体调用ev_invoke_pending就会检测pending上就绪的io
watcher并调用该watcher的回调函数pipecb(pipecb函数就会读取管道数据,并把signal watcher放到loop->pengding上),然后ev_invoke_pending检测到signal watcher被激活,调用它的回调函数signal_do。
signal watcher的配置
evinit(事件)—>ev事件set()—>ev事件_start()
测试用例:我创建一个信号事件,当接收到SIGINT信号时回调signal_do函数。
ev_singal signal_e;
void signal_do(struct ev_loop *loop, ev_sinal *signal_e, int e)
{
printf("signal callback!\n");
ev_signal_stop(loop, signal_e);
}
int main(int argc ,char *argv[])
{
struct ev_loop *loop = ev_default_loop(0);
ev_singal signal_e;
ev_init(&signal_e,signal_do);
ev_signal_set(&signal_e,SIGINT);
ev_signal_start(loop,&signal_e);
ev_run(loop,0);
return 0;
}
watcher通用接口
typedef void (*)(struct ev_loop *loop, ev_TYPE *watcher, int revents) callback; // callback都是这种类型
ev_init (ev_TYPE *watcher, callback); // 初始化watcher
ev_TYPE_set (ev_TYPE *watcher, [args]); // 设置watcher
ev_TYPE_init (ev_TYPE *watcher, callback, [args]); // 通常使用这个函数最方便,初始化和设置都在这里
ev_TYPE_start (loop, ev_TYPE *watcher); // 注册watcher
ev_TYPE_stop (loop, ev_TYPE *watcher); // 注销watcher
ev_set_priority (ev_TYPE *watcher, int priority); // 设置优先级
ev_feed_event (loop, ev_TYPE *watcher, int revents); // 这个做跨线程通知非常有用,相当于触发了某个事件。
bool ev_is_active (ev_TYPE *watcher); // watcher是否active.
bool ev_is_pending (ev_TYPE *watcher); // watcher是否pending.
int ev_clear_pending (loop, ev_TYPE *watcher); // 清除watcher pending状态并且返回事件
watcher 代码分析:
struct ev_signal结构体
typedef struct ev_signal
{
EV_WATCHER_LIST (ev_signal)
int signum; /* ro */
} ev_signal;
libev里面很多都是宏声明结构体和函数,下面就是struct ev_signal里宏被展开后的形式:
typedef struct ev_signal
{
/* active表示事件是否被激活 */
int active;
/* pending表示事件就绪,等待处理 */
int pending;
/* priority当前事件优先级 */
int priority;
/* data附件数据指针,用来在时间中携带额外的数据 */
void *data;
/* cb是事件触发后的回调函数 */
void (*cb)(EV_P_ struct type *w, int revents);
struct ev_watcher_list *next;
int signum; /* ro */
} ev_signal;
signals全局变量
所有SIGINT watcher都挂载到signals[SIGINT-1].head上。
typedef struct
{
EV_ATOMIC_T pending; /* 信号事件是否激活 */
struct ev_loop *loop;
WL head;
} ANSIG;
static ANSIG signals [EV_NSIG - 1];
signal watcher初始化
ev_init(&signal_e, signal_do);
#define ev_init(ev,cb_) do { \
((ev_watcher *)(void *)(ev))->active = \
((ev_watcher *)(void *)(ev))->pending = 0; \
ev_set_priority ((ev), 0); \
ev_set_cb ((ev), cb_); \
} while (0)
signal watcher配置信号
ev_signal_set(&signal_e,SIGINT)
#define ev_signal_set(ev,signum_) do { (ev)->signum = (signum_); } while (0);
signal watcher启动
ev_signal_start(loop,&signal_e);
void noinline
ev_signal_start (struct ev_loop *loop, ev_signal *w) EV_THROW
{
if (expect_false (ev_is_active (w)))
return;
signals [w->signum - 1].loop = loop;
/* # define EV_FREQUENT_CHECK ev_verify (EV_A)
* 调用ev_verify(loop)
*/
EV_FREQUENT_CHECK;
/* 此时loop->sigfd == -1 */
if (loop->sigfd == -2)
{
/* 创建一个fd来接受信号
* 把信号集loop->sigfd_set与fd关联起来
* 第一个参数为-1表示新建一个signalfd
*/
loop->sigfd = signalfd (-1, &sigfd_set, SFD_NONBLOCK | SFD_CLOEXEC);
if (loop->sigfd < 0 && errno == EINVAL)
loop->sigfd = signalfd (-1, &sigfd_set, 0); /* retry without flags */
if (loop->sigfd >= 0)
{
fd_intern (loop->sigfd); /* doing it twice will not hurt */
sigemptyset (&loop->sigfd_set);
ev_io_init (&loop->sigfd_w, sigfdcb, sigfd, EV_READ);
ev_set_priority (&loop->sigfd_w, EV_MAXPRI);
ev_io_start (loop, &loop->sigfd_w);
ev_unref (loop); /* signalfd watcher should not keep loop alive */
}
}
/* 此时loop->sigfd == -1 */
if (loop->sigfd >= 0)
{
/* TODO: check .head */
sigaddset (&loop->sigfd_set, w->signum);
sigprocmask (SIG_BLOCK, &loop->sigfd_set, 0);
signalfd (loop->sigfd, &sigfd_set, 0);
}
/*
* typedef ev_watcher *W
* 调整water的优先级
* 激活watcher, w->active = 1
* loop->activecnt++
*/
ev_start (loop, (W)w, 1);
把SIGINT信号的 watcher挂到signals[SIGINT-1]链表上
wlist_add (&signals [w->signum - 1].head, (WL)w);
if (!((WL)w)->next)
/* 此时loop->sigfd == -1 */
if (loop->sigfd < 0) /*TODO*/
{
struct sigaction sa;
ev_pipe_init:
1.建立管道(loop->evpipe), 把管道信息赋值给一个io
watcher(loop->pipe_w)。
evpipe_init (loop);
ev_sighandler的作用当接受SIGINT信号时,调用evpipe_write函数触发以下事件:
watcher设置为就绪状态(loop->sig_pending设置为1)。
往管道写信息(主循环体会调用io
watcher(loop->pipe_w)回调函数pipecb来读取管道信息,若signal watcher已激活(sig_pending等于1),主循环下一步就会调用测试代码的注册回调函数signal_do)。 sa.sa_handler = ev_sighandler; sigfillset (&sa.sa_mask); /* if restarting works we save one iteration */ sa.sa_flags = SA_RESTART; sigaction (w->signum, &sa, 0); if (loop->origflags & EVFLAG_NOSIGMASK) { sigemptyset (&sa.sa_mask); sigaddset (&sa.sa_mask, w->signum); sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0); } } EV_FREQUENT_CHECK;
}