I am learning about the use of signals in C via the use of sigaction
. While doing my own exercise, I am trying to first block the signals (SIGINT and SIGQUIT) then unblock them later.
In my terminal output, in the for-loop in which the signals are block, if I attempted to hit Ctrl C or Ctrl , it is still printing out statements as follow, however after it is unblock, it is not printing out the contents in the second for-loop.
(block) working ....
(block) working ....
^C(block) working ....
(block) working ....
^\(block) working ....
The work is done, now you can ...
However, if I do not attempt to hit either Ctrl C or Ctrl \ during the program execution in the first for-loop, the second for-loop will then be printed out.
(block) working ....
(block) working ....
(block) working ....
(block) working ....
(block) working ....
The work is done, now you can ...
(unblock) working ....
(unblock) working ....
(unblock) working ....
(unblock) working ....
(unblock) working ....
The expected outcome I am hoping to achieve is something as follows:
(block) working ....
(block) working ....
^C(block) working ....
(block) working ....
^\(block) working ....
The work is done, now you can ...
(unblock) working ....
^C
in which I can try hitting in multiple Ctrl C or Ctrl \ times during the first for-loop, then hitting either signals will terminate the command when it goes into the second for-loop.
Here is my code:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int i;
sigset_t sigs, sigs2;
sigemptyset(&sigs);
sigaddset(&sigs, SIGINT);
sigaddset(&sigs, SIGQUIT);
sigprocmask(SIG_SETMASK, &sigs, NULL); // tried with SIGBLOCK, same issues
for (i=0; i<5; i)
{
printf("(block) working ....\n");
sleep (1);
}
printf("The work is done, now you can ...\n");
// unblock signals
sigprocmask(SIG_UNBLOCK, &sigs, NULL);
for (int j=0; j<5; j)
{
printf("(unblock) working ....\n");
sleep (1);
}
exit(0);
}
Appreciate in advance for any insights.
CodePudding user response:
Blocking a signal is not the same thing as ignoring it. If a signal is sent to a process while that signal is blocked for that process then it remains pending until such time as the signal is unblocked or the process terminates.
That is exactly what you observe. You deliver a SIGINT
and a SIGQUIT
to your process while those are blocked. One is delivered immediately after they are unblocked, terminating the process before the second loop is entered.
Which one is actually delivered (first) is unspecified, but if one had a handler registered, so that it did not terminate the process, then it would be possible for both to be delivered, and even for a handler for the first received to be interrupted by receipt of the second.
However, multiples of the same regular signal do not queue. For example, no matter how many SIGQUIT
s you send while that signal is blocked, no more than one will be waiting to be delivered when that signal is unblocked.
CodePudding user response:
Adding to John Bollinger's answer, as he suggests what you want to do here is ignore the signals, not just block them. You can use sigaction
for this, setting the handler for SIGINT
and SIGQUIT
to SIG_IGN
(ignore) and then setting it back to SIG_DFL
(default handler).
Here's a simple example:
#define _POSIX_C_SOURCE 1
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
int i;
struct sigaction sa = { .sa_handler = SIG_IGN };
if (sigaction(SIGINT, &sa, NULL) == -1) {
perror("sigaction(SIGINT, SIG_IGN) failed");
return 1;
}
if (sigaction(SIGQUIT, &sa, NULL) == -1) {
perror("sigaction(SIGQUIT, SIG_IGN) failed");
return 1;
}
for (i = 0; i < 5; i) {
printf("(ignore) working ....\n");
sleep(1);
}
printf("The work is done, now you can ...\n");
sa.sa_handler = SIG_DFL;
if (sigaction(SIGINT, &sa, NULL) == -1) {
perror("sigaction(SIGINT, SIG_DFL) failed");
return 1;
}
if (sigaction(SIGQUIT, &sa, NULL) == -1) {
perror("sigaction(SIGQUIT, SIG_DFL) failed");
return 1;
}
for (i = 0; i < 5; i) {
printf("(un-ignore) working ....\n");
sleep(1);
}
return 0;
}
The above example is trivial, but note that in a general scenario you should use the third argument of sigaction
to save the current struct sigaction
for the signal which you are modifying so that you can later restore it instead of resetting it to SIG_DFL
.