学习之Linux学习

linux手册翻译——sigaction(2)

2021-06-12  本文已影响0人  蟹蟹宁

\color{#A00000}{NAME}
sigaction, rt_sigaction - 检查和修改信号的Action(这里的Action语义同signal(7)中的disposition)

\color{#A00000}{SYNOPSIS}

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

\color{#A00000}{DESCRIPTION}
sigaction() 系统调用用于更改进程在接收到特定信号时采取的Action。 (有关信号的概述,请参阅我翻译的signal手册
参数 signum 指定信号,可以是除 SIGKILL 和 SIGSTOP 之外的任何有效信号。
如果参数 act 非空,那么将通过 act 指定具体的信号处理动作(区别于信号处理函数),如果参数 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

sa_restorer 字段不适用于应用程序。(POSIX 没有指定 sa_restorer 字段。)可以在 sigreturn(2) 中找到有关此字段用途的更多详细信息。

sa_handler

sa_handler 指定要与 signum 关联的Action,并且是以下之一:

sa_sigaction

如果在sa_flags 中指定了SA_SIGINFO,则sa_sigaction(而不是sa_handler)指定signum 的信号处理函数。 该函数接收三个参数,如下所述。

sa_mask

sa_mask 指定在信号处理程序执行期间应该被阻塞的信号掩码(即,添加到调用信号处理程序的线程的信号掩码中)。 此外,触发处理程序的信号将被阻塞,除非使用 SA_NODEFER 标志。

sa_flags

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

SA_SIGINFO 处理程序的 siginfo_t 参数

当在 act.sa_flags 中指定 SA_SIGINFO 标志时,信号处理程序地址通过 act.sa_sigaction 字段传递。 此处理程序采用三个参数,如下所示:

void handler(int sig, siginfo_t *info, void *ucontext)
{
      ...
}

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 */
    union sigval 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 上通常不使用。)结构的其余部分可能是联合,因此应该只读取对给定信号有意义的字段:

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 开始,大多数这些符号的定义是通过定义功能测试宏(在包含任何头文件之前)从 <signal.h> 获得的,如下所示:

对于 TRAP_* 常量,仅在前两种情况下提供符号定义。 在 glibc 2.20 之前,不需要特性测试宏来获取这些符号。

对于常规信号,以下列表显示了可以放置在任何信号的 si_code 中的值,以及生成信号的原因:
si_code 原因
SI_USER kill(2).
SI_KERNEL Sent by the kernel.
SI_QUEUE sigqueue(3).
SI_TIMER POSIX timer expired.
SI_MESGQ (since Linux 2.6.6) POSIX message queue state changed; see mq_notify(3).
SI_ASYNCIO AIO completed.
SI_SIGIO Queued SIGIO (only in kernels up to Linux 2.2; from Linux 2.4 onward SIGIO/SIGPOLL fills in si_code as described below).
SI_TKILL (since Linux 2.4.19) tkill(2) or tgkill(2).
可以在 si_code 中为 SIGILL 信号放置以下值:
si_code 原因
ILL_ILLOPC Illegal opcode.
ILL_ILLOPN Illegal operand.
ILL_ILLADR Illegal addressing mode.
ILL_ILLTRP Illegal trap.
ILL_PRVOPC Privileged opcode.
ILL_PRVREG Privileged register.
ILL_COPROC Coprocessor error.
ILL_BADSTK Internal stack error
可以在 si_code 中为 SIGFPE 信号放置以下值:
si_code 原因
FPE_INTDIV Integer divide by zero.
FPE_INTOVF Integer overflow.
FPE_FLTDIV Floating-point divide by zero.
FPE_FLTOVF Floating-point overflow.
FPE_FLTUND Floating-point underflow.
FPE_FLTRES Floating-point inexact result.
FPE_FLTINV Floating-point invalid operation.
FPE_FLTSUB Subscript out of range.
可以在 si_code 中为 SIGSEGV 信号放置以下值:
si_code 原因
SEGV_MAPERR Address not mapped to object.
SEGV_ACCERR Invalid permissions for mapped object.
SEGV_BNDERR (since Linux 3.19) Failed address bound checks.
SEGV_PKUERR (since Linux 4.6) Access was denied by memory protection keys. See pkeys(7). The protection key which applied to this access is available via si_pkey.
可以在 si_code 中为 SIGBUS 信号放置以下值:
si_code 原因
BUS_ADRALN Invalid address alignment.
BUS_ADRERR Nonexistent physical address.
BUS_OBJERR Object-specific hardware error.
BUS_MCEERR_AR (since Linux 2.6.32) Hardware memory error consumed on a machine check;action required.
BUS_MCEERR_AO (since Linux 2.6.32) Hardware memory error detected in process but not consumed; action optional.
可以在 si_code 中为 SIGTRAP 信号放置以下值:
si_code 原因
TRAP_BRKPT Process breakpoint.
TRAP_TRACE Process trace trap.
TRAP_BRANCH (since Linux 2.4, IA64 only) Process taken branch trap.
TRAP_HWBKPT (since Linux 2.4, IA64 only) Hardware breakpoint/watchpoint.
可以在 si_code 中为 SIGCHLD 信号放置以下值:
si_code 原因
CLD_EXITED Child has exited.
CLD_KILLED Child was killed.
CLD_DUMPED Child terminated abnormally.
CLD_TRAPPED Traced child has trapped.
CLD_STOPPED Child has stopped.
CLD_CONTINUED (since Linux 2.6.9) Stopped child has continued.
可以在 si_code 中为 SIGIO/SIGPOLL 信号放置以下值:
si_code 原因
POLL_IN Data input available.
POLL_OUT Output buffers available.
POLL_MSG Input message available.
POLL_ERR I/O error.
POLL_PRI High priority input available.
POLL_HUP Device disconnected.
可以在 si_code 中为 SIGSYS 信号放置以下值:
si_code 原因
SYS_SECCOMP (since Linux 3.5)Triggered by a seccomp(2) filter rule.

\color{#A00000}{NOTES}
通过 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))。然而,历史上 BSD 和 System V 忽略 SIGCHLD 的行为是不同的,因此确保终止的子进程不会变成僵尸的唯一完全可移植的方法是捕获 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。在用于旧 UNIX 实现的应用程序中,在 sa_flags 中使用这些后面的值可能不太容易移植。

SA_RESETHAND 标志与同名的 SVr4 标志兼容。

SA_NODEFER 标志与内核 1.3.9 及更高版本下的同名 SVr4 标志兼容。在较旧的内核上,Linux 实现允许接收任何信号,而不仅仅是我们正在安装的信号(有效地覆盖任何 sa_mask 设置)。

可以使用 NULL 第二个参数调用 sigaction() 以查询当前信号处理程序。它还可以用于检查给定信号是否对当前机器有效,方法是使用 NULL 第二和第三个参数调用它。

无法阻止 SIGKILL 或 SIGSTOP(通过在 sa_mask 中指定它们)。这样做的尝试会被默默地忽略。
有关操作信号集的详细信息,请参阅 sigsetops(3)。

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

C 库/内核差异

sigaction() 的 glibc 包装函数在尝试更改 NPTL 线程实现内部使用的两个实时信号的处置时给出错误 (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()。

上一篇 下一篇

猜你喜欢

热点阅读