日期:2014-05-16  浏览次数:20770 次

linux新API---signalfd的使用方法

linux新API--signalfd的使用方法

名字

signalfd - 创建一个用于所受信号的文件描述符

概要

#include <sys/signalfd.h>

int signalfd(int fd, const sigset_t*mask, intflags);

描述

signalfd() 创建一个可以用于接受以调用者为目标的信号的文件描述符。这提供了一个使用信号处理器或sigwaitinfo(2)的改良方式,并且这种方式存在一个优点就是可以使用select(2)、poll(2) 和epoll(7) 来监视。

mask 参数指出想要通过这个文件描述符接受的信号集。这个参数是信号集,它可以使用在 sigsetops(3)说明的宏来初始化。通常情况下,通过这个文件描述符接受的信号应该使用sigprocmask(2)阻塞,这样可以避免触发这些信号的默认处理方式。不可能通过文件描述符接受到信号SIGKILLSIGSTOP;如果这两个信号在mask 里指定则会被默默地忽略。

如果 fd 参数是 -1,那么调用创建一个新的文件描述符并且把 mask 指定的信号集与其关联。如果fd 不是 -1,它必须是一个有效的并已经存在的文件描述符,而mask用于替换之前与这个文件描述符关联的信号集。

从 Linux 2.6.27 开始,下面值可以经过位或运算放置在 flags 里以来改变signalfd() 的行为:

SFD_NONBLOCK
在新打开的文件描述符设置 O_NONBLOCK 标记。在 fcntl(2) 中保存这个标记可以得到相同的效果。
SFD_CLOEXEC
在新打开的文件描述符里设置 close-on-exec (FD_CLOEXEC) 标记。参看在open(2) 里关于O_CLOEXEC标记的描述来了解这为什么有用。

在包括 2.6.26 之前的版本里,flags 参数没有使用,并且必须指定为零。

signalfd() 返回的文件描述符支持如下操作:

read(2)
如果有一个或多个在 mask 指定的信号对进程未决,那么 read(2) 提供的缓存区将用于返回一个或多个用于描述信号的signalfd_siginfo 结构(见下面说明)。read(2)尽可能地把未决的信号都返回并且把它们填充到提供的缓存区里。这个缓存区至少要有sizeof(structsignalfd_siginfo) 个字节尺寸。read(2) 的返回值是所有读到数据的字节总数。
在一系列的 read(2)之后,信号被消耗了,因此它们不会再处于未决状态进程(也就是说,不会再调用信号处理器,并且不会被sigwaitinfo(2) 接受)。
如果没有在 mask 里的信号对进程处于未决状态,那么 read(2) 要么阻塞至有一个 mask里的信号为进程产生,或者在非阻塞模式里失败于EAGAIN
poll(2), select(2) (等等诸如此类)
如果有一个或多个在 mask 里信号对进程处于未决状态,则文件描述符可读(select(2) readfds 参数;poll(2) POLLIN 标志)。
signalfd 文件描述符也支持其它文件描述符复用 API:pselect(2)、ppoll(2) 和epoll(7)。
close(2)
当文件描述符不再使用时应该被关闭。当关联于同一个 signalfd对象的所有文件描述符都被关闭时,相应的资源将被内核回收。

signalfd_siginfo 结构

read(2) 从 signalfd 文件描述符返回的signalfd_siginfo 结构的正式定义如下:
struct signalfd_siginfo {
    uint32_t ssi_signo;   /* 信号编号 */
    int32_t  ssi_errno;   /* 错误码 (未使用) */
    int32_t  ssi_code;    /* 信号码 */
    uint32_t ssi_pid;     /* 发送都的 PID */
    uint32_t ssi_uid;     /* 发送都的真实UID */
    int32_t  ssi_fd;      /* 文件描述符 (SIGIO) */
    uint32_t ssi_tid;     /* 内核定时器 ID (POSIX 定时器)
    uint32_t ssi_band;    /* 波动事件 (SIGIO) */
    uint32_t ssi_overrun; /* POSIX 定时器超过次数 */
    uint32_t ssi_trapno;  /* 导致信号的陷阱号 */
    int32_t  ssi_status;  /* 退出状态或信号 (SIGCHLD) */
    int32_t  ssi_int;     /* sigqueue(2) 发送的整数 */
    uint64_t ssi_ptr;     /* sigqueue(2) 发送的指针 */
    uint64_t ssi_utime;   /* 用户CPU时消耗 (SIGCHLD) */
    uint64_t ssi_stime;   /* 系统CPU时消耗 (SIGCHLD) */
    uint64_t ssi_addr;    /* 产生信号的地址(对硬件信号) */
    uint8_t  pad[X];   /*填充到 128 字节 (允许将来添加字段) */
};

这个结构中的字段与 siginfo_t 结构中的同名字段有相同含意。siginfo_t 结构在sigaction(2) 里有描述。对于特定的信号并不是signalfd_siginfo 结构中的所有字段都有意义;有效的字段集可以通过其ssi_code域来判定。这个字段与siginfo_t 中的 si_code 字段相同;参考 sigaction(2) 了解细节。

fork(2) 语义

fork(2) 之后,孩子复制继承 signalfd文件描述符。在孩子里调用 read(2) 将返回缓存给孩子的信号。

execve(2) 语义

与所有其它文件描述符一样,一个 signalfd 文件描述符在穿过 execve(2) 之后仍然保持打开,除非它被标记为“执行时关闭”(见fcntl