I am trying to understand the signals in POSIX/Linux. I wrote this test.c
program:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void handler(int signum) {
printf("\nGoodbye!\n"); exit(0);
}
int main() {
struct sigaction sa = { .sa_handler = handler };
// Intercept SIGINT
sigemptyset(&sa.sa_mask);
if (sigaction(SIGINT, &sa, NULL) == -1) {
perror("sigaction"); exit(EXIT_FAILURE);
}
signal(SIGUSR1, SIG_IGN); // Ignore SIGUSR1
// Block SIGUSR2
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR2);
sigprocmask(SIG_BLOCK, &mask, NULL);
// Simulate work for 10 seconds
for (int i = 0; i < 10; i++) {
printf("Working... %d\n", i);
sleep(1);
}
sigprocmask(SIG_UNBLOCK, &mask, NULL);
}
During the execution, I send:
kill -s USR2 $(pgrep test)
Then quickly after that:
cat /proc/`pgrep test`/status | grep Sig
SigQ: 1/256970
SigPnd: 0000000000000000
SigBlk: 0000000000000800
SigIgn: 0000000000000200
SigCgt: 0000000000000002
SigCgt
shows me that SIGINT
is intercepted, SigIgn
shows that SIGUSR1
is ignored and SigBlk
shows that SIGUSR2
is blocked.
In my understanding, sending a signal to a process that is blocked by the process will be pending until the unblock. However I don't see any effect on SigPnd
Any explanation?
You need to look at ShdPnd
(signals pending directed to the whole process), not SigPnd
(signals pending directed to that specific thread):
$ kill -s USR2 $(pgrep test)
$ cat /proc/`pgrep test`/status | grep -E 'Sig|Shd'
SigQ: 1/256970
SigPnd: 0000000000000000
ShdPnd: 0000000000000800
SigBlk: 0000000000000800
SigIgn: 0000000000000200
SigCgt: 0000000000000002
The kill
command uses the kill
syscall, which directs the signal to the whole process. To have a signal appear in SigPnd
in /proc/PID/status
you would have to direct it specifically to the main thread using the tgkill
syscall (not sure if there is a command that can do this for you).