我有一个下面的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
. 但是相关的参考资料对我来说太难找了。
谁能给点建议?先谢谢大家了。
你看到的是pthread库的内部工作。换句话说,不是内核负责从信号掩码中添加和删除这些信号,而是pthread库。实时信号是由pthread库在内部用来管理线程的。strace
pthread库将它们显示为 RT_n
. 事实上,它们从掩模中被添加或删除的事实不应该让你担心。
关于实时信号的更多信息,请访问 man 7 signal
在 "实时信号 "部分。