ev_signal¶
ev_signal 主要用来将异步信号转换为同步信号.
当进程一次或多次接收到特定的信号时, ev_signal将会报告一次事件. 尽管我们都知道信号(signal)是完全异步的, 但Libev会像普通事件处理那样尽可能同步传递.
如果您希望真正的使用异步信号, 就像是没有Libev那样只需要使用sigaction即可. 甚至你可以使用ev_async从外部信号函数中唤醒事件循环.
允许为统一个信号(signal)创建并配置任意数量的ev_signal, 但是这只能在同一个ev_loop中. 即: 您可以在loop_1中观察SIGINT, loop_2中观察SIGIO; 但不能再loop_1与loop_2中同时观察SIGINT. 并且, SIGCHILD只能在默认的是事件循环中有效.
只有真正启动了ev_signal后, Libev才会向内核注册更改. 因此, 只要您不向Libev注册任何信号, Libev就能正常的与您自己的信号处理程序共存.
fork/execve/pthread_create 继承的特殊问题
sigprocmask与sigaction在启动ev_signal之后都是未被指定的. 也就是说Libev可能会也可能不会阻塞信号, 可能会也可能不会回恢复sigaction.(参考EVFLAG_NOSIGMASK).
虽然这对信号处理没有影响(Libev不会将信号设置为SIG_IGN, 所以处理程序将在execve上重置为SIG_DFL), 但这对信号掩码有影响. 如: 许多程序并不期望某些信号被阻塞.
这意味着在调用exec之后, 您应该在子进程将信号掩码重置为您所认为的任何”默认值”. 确保在子进程中重置信号掩码的最简单方法就是使用pthread_atfork来处理.
在新版本的Libev之中. 除非您使用signalfd的相关API, 否则信号不会被无限期的阻塞.
线程信号处理的特殊问题
POSIX线程的信号处理语义有问题. 特别是很多功能(sigfd、sigwait等)只有在一个进程中的所有线程都阻塞信号时才真正起作用, 这很难实现。
当您想要使用sigwait(或将Libev信号处理与您自己的信号处理混合使用), 您可以在创建ev_loop的之前, 创建任何线程(或使用完全设置的sigprocmask创建线程)之前全局阻塞所有信号并且指定EVFLAG_NOSIGMASK来解决此问题. 然后指定其中一个线程作为信号处理线程.
你可以通过调动ev_feed_signal来传递任何Libev感兴趣的信号.
相关函数¶
ev_signal_init (ev_signal *, callback, int signum);
// 将ev_signal配置为signum所表示的信号编号上的观察程序.
ev_signal_set (ev_signal *, int signum);
// ev_signal关注的信号.
int signum [read-only]
使用示例¶
我们注册一个SIGINT, 在您按下ctrl-c的时候程序退出打印Bye:
// 只需导入单个头文件
#include <ev.h>
#include <stdio.h>
// 当使用了键盘的组合键`CTRL`+`C`之后回调会被调用.
static void sig_cb (struct ev_loop *loop, ev_signal *w, int revents)
{
puts ("Bye.");
ev_break(loop, EVBREAK_ALL);
}
int main (void)
{
// 可以使用已定义的宏来获取默认的事件循环, 当然你也可以根据自己的需求创建指定的.
struct ev_loop *loop = EV_DEFAULT;
ev_signal sigint;
ev_signal_init(&sigint, sig_cb, SIGINT);
ev_signal_start(loop, &sigint);
// 开始运行事件循环
ev_run (loop, 0);
// 如果事件循环退出, 那将会执行到这里.
return 0;
}