signal()有个高级版本的函数sigaction(),这个函数功能上要比signal()强大且具有可移植性
- int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
- struct sigactgion {
- void (*sa_handler)(int); //信号捕捉函数,同signal(可以是SIG_IGN SIG_DFL)
- sigset_t sa_mask;
- int sa_flags;
- void (*sa_sigaction)(int , siginfo_t *, void *);
- };
SA_INTERRUPT和SA_RESTART两个选项只能有一个,前者是被打断的系统调用不会启动重启后者会自动重启,比如read()在阻塞时如果到来一个信号read()会被打断,如果信号的处理动作中设置SA_RESTART会自动重启,如果设置了SA_INTRRUPUT则不会自动重启,read()返回-1并设置errno为EINTR。(默认是SA_RESTART 忽略的信号不能打断低速系统调用)。
SA_NOCLDWAIT,用户SIGCHLD信号,子进程不会创建僵尸进程。SA_SIGINFO,设置了则使用高级版本的信号处理函数sa_sigaction。
SA_NODEFER,在该信号的处理函数中不会阻塞该信号,用于不可靠信号。
最后在来看看高级版本的信号处理函数sa_sigaction,该函数指针指向的处理函数的第一个参数仍然是信号编号,第二个参数是一个结构体指针,该结构体中提供了信号产生原因的一系列信息,最后一个参数void*是一个上下文环境,用不到。来看下siginfo_t结构
- struct siginfo_t {
- int si_signo; /* Signal number */
- int si_errno; /* if nonzero, errno value from errno.h */
- int si_code; /* additional info(depends on signal) 详细见下图 */
- pid_t si_pid; /* Sending process ID */
- uid_t si_uid; /* Real user ID of sending process */
- void* si_addr; /* adress that caused the fault */
- int si_status; /* Exit value or signal number */
- int si_band; /* Band number for SIGPOLL */
- sigval_t si_value; /* 信号伴随的额外信息 */
- /* possibly other fields also */
- ;
si_pid si_uid是发送者的信息,但只针对SIGCHLD和可靠信号有效。从si_value中可以获得发送信号时携带的信息,类型是sigval_t,其实是一个共用体,如下
- union sigval {
- int sival_int;
- void *sival_ptr;
- };
那如何在发送时发送携带数据?使用sigqueue()函数发送信号时可以携带数据:
- int sigqueue(pid_t pid, int sig, const union sigval value);
最后我们说明一下实时信号的概念,在常用的前一部分非实时信号后,SIGRTMIN~SIGRTMAX这些信号是实时信号。
信号(1)中我们提到,当在不可靠信号处理函数执行过程中,再次接受到多个相同的信号,则当处理函数执行完毕后只再执行一般,其余的信号丢失了,也就是当不可靠信号处于阻塞状态下,最多只能有个该信号处于未决状态,其余的都丢失了;实时信号不会丢失,实现了排队的功能,并且实时信号时用户优先级的,优先级是由SIGRTMIN~SIGRTMAX依次递增的。