SIGACTION - Linux手册页
Linux程序员手册 第2部分
更新日期: 2020-08-13
名称
sigaction,rt_sigaction-检查并更改信号动作
语法
#include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
glibc的功能测试宏要求(请参阅feature_test_macros(7)):
sigaction():_POSIX_C_SOURCE
siginfo_t:_POSIX_C_SOURCE> = 199309L
说明
sigaction()系统调用用于更改进程在收到特定信号后采取的操作。 (有关信号的概述,请参见signal(7)。)
signum指定信号,并且可以是除SIGKILL和SIGSTOP之外的任何有效信号。
如果act为非NULL,则从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_handler和sa_sigaction。
sa_restorer字段不适用于应用程序。 (POSIX未指定sa_restorer字段。)此字段用途的其他详细信息可以在sigreturn(2)中找到。
sa_handler指定要与信号量关联的操作,对于默认操作,可以为SIG_DFL;可以忽略该信号的为SIG_IGN;或者为信号处理函数的指针。该函数接收信号编号作为其唯一参数。
如果在sa_flags中指定了SA_SIGINFO,则sa_sigaction(而不是sa_handler)指定信号的信号处理功能。该函数接收三个自变量,如下所述。
sa_mask指定在执行信号处理程序期间应阻止(即,添加到调用信号处理程序的线程的信号掩码中)的信号掩码。另外,除非使用SA_NODEFER标志,否则触发处理程序的信号将被阻止。
sa_flags指定一组标志,这些标志可修改信号的行为。它由以下零或多个零的按位或运算而成:
- SA_NOCLDSTOP
- 如果signum为SIGCHLD,则子进程停止时(即当它们接收到SIGSTOP,SIGTSTP,SIGTTIN或SIGTTOU中的一种时)或恢复(即接收到SIGCONT)时不接收通知(请参见wait(2))。仅当为SIGCHLD建立处理程序时,此标志才有意义。
- SA_NOCLDWAIT(since Linux 2.6)
- 如果signum是SIGCHLD,则在终止子进程时不要将其转变为僵尸。另请参见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_RESTORER
- 不适用于应用程序。 C库使用此标志来指示sa_restorer字段包含"信号蹦床"的地址。有关更多详细信息,请参见sigreturn(2)。
- SA_SIGINFO(since Linux 2.2)
- 信号处理程序采用三个参数,而不是一个。在这种情况下,应设置sa_sigaction而不是sa_handler。该标志仅在建立信号处理程序时才有意义。
The siginfo_t argument to a SA_SIGINFO handler
当在act.sa_flags中指定SA_SIGINFO标志时,信号处理程序地址将通过act.sa_sigaction字段传递。该处理程序采用三个参数,如下所示:
void handler(int sig, siginfo_t *info, void *ucontext) { ... }
这三个参数如下
- sig
- 导致处理程序调用的信号编号。
- info
- 指向siginfo_t的指针,这是一个包含有关信号的更多信息的结构,如下所述。
- ucontext
- 这是指向ucontext_t结构的指针,该结构转换为void *。该字段所指向的结构包含内核已保存在用户空间堆栈中的信号上下文信息。有关详细信息,请参见sigreturn(2)。有关ucontext_t结构的更多信息,请参见getcontext(3)。通常,处理程序函数不使用第三个参数。
siginfo_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 Linux 2.6.32) */ void *si_lower; /* Lower bound when address violation occurred (since Linux 3.19) */ void *si_upper; /* Upper bound when address violation occurred (since Linux 3.19) */ int si_pkey; /* Protection key on PTE that caused fault (since Linux 4.6) */ void *si_call_addr; /* Address of system call instruction (since Linux 3.5) */ int si_syscall; /* Number of attempted system call (since Linux 3.5) */ unsigned int si_arch; /* Architecture of attempted system call (since Linux 3.5) */ }
为所有信号定义了si_signo,si_errno和si_code。 (si_errno在Linux上通常是未使用的。)结构的其余部分可能是一个并集,因此,应只读取对于给定信号有意义的字段:
- *
- 用kill(2)和sigqueue(3)发送的信号填充si_pid和si_uid。另外,用sigqueue(3)发送的信号将用信号发送者指定的值填充si_int和si_ptr。有关更多详细信息,请参见sigqueue(3)。
- *
- POSIX.1b计时器(自Linux 2.6起)发送的信号填充si_overrun和si_timerid。 si_timerid字段是内核用来标识计时器的内部ID。它与timer_create(2)返回的计时器ID不同。 si_overrun字段是计时器溢出计数;这与通过调用timer_getoverrun(2)获得的信息相同。这些字段是非标准的Linux扩展。
- *
- 发送给消息队列通知的信号(请参见mq_notify(3)中的SIGEV_SIGNAL的描述)将siigint_value值提供给mq_notify(3)填充si_int / si_ptr; si_pid,带有消息发送者的进程ID;和si_uid,以及消息发送者的真实用户ID。
- *
- SIGCHLD填充si_pid,si_uid,si_status,si_utime和si_stime,以提供有关子级的信息。 si_pid字段是子进程的ID。 si_uid是孩子的真实用户ID。 si_status字段包含子项的退出状态(如果si_code为CLD_EXITED)或导致进程更改状态的信号号。 si_utime和si_stime包含子进程使用的用户和系统CPU时间。这些字段不包括等待的孩子使用的时间(与getrusage(2)和times(2)不同)。在2.6及以下版本的内核中(从2.6.27开始),这些字段以sysconf(_SC_CLK_TCK)为单位报告CPU时间。在2.6.27之前的2.6内核中,一个错误意味着这些字段以(可配置)系统抖动的单位报告时间(请参见time(7))。
- *
- SIGILL,SIGFPE,SIGSEGV,SIGBUS和SIGTRAP用故障地址填充si_addr。在某些体系结构上,这些信号也填充si_trapno字段。
- SIGBUS的某些子错误,尤其是BUS_MCEERR_AO和BUS_MCEERR_AR,也填充si_addr_lsb。此字段指示报告的地址的最低有效位,因此指示损坏的程度。例如,如果整页已损坏,则si_addr_lsb包含log2(sysconf(_SC_PAGESIZE))。当响应ptrace(2)事件(PTRACE_EVENT_foo)传递SIGTRAP时,不会填充si_addr,但是会使用负责传递陷阱的相应进程ID和用户ID来填充si_pid和si_uid。对于seccomp(2),示踪将显示为传递事件。 BUS_MCEERR_ *和si_addr_lsb是特定于Linux的扩展。
- SIGSEGV的SEGV_BNDERR子错误填充si_lower和si_upper。
- SIGSEGV的SEGV_PKUERR子错误填充si_pkey。
- *
- SIGIO / SIGPOLL(这两个名称在Linux上是同义词)填充si_band和si_fd。 si_band事件是一个位掩码,其中包含与poll(2)在revents字段中填充的值相同的值。 si_fd字段指示发生了I / O事件的文件描述符;有关更多详细信息,请参见fcntl(2)中F_SETSIG的描述。
- *
- 当seccomp过滤器返回SECCOMP_RET_TRAP时生成的SIGSYS(从Linux 3.5开始),按照seccomp(2)中的描述填写si_call_addr,si_syscall,si_arch,si_errno和其他字段。
The si_code field
传递到SA_SIGINFO信号处理程序的siginfo_t参数内的si_code字段是一个值(不是位掩码),指示为什么发送此信号。对于ptrace(2)事件,si_code将包含SIGTRAP并在高字节中包含ptrace事件:
(SIGTRAP | PTRACE_EVENT_foo << 8).
对于非ptrace(2)事件,本节其余部分描述了si_code中可能出现的值。从glibc 2.20开始,大多数这些符号的定义是通过如下定义功能测试宏(包括任何头文件)获得的:
- *
- _XOPEN_SOURCE的值等于或大于500;
- *
- _XOPEN_SOURCE和_XOPEN_SOURCE_EXTENDED;要么
- *
- _POSIX_C_SOURCE的值等于或大于200809L。
对于TRAP_ *常量,仅在前两种情况下提供符号定义。在glibc 2.20之前,不需要功能测试宏即可获得这些符号。
对于常规信号,以下列表显示了可以为任何信号放置在si_code中的值,以及生成信号的原因。
可以将以下值放在SIGILL信号的si_code中:
- ILL_ILLOPC
- 非法操作码。
- ILL_ILLOPN
- 非法的操作数。
- ILL_ILLADR
- 非法寻址模式。
- ILL_ILLTRP
- 非法陷阱。
- ILL_PRVOPC
- 特权操作码。
- ILL_PRVREG
- 特权寄存器。
- ILL_COPROC
- 协处理器错误。
- ILL_BADSTK
- 内部堆栈错误。
可以将以下值放在si_code中以获取SIGFPE信号:
- FPE_INTDIV
- 整数除以零。
- FPE_INTOVF
- 整数溢出。
- FPE_FLTDIV
- 浮点除以零。
- FPE_FLTOVF
- 浮点溢出。
- FPE_FLTUND
- 浮点下溢。
- FPE_FLTRES
- 浮点数不精确的结果。
- FPE_FLTINV
- 浮点运算无效。
- FPE_FLTSUB
- 下标超出范围。
可以将以下值放在SIG_EGV信号的si_code中:
- SEGV_MAPERR
- 地址未映射到对象。
- SEGV_ACCERR
- 映射对象的权限无效。
- SEGV_BNDERR(since Linux 3.19)
- 地址绑定检查失败。
- SEGV_PKUERR(since Linux 4.6)
- 访问被内存保护键拒绝。参见pkeys(7)。可以通过si_pkey获得应用于此访问的保护密钥。
可以将以下值放在SIGBUS信号的si_code中:
- BUS_ADRALN
- 无效的地址对齐。
- BUS_ADRERR
- 不存在的物理地址。
- BUS_OBJERR
- 特定于对象的硬件错误。
- BUS_MCEERR_AR(since Linux 2.6.32)
- 机器检查消耗的硬件内存错误;需要采取的行动。
- BUS_MCEERR_AO(since Linux 2.6.32)
- 在处理中检测到但未消耗的硬件内存错误动作可选。
可以将以下值放在SIGTRAP信号的si_code中:
- TRAP_BRKPT
- 流程断点。
- TRAP_TRACE
- 进程跟踪陷阱。
- TRAP_BRANCH(since Linux 2.4, IA64 only))
- 过程采取分支陷阱。
- TRAP_HWBKPT(since Linux 2.4, IA64 only))
- 硬件断点/观察点。
可以将以下值放置在SIG_LD信号的si_code中:
- CLD_EXITED
- 儿童已退出。
- CLD_KILLED
- 孩子被杀了。
- CLD_DUMPED
- 儿童异常终止。
- CLD_TRAPPED
- 被追踪的孩子被困。
- CLD_STOPPED
- 孩子已停止。
- CLD_CONTINUED(since Linux 2.6.9)
- 被阻止的孩子仍在继续。
对于SIGIO / SIGPOLL信号,可以在si_code中放置以下值:
- POLL_IN
- 可用数据输入。
- POLL_OUT
- 可用的输出缓冲区。
- POLL_MSG
- 输入消息可用。
- POLL_ERR
- I / O错误。
- POLL_PRI
- 高优先级输入可用。
- POLL_HUP
- 设备已断开连接。
可以将以下值放在si_code中以获取SIGSYS信号:
- SYS_SECCOMP(since Linux 3.5)
- 由seccomp(2)过滤规则触发。
返回值
sigaction()成功返回0;如果出错,则返回-1,并且将errno设置为指示错误。
错误说明
- EFAULT
- act或oldact指向不是进程地址空间有效部分的内存。
- EINVAL
- 指定了无效的信号。如果试图更改SIGKILL或SIGSTOP的操作,也将生成此错误,而不能捕获或忽略该操作。
遵循规范
POSIX.1-2001,POSIX.1-2008,SVr4。
备注
通过fork(2)创建的子级继承其父级信号处置的副本。在execve(2)期间,已处理信号的处理将重置为默认值;被忽略信号的配置保持不变。
根据POSIX,在忽略不由kill(2)或raise(3)生成的SIGFPE,SIGILL或SIGSEGV信号之后,进程的行为是不确定的。整数除以零将产生不确定的结果。在某些架构上,它将生成SIGFPE信号。 (也将最负的整数除以-1可能会生成SIGFPE。)忽略此信号可能会导致无限循环。
POSIX.1-1990不允许将SIGCHLD的操作设置为SIG_IGN。 POSIX.1-2001和更高版本允许这种可能性,因此可以忽略SIGCHLD来防止创建僵尸(请参阅wait(2))。但是,过去忽略SIGCHLD的BSD和System V行为是不同的,因此确保终止的子代不会成为僵尸的唯一完全可移植的方法是捕获SIGCHLD信号并执行wait(2)或类似操作。
POSIX.1-1990仅指定了SA_NOCLDSTOP。 POSIX.1-2001添加了SA_NOCLDSTOP,SA_NOCLDWAIT,SA_NODEFER,SA_ONSTACK,SA_RESETHAND,SA_RESTART和SA_SIGINFO。在sa_flags中使用这些后面的值在用于较早UNIX实现的应用程序中可能不太容易移植。
SA_RESETHAND标志与相同名称的SVr4标志兼容。
在内核1.3.9及更高版本中,SA_NODEFER标志与同名的SVr4标志兼容。在较早的内核上,Linux实现允许接收任何信号,而不仅仅是我们正在安装的信号(有效地覆盖任何sa_mask设置)。
可以使用NULL第二个参数调用sigaction()来查询当前信号处理程序。通过使用NULL第二和第三个参数调用给定信号,它也可以用于检查给定信号对于当前机器是否有效。
无法阻止SIGKILL或SIGSTOP(通过在sa_mask中指定它们)。这样做的尝试被默默忽略。
有关操纵信号集的详细信息,请参见sigsetops(3)。
有关可从信号处理程序内部安全调用的异步信号安全函数的列表,请参见signal-safety(7)。
C library/kernel differences
尝试更改NPTL线程实现内部使用的两个实时信号的配置时,sigaction()的glibc包装函数给出错误(EINVAL)。有关详细信息,请参见nptl(7)。
在信号蹦床驻留在C库中的体系结构上,sigaction()的glibc包装函数将蹦床代码的地址放置在act.sa_restorer字段中,并在act.sa_flags字段中设置SA_RESTORER标志。参见sigreturn(2)。
最初的Linux系统调用名为sigaction()。但是,在Linux 2.2中添加了实时信号后,该系统调用支持的固定大小的32位sigset_t类型不再适合此目的。因此,添加了新的系统调用rt_sigaction()以支持扩展的sigset_t类型。新的系统调用采用第四个参数size_t sigsetsize,它指定act.sa_mask和oldact.sa_mask中信号集的大小(以字节为单位)。当前需要此参数具有sizeof(sigset_t)值(或错误EINVAL结果)。 glibc sigaction()包装函数对我们隐藏了这些细节,在内核提供时透明地调用rt_sigaction()。
Undocumented
在引入SA_SIGINFO之前,还可以获得有关信号的一些其他信息。这是通过为sa_handler信号处理程序提供结构sigcontext类型的第二个参数来完成的,该参数与在ucontext结构的uc_mcontext字段中传递的结构(通过指针)在第三个参数中传递的结构相同。 sa_sigaction处理程序。有关详细信息,请参见相关的Linux内核资源。现在,这种用法已经过时了。
BUGS
当使用SA_SIGINFO处理程序传递信号时,内核并不总是为siginfo_t中与该信号相关的所有字段提供有意义的值。
在2.6.13及以下版本的内核中,在sa_flags中指定SA_NODEFER不仅可以防止在处理程序执行期间屏蔽传递的信号,而且还可以防止在sa_mask中指定的信号。此错误已在内核2.6.14中修复。
示例
请参见mprotect(2)。
另外参见
kill(1),kill(2),pause(2),pidfd_send_signal(2),restart_syscall(2),seccomp(2),sigaltstack(2),signal(2),signalfd(2),sigpending(2), sigprocmask(2),sigreturn(2),sigsuspend(2),wait(2),killpg(3),raise(3),siginterrupt(3),sigqueue(3),sigsetops(3),sigvec(3),核心(5),信号(7)
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。