I was doing a little reading about sigaction()
(sources are from my course notes) and I'm not sure I understand this text:
The signal mask is calculated and installed only for the duration of the signal handler.
By default, the signal “sig” is also blocked when the signal occurs.
Once an action is installed for a specific signal using sigaction, it remains installed until another action is explicitly requested.
Does this mean that the default signal mask is restored after returning form the signal handler?
Also, do I have to re-install the handler after using it, as if I was using signal()
?
Also, there's this piece of code:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void termination_handler(int signum) {
exit(7);
}
int main (void) {
struct sigaction new_action,old_action;
new_action.sa_handler = termination_handler;
sigemptyset(&new_action.sa_mask);
sigaddset(&new_action.sa_mask, SIGTERM);
new_action.sa_flags = 0;
sigaction(SIGINT, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN) {
sigaction(SIGINT,&new_action,NULL);
}
sleep(10);
return 0;
}
So - how exactly will SIGTERM
be handled? I can see that the installed handler is termination handler()
, but then SIGTERM
was added to the signal mask with no use of sigprocmask()
. What does this mean? Thanks!
P.s. one last question: why the if
statement in main()
?
The sigaction() function allows the calling process to examine and/or specify the action to be associated with a specific signal. The argument sig specifies the signal; acceptable values are defined in <signal. h>.
sigaction() can be used to inquire about the current handling of signal sig. If act is not NULL, the action specified in the sigaction structure becomes the new action associated with sig. (Output) A pointer to a storage location where sigaction() can store a sigaction structure.
Therefore, if you use signal to save and later reestablish an action, it may not be able to reestablish properly a handler that was established with sigaction . To avoid having problems as a result, always use sigaction to save and restore a handler if your program uses sigaction at all.
sigaction() can be called with a NULL second argument to query the current signal handler. It can also be used to check whether a given signal is valid for the current machine by calling it with NULL second and third arguments.
Let's try to understand what's happening with a modified version of your code :
#include <signal.h>
#include <stdio.h>
void termination_handler(int signum)
{
printf("Hello from handler\n");
sleep(1);
}
int main (void)
{
//Structs that will describe the old action and the new action
//associated to the SIGINT signal (Ctrl+c from keyboard).
struct sigaction new_action, old_action;
//Set the handler in the new_action struct
new_action.sa_handler = termination_handler;
//Set to empty the sa_mask. It means that no signal is blocked
// while the handler run.
sigemptyset(&new_action.sa_mask);
//Block the SEGTERM signal.
// It means that while the handler run, the SIGTERM signal is ignored
sigaddset(&new_action.sa_mask, SIGTERM);
//Remove any flag from sa_flag. See documentation for flags allowed
new_action.sa_flags = 0;
//Read the old signal associated to SIGINT (keyboard, see signal(7))
sigaction(SIGINT, NULL, &old_action);
//If the old handler wasn't SIG_IGN (it's a handler that just
// "ignore" the signal)
if (old_action.sa_handler != SIG_IGN)
{
//Replace the signal handler of SIGINT with the one described by new_action
sigaction(SIGINT,&new_action,NULL);
}
while(1)
{
printf("In the loop\n");
sleep(100);
}
return 0;
}
So, if you compile it and launch it, and press Ctrl+C, then you'll have the handler message executed, and then you get back immediately out of the main's sleep. You can do it as many time as you want, and the handler message and the inloop message are still displayed.
So, you give a function, and sigaction does everything needed to hook the signal with your handler.
Now, what about sigterm? If you increase the sleep time in termination_handler, you can type something like "pkill --signal SIGTERM ./a.out" after pressing Ctrl+C. Then, what happens? Nothing! The SIGTERM signal is blocked while termination_handler is running. But once you are back in the main, now the SIGTERM will kill the application.
(Remember, while you are testing this code, you can still kill applications by sending a SIGKILL signal.)
If you want to know more, and have more fun with signals, you have the signal manual and the sigaction manual which tell a lot more. Notice that you also have the detailed description of the sigaction structure.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With