Reputation: 19452
How can I cancel a sent signal to a process which is still not delivered?
Consider the scenario where I have sent a signal to a process, but the process was in un-interruptible state.
I am doing a conditional wait for the signal to be handled. But since it did not I want to continue executing further. In that case, is there a way that I can cancel the sent signal(it is not yet delivered)
Upvotes: 4
Views: 3827
Reputation: 21213
A pending signal is canceled if that signal is ignored before the signal is delivered. You just have to ignore the signal. You can do this with sigaction()
by setting the sa_handler
field in struct sigaction
to SIG_IGN
.
Here's some example code that illustrates this and shows that it works. The code does the following:
SIGINT
so that we have a window of time to send it SIGINT
when it is blocked - this will generate a pending SIGINT
that will be delivered when the process signal mask is changed to a mask that does not include SIGINT
(and will be canceled if the signal is ignored).SIGINT
SIGINT
after knowing that a SIGINT
is pending. This has the effect of canceling the pending signal.SIGINT
, which is to terminate the processSIGINT
.You can see that the process does not terminate after step 5 and waits for your input, which means that the pending signal was canceled.
Here's the code that illustrates this:
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void) {
sigset_t block_sigint, prev_mask;
sigemptyset(&block_sigint);
sigaddset(&block_sigint, SIGINT);
if (sigprocmask(SIG_SETMASK, &block_sigint, &prev_mask) < 0) {
perror("Couldn't block SIGINT");
return 0;
}
printf("SIGINT blocked: kill -SIGINT %ld to generate a pending SIGINT. Press return when done.\n", (long) getpid());
/* Now, open a new terminal and send SIGINT to this process.
*
* After doing that, the signal will be pending delivery because it is currently blocked.
*
* Now, if we ignore SIGINT, the pending signal will be cancelled
*/
getchar();
struct sigaction ign_sigint, prev;
ign_sigint.sa_handler = SIG_IGN;
ign_sigint.sa_flags = 0;
sigemptyset(&ign_sigint.sa_mask);
if (sigaction(SIGINT, &ign_sigint, &prev) < 0) {
perror("Couldn't ignore SIGINT");
return 0;
}
printf("SIGINT ignored - pending SIGINT was canceled.\n");
/* Now, restore the default action for SIGINT */
if (sigaction(SIGINT, &prev, NULL) < 0) {
perror("Couldn't restore default SIGINT behavior");
return 0;
}
/* And also restore the process's original sigmask, which does not block SIGINT */
if (sigprocmask(SIG_SETMASK, &prev_mask, NULL) < 0) {
perror("Couldn't restore original process sigmask");
return 0;
}
printf("Process sigmask and action for SIGINT are now restored\n");
/* We will not receive SIGINT at this point because it was canceled
* So the process will block on getchar() here instead of terminating
*/
getchar();
return 0;
}
Upvotes: 15