簡體   English   中英

sys_rt_sigreturn 中的信號掩碼是如何設置的?

[英]How is the signal mask set in sys_rt_sigreturn?

我有以下 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的第三個參數給出的結果,它代表舊的信號掩碼)? 由於一開始它被設置為空,我找不到任何其他系統調用更改掩碼。

我猜想可能是 kernel 在某個時候更改了這個掩碼,也許它會在某些情況下這樣做,例如,像 kernel 這樣的東西在線程進入信號處理程序時添加sigaction指定的掩碼,並在sigreturn中恢復它們。 但是相關的參考資料太難找了。

有人可以就此提供任何建議嗎? 提前致謝。

您所看到的是 pthread 庫的內部工作原理。 換句話說,不是 kernel 負責在信號掩碼中添加/刪除這些信號,而是 pthread 庫。 pthread 庫在內部使用實時信號來管理線程。 strace將它們顯示為RT_n 它們被添加到掩碼中/從掩碼中移除的事實不應該讓您擔心。

在“實時信號”部分的man 7 signal中找到有關實時信號的更多信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM