sigaction(2) - Linux 手册页

名称

sigaction - 检查并更改信号动作

概要

#include <signal.h>

int sigaction(int signum, const struct sigaction *act,
              struct sigaction *oldact);
glibc 的功能测试宏要求(参见 feature_test_macros(7))
sigaction(): _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE

siginfo_t: _POSIX_C_SOURCE >= 199309L

描述

sigaction() 系统调用用于更改进程在接收到特定信号时所采取的动作。(关于信号的概述,请参见 signal(7)。)

signum 指定信号,可以是除了 SIGKILLSIGSTOP 之外的任何有效信号。

如果 act 不为 NULL,则信号 signum 的新动作将根据 act 进行安装。如果 oldact 不为 NULL,则先前的动作将保存在 oldact 中。

sigaction 结构体的定义大致如下

struct sigaction {
    void     (*sa_handler)(int);
    void     (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t   sa_mask;
    int        sa_flags;
    void     (*sa_restorer)(void);
};
在某些架构上,会涉及到一个联合体:请勿同时对 sa_handlersa_sigaction 进行赋值。

sa_restorer 元素已过时,不应使用。POSIX 未指定 sa_restorer 元素。

sa_handler 指定与 signum 相关联的动作,可以是 SIG_DFL(默认动作)、SIG_IGN(忽略此信号)或指向信号处理函数的指针。此函数接收信号编号作为其唯一参数。

如果 sa_flags 中指定了 SA_SIGINFO,则 sa_sigaction(而不是 sa_handler)指定 signum 的信号处理函数。此函数接收信号编号作为其第一个参数,指向 siginfo_t 的指针作为其第二个参数,以及指向 ucontext_t(强制转换为 void *)的指针作为其第三个参数。(通常,处理函数不会使用第三个参数。关于 ucontext_t 的更多信息,请参见 getcontext(3)。)

sa_mask 指定了一个信号掩码,在该信号处理函数执行期间,这些信号应被阻塞(即,添加到调用信号处理函数的线程的信号掩码中)。此外,除非使用了 SA_NODEFER 标志,否则触发该处理函数的信号本身也会被阻塞。

sa_flags 指定了一组修改信号行为的标志。它由零个或多个以下标志按位或而成

SA_NOCLDSTOP
如果 signumSIGCHLD,则在子进程停止(即,接收到 SIGSTOPSIGTSTPSIGTTINSIGTTOU 之一)或恢复(即,接收到 SIGCONT)时,不接收通知(参见 wait(2))。此标志仅在为 SIGCHLD 建立处理程序时有意义。
SA_NOCLDWAIT (自 Linux 2.6 起)
如果 signumSIGCHLD,则在子进程终止时不要将其变为僵尸进程。另请参见 waitpid(2)。此标志仅在为 SIGCHLD 建立处理程序,或将该信号的配置设置为 SIG_DFL 时有意义。

如果在为 SIGCHLD 建立处理程序时设置了 SA_NOCLDWAIT 标志,POSIX.1 未明确规定在子进程终止时是否生成 SIGCHLD 信号。在 Linux 上,此时会生成 SIGCHLD 信号;而在某些其他实现中则不会。

SA_NODEFER
不要阻止在信号处理程序自身内部接收该信号。此标志仅在建立信号处理程序时有意义。SA_NOMASK 是此标志的一个过时的、非标准的同义词。
SA_ONSTACK
在由 sigaltstack(2) 提供的备用信号栈上调用信号处理程序。如果没有可用的备用栈,将使用默认栈。此标志仅在建立信号处理程序时有意义。
SA_RESETHAND
进入信号处理程序时将信号动作恢复为默认值。此标志仅在建立信号处理程序时有意义。SA_ONESHOT 是此标志的一个过时的、非标准的同义词。
SA_RESTART
通过使某些系统调用在信号中断后可重启,从而提供与 BSD 信号语义兼容的行为。此标志仅在建立信号处理程序时有意义。有关系统调用重启的讨论,请参见 signal(7)。
SA_SIGINFO (自 Linux 2.2 起)
信号处理程序接收三个参数,而不是一个。在这种情况下,应设置 sa_sigaction 而不是 sa_handler。此标志仅在建立信号处理程序时有意义。
传递给 sa_sigactionsiginfo_t 参数是一个包含以下元素的结构体
siginfo_t {
    int      si_signo;    /* Signal number */
    int      si_errno;    /* An errno value */
    int      si_code;     /* Signal code */
    int      si_trapno;   /* Trap number that caused
                             hardware-generated signal
                             (unused on most architectures) */
    pid_t    si_pid;      /* Sending process ID */
    uid_t    si_uid;      /* Real user ID of sending process */
    int      si_status;   /* Exit value or signal */
    clock_t  si_utime;    /* User time consumed */
    clock_t  si_stime;    /* System time consumed */
    sigval_t si_value;    /* Signal value */
    int      si_int;      /* POSIX.1b signal */
    void    *si_ptr;      /* POSIX.1b signal */
    int      si_overrun;  /* Timer overrun count; POSIX.1b timers */
    int      si_timerid;  /* Timer ID; POSIX.1b timers */
    void    *si_addr;     /* Memory location which caused fault */
    long     si_band;     /* Band event (was int in
                             glibc 2.3.2 and earlier) */
    int      si_fd;       /* File descriptor */
    short    si_addr_lsb; /* Least significant bit of address
                             (since kernel 2.6.32) */
}
si_signosi_errnosi_code 对所有信号都有定义。(si_errno 在 Linux 上通常未使用。)结构体的其余部分可能是一个联合体,因此只应读取对给定信号有意义的字段。
*

使用 kill(2) 和 sigqueue(3) 发送的信号会填充 si_pidsi_uid。此外,使用 sigqueue(3) 发送的信号会使用信号发送者指定的值填充 si_intsi_ptr;有关更多详细信息,请参见 sigqueue(3)。

*

由 POSIX.1b 定时器发送的信号(自 Linux 2.6 起)会填充 si_overrunsi_timeridsi_timerid 字段是内核用于标识定时器的内部 ID;它与 timer_create(2) 返回的定时器 ID 不同。si_overrun 字段是定时器超时计数;这与通过调用 timer_getoverrun(2) 获取的信息相同。这些字段是非标准的 Linux 扩展。

*

为消息队列通知发送的信号(参见 mq_notify(3) 中 SIGEV_SIGNAL 的描述)会填充 si_int/si_ptr,其中包含提供给 mq_notify(3) 的 sigev_valuesi_pid 包含消息发送者的进程 ID;si_uid 包含消息发送者的实际用户 ID。

*

SIGCHLD 填充 si_pidsi_uidsi_statussi_utimesi_stime,提供关于子进程的信息。si_pid 字段是子进程的进程 ID;si_uid 是子进程的实际用户 ID。si_status 字段包含子进程的退出状态(如果 si_codeCLD_EXITED),或者导致进程状态改变的信号编号。si_utimesi_stime 包含子进程使用的用户 CPU 时间和系统 CPU 时间;这些字段不包括已等待子进程所使用的 CPU 时间(与 getrusage(2) 和 time(2) 不同)。在 2.6 及之前版本的内核中,以及自 2.6.27 起,这些字段以 sysconf(_SC_CLK_TCK) 为单位报告 CPU 时间。在 2.6.27 之前的 2.6 内核中,一个 bug 导致这些字段以(可配置的)系统时钟滴答数(jiffy)为单位报告时间(参见 time(7))。

*

SIGILLSIGFPESIGSEGVSIGBUSSIGTRAP 会填充 si_addr,其中包含故障地址。在某些架构上,这些信号还会填充 si_trapno 字段。SIGBUS 的某些子错误,特别是 BUS_MCEERR_AOBUS_MCEERR_AR,也会填充 si_addr_lsb。该字段指示所报告地址的最低有效位,从而表示损坏的程度。例如,如果整页损坏,si_addr_lsb 包含 log2(sysconf(_SC_PAGESIZE))BUS_MCERR_*si_addr_lsb 是 Linux 特有的扩展。

*

SIGIO/SIGPOLL(在 Linux 上这两个名称是同义词)填充 si_bandsi_fdsi_band 事件是一个位掩码,包含与 poll(2) 在 revents 字段中填充的值相同的值。si_fd 字段指示发生 I/O 事件的文件描述符。

si_code 是一个值(非位掩码),指示发送此信号的原因。以下列表显示了可放置在任何信号的 si_code 中的值,以及信号生成的原因。
SI_USER

kill(2)

SI_KERNEL

由内核发送。

SI_QUEUE

sigqueue(3)

SI_TIMER

POSIX 定时器到期

SI_MESGQ

POSIX 消息队列状态改变(自 Linux 2.6.6 起);参见 mq_notify(3)

SI_ASYNCIO

异步 I/O (AIO) 完成

SI_SIGIO

排队的 SIGIO(仅在 Linux 2.2 及以前内核中;从 Linux 2.4 开始,SIGIO/SIGPOLL 填充 si_code 的方式如下所述)。

SI_TKILL

tkill(2) 或 tgkill(2) (自 Linux 2.4.19 起)

以下值可放置在 SIGILL 信号的 si_code
ILL_ILLOPC

非法操作码

ILL_ILLOPN

非法操作数

ILL_ILLADR

非法寻址模式

ILL_ILLTRP

非法陷阱

ILL_PRVOPC

特权操作码

ILL_PRVREG

特权寄存器

ILL_COPROC

协处理器错误

ILL_BADSTK

内部栈错误

以下值可放置在 SIGFPE 信号的 si_code
FPE_INTDIV

整数除以零

FPE_INTOVF

整数溢出

FPE_FLTDIV

浮点除以零

FPE_FLTOVF

浮点溢出

FPE_FLTUND

浮点下溢

FPE_FLTRES

浮点不精确结果

FPE_FLTINV

浮点非法操作

FPE_FLTSUB

下标越界

以下值可放置在 SIGSEGV 信号的 si_code
SEGV_MAPERR

地址未映射到对象

SEGV_ACCERR

映射对象的权限无效

以下值可放置在 SIGBUS 信号的 si_code
BUS_ADRALN

无效地址对齐

BUS_ADRERR

不存在的物理地址

BUS_OBJERR

对象特定的硬件错误

BUS_MCEERR_AR (自 Linux 2.6.32 起)

硬件内存错误在机器检查时被消耗;需要采取行动。

BUS_MCEERR_AO (自 Linux 2.6.32 起)

硬件内存错误在进程中被检测到但未消耗;行动可选。

以下值可放置在 SIGTRAP 信号的 si_code
TRAP_BRKPT

进程断点

TRAP_TRACE

进程追踪陷阱

TRAP_BRANCH (自 Linux 2.4 起)

进程分支陷阱

TRAP_HWBKPT (自 Linux 2.4 起)

硬件断点/观察点

以下值可放置在 SIGCHLD 信号的 si_code
CLD_EXITED

子进程已退出

CLD_KILLED

子进程被杀死

CLD_DUMPED

子进程异常终止

CLD_TRAPPED

被追踪的子进程已陷阱

CLD_STOPPED

子进程已停止

CLD_CONTINUED

停止的子进程已继续(自 Linux 2.6.9 起)

以下值可放置在 SIGIO/SIGPOLL 信号的 si_code
POLL_IN

有数据输入可用

POLL_OUT

输出缓冲区可用

POLL_MSG

有输入消息可用

POLL_ERR

I/O 错误

POLL_PRI

有高优先级输入可用

POLL_HUP

设备已断开连接

返回值

sigaction() 成功时返回 0,出错时返回 -1。

错误

EFAULT

actoldact 指向的内存不是进程地址空间的有效部分。

EINVAL

指定了无效信号。如果尝试更改 SIGKILLSIGSTOP 的动作(它们不能被捕获或忽略),也会产生此错误。

符合

POSIX.1-2001, SVr4。

说明

通过 fork(2) 创建的子进程继承了其父进程信号配置的副本。在 execve(2) 期间,已处理信号的配置会重置为默认值;被忽略信号的配置则保持不变。

根据 POSIX,进程在忽略非由 kill(2) 或 raise(3) 生成的 SIGFPESIGILLSIGSEGV 信号后的行为是未定义的。整数除以零的结果是未定义的。在某些架构上,它会生成 SIGFPE 信号。(此外,将最小负整数除以 -1 也可能生成 SIGFPE。)忽略此信号可能会导致无限循环。

POSIX.1-1990 禁止将 SIGCHLD 的动作设置为 SIG_IGN。POSIX.1-2001 允许此可能性,因此忽略 SIGCHLD 可用于防止僵尸进程的产生(参见 wait(2))。然而,历史上 BSD 和 System V 关于忽略 SIGCHLD 的行为不同,因此确保已终止的子进程不会变成僵尸进程的最完全可移植的方法是捕获 SIGCHLD 信号并执行 wait(2) 或类似操作。

POSIX.1-1990 仅指定了 SA_NOCLDSTOP。POSIX.1-2001 添加了 SA_NOCLDWAITSA_RESETHANDSA_NODEFERSA_SIGINFO。在针对旧版 UNIX 实现的应用程序中,在 sa_flags 中使用这些值可能不那么可移植。

SA_RESETHAND 标志与具有相同名称的 SVr4 标志兼容。

SA_NODEFER 标志在 1.3.9 及更新的内核下与具有相同名称的 SVr4 标志兼容。在较旧的内核上,Linux 实现允许接收任何信号,而不仅仅是我们正在安装的那个(实际上覆盖了任何 sa_mask 设置)。

可以将 sigaction() 的第二个参数设置为 NULL 来查询当前的信号处理程序。它也可通过将第二个和第三个参数设置为 NULL 来检查给定信号对当前机器是否有效。

无法阻塞 SIGKILLSIGSTOP(通过在 sa_mask 中指定它们)。尝试这样做会被静默忽略。

有关操作信号集的详细信息,请参见 sigsetops(3)。

有关可以在信号处理程序内部安全调用的异步信号安全函数的列表,请参见 signal(7)。

未记录

在引入 SA_SIGINFO 之前,也可以通过使用带有 struct sigcontext 类型第二个参数的 sa_handler 来获取一些额外信息。详情请参阅相关的 Linux 内核源代码。这种用法现在已过时。

错误

在包括 2.6.13 在内的版本中,在 sa_flags 中指定 SA_NODEFER 不仅会防止已发送的信号在处理程序执行期间被屏蔽,还会防止 sa_mask 中指定的信号被屏蔽。此错误已在 2.6.14 内核中修复。

示例

参见 mprotect(2)。

参见

kill(1), kill(2), killpg(2), pause(2), sigaltstack(2), signal(2), signalfd(2), sigpending(2), sigprocmask(2), sigsuspend(2), wait(2), raise(3), siginterrupt(3), sigqueue(3), sigsetops(3), sigvec(3), core(5), signal(7)

引用自

abort(3), alarm(2), bsd_signal(3), clock_nanosleep(2), clone(2), fcntl(2), fifo(4), fifo(7), getitimer(2), inotify(7), iv_signal(3), prctl(2), proc(5), profil(3), psignal(3), pth(3), pthread_kill(3), pthread_sigmask(3), pthread_sigqueue(3), ptrace(2), readpassphrase(3), rt_sigqueueinfo(2), sem_wait(3), semop(2), setcontext(2), sigevent(7), sigpause(2), sigpause(3), sigqueue(2), sigset(3), sigtimedwait(2), sigvec(2), sigwait(3), socket(7), swapcontext(2), swapcontext(3), sysv_signal(3), wait4(2)