APUE - 信号

信号概念

可以要求内核在某个信号出现时按照下列三种方式之一进行处理,我们称之为信号的处理或者与信号相关的动作。

  1. 忽略此信号。大多数信号都可使用这种方式进行处理,但有两种信号却决不能被忽略,它们是 SIGKILL 和 SIGSTOP。这两种信号不能被忽略的原因是:它们向超级用户提供了使进程终止或停止的可靠方法。另外,如果忽略某些由硬件异常产生的信号,则进程的运行行为是未定义的。
  2. 捕捉信号。为了做到这一点,要通知内核在某种信号发生时调用一个用户函数。在用户函数中,可执行用户希望对这种事件进行的处理。注意,不能捕捉 SIGKILL 和 SIGSTOP 信号。
  3. 执行系统默认动作。

signal 函数

UNIX 系统的信号机制最简单的接口是 signal 函数。

#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);

kill 和 raise 函数

kill 函数将信号发送给进程或进程组。raise 函数允许进程向自身发送信号。

#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);

alarm 和 pause 函数

使用 alarm 函数可以设置一个计时器,在将来某个指定的时间该计时器会超时。当计时器超时时,产生 SIGALRM 信号。如果不忽略或不捕捉此信号,则其默认动作是终止调用该 alarm 函数的进程。

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

每个进程只能有一个闹钟时钟。如果在调用 alarm 时,以前已为该进程设置过闹钟时钟,而且它还没有超时,则将该闹钟时钟的余留值作为本次 alarm 函数调用的返回值。以前登记的闹钟时钟则被新值代替。

如果有以前为进程登记的尚未超过的闹钟时钟,而且本次调用的 seconds 值是 0,则取消以前的闹钟时钟,其余留值仍作为 alarm 函数的返回值。

pause 函数使调用进程挂起直至捕捉到一个信号。

#include <unistd.h>
int pause(void);

只有执行了一个信号处理程序并从其返回时,pause 才返回。

信号集

POSIX.1 定义了数据类型 sigset_t 以包含一个信号集,并且定义了下列五个处理信号集的函数。

#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);

sigprocmask 函数

调用 sigprocmask 函数可以检测或更改信号屏蔽字,或者在一个步骤中同时执行这两个操作。

#include <signal.h>
int sigprocmask(int how, const sigset_t *restrict set,
                sigset_t *restrict oset);

sigprocmask 是仅为单线程的进程定义的。

sigpending 函数

sigpending 函数返回信号集,其中的各个信号对于调用进程是阻塞的而不能递送,因而也一定是当前未决的。

#include <signal.h>
int sigpending(sigset_t *set);

sigaction 函数

sigaction 函数的功能是检查或修改与指定信号相关联的处理动作(或同时执行这两种操作)。

#include <signal.h>
int sigaction(int signo, const struct sigaction *restrict act,
              struct sigaction *restrict oact);

struct sigaction {
    void        (*sa_handler)(int); /* addr of signal handler, */
                                    /* or SIG_IGN, or SIG_DFL */
    sigset_t    sa_mask;            /* additional signals to block */
    int         sa_flags;           /* signal options */

    /* alternate handler */
    void        (*sa_sigaction)(int, siginfo_t *, void *);
};

struct siginfo {
    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;     /* sending process real user ID */
    void   *si_addr;    /* address that caused the fault */
    int     si_status;  /* exit value or signal number */
    long    si_band;    /* band number for SIGPOLL */
    /* possibly other fields also */
};

sigsetjmp 和 siglongjmp 函数

#include <setjmp.h>
int sigsetjmp(sigjmp_buf env, int savemask);
void siglongjmp(sigjmp_buf env, int val);

sigsuspend 函数

#include <signal.h>
int sigsuspend(const sigset_t *sigmask);

abort 函数

#include <stdlib.h>
void abort(void);

sleep 函数

#include <unistd.h>
unsigned int sleep(unsigned int seconds);