【问题标题】:How is the signal mask set in sys_rt_sigreturn?sys_rt_sigreturn 中的信号掩码是如何设置的?
【发布时间】:2020-10-02 01:38:27
【问题描述】:

我有一个下面的 C 程序,比如signal.c:

#define _GNU_SOURCE

#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

static void *func(void *arg) {
    sleep(3);
}

int main(void) {
    pthread_t td;

    pthread_create(&td, 0, func, NULL);
    pthread_cancel(td);
    pthread_join(td, NULL);

    return 0;
}

程序是用musl-gcc编译的,也就是说它使用了musl-libc。

我想知道这个程序使用的系统调用实际上是如何工作的,所以我用strace检查了这个程序,主要结果是:

[pid 14736] execve("./signal", ["./signal"], 0x55b68a817448 /* 72 vars */) = 0
[pid 14736] arch_prctl(ARCH_SET_FS, 0x603118) = 0
[pid 14736] set_tid_address(0x603330)   = 14736
[pid 14736] rt_sigprocmask(SIG_UNBLOCK, [RT_1 RT_2], NULL, 8) = 0
[pid 14736] mmap(NULL, 143360, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa528201000
[pid 14736] mprotect(0x7fa528203000, 135168, PROT_READ|PROT_WRITE) = 0
[pid 14736] rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [], 8) = 0
[pid 14736] clone(child_stack=0x7fa528223ed8, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID|0x400000, parent_tidptr=0x7fa528223f58, tls=0x7fa528223f20, child_tidptr=0x603330) = 14737
[pid 14736] rt_sigprocmask(SIG_SETMASK, [], strace: Process 14737 attached
NULL, 8) = 0
[pid 14737] rt_sigprocmask(SIG_SETMASK, [],  <unfinished ...>
[pid 14736] rt_sigaction(SIGRT_1, {sa_handler=0x40055e, sa_mask=~[], sa_flags=SA_RESTORER|SA_RESTART|SA_SIGINFO, sa_restorer=0x401820},  <unfinished ...>
[pid 14737] <... rt_sigprocmask resumed> NULL, 8) = 0
[pid 14736] <... rt_sigaction resumed> NULL, 8) = 0
[pid 14737] nanosleep({tv_sec=3, tv_nsec=0},  <unfinished ...>
[pid 14736] tkill(14737, SIGRT_1 <unfinished ...>
[pid 14737] <... nanosleep resumed> {tv_sec=2, tv_nsec=999998914}) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
[pid 14736] <... tkill resumed> )       = 0
[pid 14737] --- SIGRT_1 {si_signo=SIGRT_1, si_code=SI_TKILL, si_pid=14736, si_uid=1000} ---
[pid 14736] futex(0x7fa528223f60, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
[pid 14737] tkill(14737, SIGRT_1)       = 0
[pid 14737] rt_sigreturn({mask=[RT_1]}) = -1 EINTR (Interrupted system call)
[pid 14737] rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [RT_1], 8) = 0
[pid 14737] futex(0x7fa528223f60, FUTEX_WAKE_PRIVATE, 1) = 1
[pid 14736] <... futex resumed> )       = 0
[pid 14737] exit(0 <unfinished ...>
[pid 14736] futex(0x603330, FUTEX_WAIT, 14737, NULL <unfinished ...>
[pid 14737] <... exit resumed>)         = ?
[pid 14736] <... futex resumed> )       = 0
[pid 14737] +++ exited with 0 +++
[pid 14736] munmap(0x7fa528201000, 143360) = 0
[pid 14736] exit_group(0)               = ?
[pid 14736] +++ exited with 0 +++

让我困惑的是sigreturn设置的面具,你可以看到它是[RT_1]。据我了解,sigreturn会在被信号中断之前恢复线程的掩码。但是我们可以发现sigprocmask设置的掩码只是一个空集。关注以下结果:

[pid 14737] rt_sigprocmask(SIG_SETMASK, [],  <unfinished ...>
[pid 14736] rt_sigaction(SIGRT_1, {sa_handler=0x40055e, sa_mask=~[], sa_flags=SA_RESTORER|SA_RESTART|SA_SIGINFO, sa_restorer=0x401820},  <unfinished ...>
[pid 14737] <... rt_sigprocmask resumed> NULL, 8) = 0
[pid 14736] <... rt_sigaction resumed> NULL, 8) = 0
[pid 14737] nanosleep({tv_sec=3, tv_nsec=0},  <unfinished ...>
[pid 14736] tkill(14737, SIGRT_1 <unfinished ...>
[pid 14737] <... nanosleep resumed> {tv_sec=2, tv_nsec=999998914}) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
[pid 14736] <... tkill resumed> )       = 0
[pid 14737] --- SIGRT_1 {si_signo=SIGRT_1, si_code=SI_TKILL, si_pid=14736, si_uid=1000} ---
[pid 14736] futex(0x7fa528223f60, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
[pid 14737] tkill(14737, SIGRT_1)       = 0
[pid 14737] rt_sigreturn({mask=[RT_1]}) = -1 EINTR (Interrupted system call)
[pid 14737] rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [RT_1], 8) = 0

换句话说,我不能理解的一点是,掩码怎么会是[RT_1](根据rt_sigprocmask的第三个参数给出的结果,代表旧的信号掩码)?由于一开始它被设置为空,我找不到任何其他系统调用更改掩码。

我猜可能是内核在某个时候改变了这个掩码,也许它会在某些情况下这样做,例如,当一个线程进入信号处理程序时,内核添加了sigaction指定的掩码,并且在sigreturn 中恢复它们。但是相关的参考资料太难找了。

有人可以就此提供任何建议吗?提前致谢。

【问题讨论】:

    标签: c linux-kernel pthreads signals


    【解决方案1】:

    您看到的是 pthread 库的内部工作原理。换句话说,负责在信号掩码中添加/删除这些信号的不是内核,而是 pthread 库。 pthread 库在内部使用实时信号来管理线程。 strace 将它们显示为 RT_n。它们被添加到掩码中/从掩码中移除的事实不应该让您担心。

    在“实时信号”部分的man 7 signal 上查找有关实时信号的更多信息。

    【讨论】:

    • 感谢您的回复! pthread 库仍然在用户空间下执行,因此(可能)它只能通过一些系统调用来更改掩码,具体来说,我认为应该类似于sigprocmaskrt_sigprocmask。但是当掩码发生变化时,我就是找不到这样的系统调用。这就是我怀疑是内核导致了这种变化的原因。所以我想知道什么情况会导致内核做这样的改变?例如内核在进入信号处理器时会将sigaction指定的信号添加到掩码中,并在sigreturn中恢复。
    • @function2 正如我所说,pthread 库可以满足它的需要。 sigreturn 必须恢复用户设置的信号掩码,pthread 库发生的只是它还希望将 RT_1 添加到该掩码出于实现定义的原因。你不必担心。你需要担心的是,如果你看到 sigreturn add 例如 SIGUSR1 而你没有在面具上。
    猜你喜欢
    • 1970-01-01
    • 2012-11-04
    • 1970-01-01
    • 2018-10-19
    • 1970-01-01
    • 1970-01-01
    • 2014-08-05
    • 1970-01-01
    • 2019-01-22
    相关资源
    最近更新 更多