学习之Linux学习

linux手册翻译——sigaltstack(2)

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

\color{#A00000}{NAME}
sigaltstack - set or/and get 信号的堆栈上下文

\color{#A00000}{SYNOPSIS}

       #include <signal.h>
       int sigaltstack(const stack_t *restrict ss, stack_t *restrict old_ss);

       Feature Test Macro Requirements for glibc (see
       feature_test_macros(7)):

       sigaltstack():
           _XOPEN_SOURCE >= 500
               || /* Since glibc 2.12: */ _POSIX_C_SOURCE >= 200809L
               || /* Glibc <= 2.19: */ _BSD_SOURCE

\color{#A00000}{DESCRIPTION}
sigaltstack() 允许线程定义新的备用信号堆栈和/或获取现有备用信号堆栈的状态。如果信号处理程序的建立(请参阅 sigaction(2))指定使用备用堆栈,即设置了SA_ONSTACK参数,则在信号处理程序的执行期间使用备用信号堆栈。
使用备用信号堆栈的一般步骤如下:

  1. 分配一块内存区域用于备用信号堆栈。
  2. 使用 sigaltstack() 通知系统备用信号堆栈的存在和位置。
  3. 使用 sigaction(2) 建立信号处理程序时,通过指定 SA_ONSTACK 标志通知系统应在备用信号堆栈上执行信号处理程序。

ss 参数用于指定新的备用信号堆栈,而 old_ss 参数用于获取有关当前建立的信号堆栈的信息。如果我们只对执行其中一项任务感兴趣,则可以将另一个参数指定为 NULL。

stack_t 类型定义如下:

           typedef struct {
               void  *ss_sp;     /* Base address of stack */
               int    ss_flags;  /* Flags */
               size_t ss_size;   /* Number of bytes in stack */
           } stack_t;

ss.ss_flags

此字段包含 0 或以下标志,此字段也是必须要配置的,起码要是0,否则将会备用栈配置会无效

ss.ss_sp

该字段指定堆栈的起始地址。 当在备用堆栈上调用信号处理程序时,内核会自动将 ss.ss_sp 中给出的地址与底层硬件架构的合适地址边界对齐。

ss.ss_size

此字段指定堆栈的大小。 常量 SIGSTKSZ(8KB)定义了足够满足信号堆栈的通常大小要求的栈空间大小,常量 MINSIGSTKSZ(2KB)定义执行信号处理程序所需的最小大小。

要禁用现有备用信号堆栈,请将 ss.ss_flags 指定为 SS_DISABLE。 在这种情况下,内核会忽略 ss.ss_flags 中的任何其他标志以及 ss 中的其余字段。即若ss.ss_flags指定了SS_DISABLE,那么就停用备用信号堆栈

如果 old_ss 不为 NULL,则它用于返回有关在调用 sigaltstack() 之前生效的备用信号堆栈的信息。 old_ss.ss_sp 和 old_ss.ss_size 字段返回该堆栈的起始地址和大小。 old_ss.ss_flags 可能返回以下任一值:

通过将 ss 指定为 NULL,并将 old_ss 指定为非 NULL 值,可以获得备用信号堆栈的当前设置而无需更改它们。
\color{#A00000}{RETURN VALUE}
sigaltstack() 成功时返回 0,失败时返回 -1,并设置 errno 以指示错误。

\color{#A00000}{ERRORS}
EFAULT
ss 或 old_ss 不为 NULL 并指向进程地址空间之外的区域。

EINVAL
ss 不是 NULL 并且 ss_flags 字段包含无效标志。

ENOMEM
新备用信号堆栈 ss.ss_size 的指定大小小于 MINSIGSTKSZ。

EPERM
尝试在备用信号堆栈处于活动状态时更改它(即,线程已经在当前备用信号堆栈上执行)。

\color{#A00000}{ATTRIBUTES}

Interface Attribute Value
sigaltstack() Thread safety MT-Safe

\color{#A00000}{NOTES}
备用信号堆栈最常见的用法是处理标准堆栈可用空间耗尽时生成的 SIGSEGV 信号:在这种情况下,无法在标准堆栈上调用 SIGSEGV 的信号处理程序;如果我们想处理它,我们必须使用备用信号堆栈。
如果线程可能耗尽其标准堆栈,则建立备用信号堆栈很有用。堆栈增长得太大以至于遇到向上增长的堆,或者它达到了调用 setrlimit(RLIMIT_STACK, &rlim) 设置的限制,都意味着标准的堆栈被用尽,此时内核会向线程发送一个 SIGSEGV 信号。在这些情况下,捕获此信号的唯一方法是在备用信号堆栈上。

在 Linux 支持的大多数硬件架构上,堆栈向下增长。 sigaltstack() 自动考虑堆栈增长的方向。

从在备用信号堆栈上执行的信号处理程序时调用的函数或者触发新的信号处理函数都将使用备用信号堆栈。与标准堆栈不同,系统不会自动扩展备用信号堆栈。超过备用信号堆栈的分配大小将导致不可预测的结果。

成功调用 execve(2) 会删除任何现有的备用信号堆栈。通过 fork(2) 或clone(2)创建的子进程继承其父进程的备用信号堆栈设置的副本。但是对于clone(2)创建的线程,将禁用在父进程中建立的任何备用信号堆栈。

sigaltstack() 取代了旧的 sigstack() 调用。为了向后兼容,glibc 还提供了 sigstack()。所有新应用程序都应使用 sigaltstack() 编写。历史 4.2BSD 有一个 sigstack() 系统调用。它使用了一个稍微不同的结构,主要的缺点是调用者必须知道堆栈增长的方向。

\color{#A00000}{BUGS}
在 Linux 2.2 及更早版本中,唯一可以在 ss.sa_flags 中指定的标志是 SS_DISABLE。 在 Linux 2.4 内核发布之前,进行了更改以允许 sigaltstack() 允许 ss.ss_flags==SS_ONSTACK 具有与 ss.ss_flags==0 相同的含义(即,将 SS_ONSTACK 包含在 ss .ss_flags 是空操作)。 在其他实现中,根据 POSIX.1,SS_ONSTACK 仅作为 old_ss.ss_flags 中的报告标志出现。 在 Linux 上,没有必要在 ss.ss_flags 中指定 SS_ONSTACK,并且确实应该出于可移植性考虑避免这样做:如果 SS_ONSTACK 在 ss.ss_flags 中指定,则其他各种系统都会出错。

\color{#A00000}{EXAMPLES}
以下代码段演示了如何使用 sigaltstack()(和 sigaction(2))来安装备用信号堆栈,该堆栈由 SIGSEGV 信号的处理程序使用:

           stack_t ss;

           ss.ss_sp = malloc(SIGSTKSZ);
           if (ss.ss_sp == NULL) {
               perror("malloc");
               exit(EXIT_FAILURE);
           }

           ss.ss_size = SIGSTKSZ;
           ss.ss_flags = 0;
           if (sigaltstack(&ss, NULL) == -1) {
               perror("sigaltstack");
               exit(EXIT_FAILURE);
           }

           sa.sa_flags = SA_ONSTACK;
           sa.sa_handler = handler();      /* Address of a signal handler */
           sigemptyset(&sa.sa_mask);
           if (sigaction(SIGSEGV, &sa, NULL) == -1) {
               perror("sigaction");
               exit(EXIT_FAILURE);
           }
上一篇 下一篇

猜你喜欢

热点阅读