I have set a handler for each signal (SIGCHLD, SIGTSTP, SIGINT), now I need to block other signals while some handler running .
There is some resources like sigaction(2) and Blocking for Handler , but I didn't understand what should I do in my situation or how to use the code .
little information :
handlers : sigchldHandler, sigintHandler, sigtstpHander => signals.c
there is a file called smash.c which contains an infinite loop to get commands all the time .
thanks in advance
When setting up the sigaction, you can specify a mask of signals that should be blocked when the handler is running.
You use it like so:
struct sigaction act;
sigset_t set;
memset(&act,0,sizeof act);
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGSTP);
act.sa_mask = set;
act.sa_handler = sigchldHandler;
act.sa_flags = SA_RESTART;
sigaction(SIGCHLD, &act, NULL);
This will block SIGUSR1 and SIGSTP while your handler for SIGCHLD is running. Do the same for your 2 other handlers as well.
Related
I tried to find an answer to my question at this post: Signal handler and waitpid coexisting but for me isn't very clear at the moment.
I try to explain my problems:
I'm trying to write a C program that concerns IPC between a parent process and its children.
The parent process creates N child processes, then it waits for the termination in a loop like this:
while((pid_term = waitpid(-1, &status, 0)) != -1)
After X seconds, parent receives SIGALRM, then with the sigaction system call,
it catches the alarm:
struct sigaction act;
act.sa_handler = alarmHandler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, NULL);
But, when the handler function returns, the waitpid also returns -1, and the parent process exits from the while loop above.
At the moment, the handler function has an empty body.
I ask myself what happened — why did waitpid() return -1 after the handler invocation even though most of the children are still alive? Why doesn't this happen with signal() function?
The default behavior of signal handlers established by sigaction is to interrupt blocking system calls; if you check errno after the alarm fires you should observe it to be set to EINTR. This behavior is almost never what you want; it's only the default for backward compatibility's sake. You can make it not do this by setting the SA_RESTART bit in sa_flags:
struct sigaction act;
act.sa_flags = SA_RESTART;
act.sa_handler = alarmHandler;
sigemptyset(&act.sa_mask);
sigaction(SIGALRM, &act, 0);
One of the most important reasons to use sigaction instead of signal, is that when you use signal it is unpredictable whether or not the signal handler will interrupt blocking system calls. (The System V lineage picked one semantic and the BSD lineage picked the other.)
for a homework assignment I have to use only linux system calls to manage signals in a game, programmed in C.
One thing I have to do, it's to call indefinitly sigsuspend in a thread and wait for a SIGALRM,then if there is a sigalarm (signal alarm) I have to printf() something (doesn't matter what).
However, I tried several things but it doesn't work, I don't know how to "deblock" sigsuspend and print what i want. And there is a timer in the game which send sigalrm. My code works but not the part with the sigsuspend
Of course I have also a sigarlm handler which does some stuff with SDL when it receives a sigarlm.
I don't really how I have to use masks with sigsuspend
Code :
//initialising sigaction struct
int init (void)
{
// Signal handler
sigact.sa_handler = sigalrm_handler;
sigact.sa_flags = 0;
sigemptyset(&sigact.sa_mask);
// Linked list
head = NULL;
sigaction(SIGALRM, &sigact, NULL);
pthread_create(&tid_sigrecv, NULL, (void *)deamon, NULL);
return 1; // Implementation ready ?
}
The sigsuspend part
void deamon(void * arg)
{
int sig;
while(1) {
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
sigsuspend(&mask);
printf("in thread\n");
}
}
Currently it only does not print "in thread" when a sigarlm is received, what should I do to use sigsuspend properly ? I am obliged to use sigsuspend
You create a thread that should wait for the signal SIGALRM thanks to sigsuspend(), but instead you open the thread to all signals but SIGALRM.
Replace
sigemptyset(&mask); // clear mask
sigaddset(&mask, SIGALRM); // set mask to SIGALRM
sigsuspend(&mask); // wait for any signal but blocks SIGALRM
with
sigfillset(&mask); // mask set to all signals
sigdelset(&mask, SIGALRM); // remove SIGALRM from the mask
sigsuspend(&mask); // block all signals but SIGALRM
this way sigsuspend() waits for a non blocked signal (SIGALRM).
For testing, you could send the thread the SIGALRM signal using
pthread_kill(tid_sigrecv, SIGALRM);
from the main thread, for instance.
Can anyone help me to understand what are the differences between the following three ways of handling a signal? I'm operating in a client/server in C.
Edit: I've understood that the 1st example is wrong, now I'd like to know which is better/possible, the 2nd one ore the third one? I've also read around the web that someone does a mix between them, using the "struct sigaction sig" in "sigemptyset" and "sigaddset", without any sigprocmask. Is this better than both my solutions?
Handler:
void closeSig(){
close(socketAccept);
close(socket);
exit(1);
}
1st example:
signal(SIGINT, closeSig);
2nd example:
sigset_t set;
struct sigaction sig;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sig.sa_sigaction = &closeSig;
sig.sa_flags = SA_SIGINFO;
sig.sa_mask = set;
sigaction(SIGINT, &sig, NULL);
sigprocmask(SIG_UNBLOCK, &set, NULL);
3rd example:
struct sigaction sig;
sig.sa_sigaction = &closeSig;
sig.sa_flags = SA_SIGINFO;
sigaction(SIGINT, &sig, NULL);
According to POSIX sigaction(), the function closeSig() is not strictly a suitable callback for signals. It should be:
void closeSig(int signum);
for a regular callback, but as you're using SA_SIGINFO, it needs to be:
void closeSig(int signum, siginfo_t *info, void *context);
You also need to look at the POSIX specification for sigprocmask().
Let's look at the second example:
sigset_t set;
struct sigaction sig;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sig.sa_sigaction = &closeSig;
sig.sa_flags = SA_SIGINFO;
sig.sa_mask = set;
sigaction(SIGINT, &sig, NULL);
sigprocmask(SIG_UNBLOCK, &set, NULL);
The & on &closeSig is unnecessary, but harmless. However, the type of closeSig() shown in the question is wrong. The sigset_t says that SIGINT (only) will be blocked when the interrupt handler is called, but that would happen anyway since the flags don't include SA_NODEFER. So, the code handling set is superfluous to sigaction().
The call to sigprocmask() unblocks interrupts (SIGINT). It is not clear why this is called; there would have to be some previous call to sigprocmask() that blocked interrupts for it to make a difference. However, after this, if an interrupt is sent to the process, the closeSig() function will be called with arguments that it does not expect.
The third example is:
struct sigaction sig;
sig.sa_sigaction = &closeSig;
sig.sa_flags = SA_SIGINFO;
sigaction(SIGINT, &sig, NULL);
This is fairly close to the minimal operations described in dissecting and simplifying the second example. The main problem is that sig.sa_mask is set to an indeterminate value. The code should be:
struct sigaction sig;
sig.sa_sigaction = &closeSig;
sig.sa_flags = SA_SIGINFO;
sigemptyset(&sig.sa_mask);
sigaction(SIGINT, &sig, NULL);
This is now equivalent to the second example.
In Android the bionic loader sets a default signal handler for every process on statrtup:
void debugger_init()
{
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_sigaction = debugger_signal_handler;
act.sa_flags = SA_RESTART | SA_SIGINFO;
sigemptyset(&act.sa_mask);
sigaction(SIGILL, &act, NULL);
sigaction(SIGABRT, &act, NULL);
sigaction(SIGBUS, &act, NULL);
sigaction(SIGFPE, &act, NULL);
sigaction(SIGSEGV, &act, NULL);
sigaction(SIGSTKFLT, &act, NULL);
sigaction(SIGPIPE, &act, NULL);
}
I would like to set it back to its default, meaning I want to ignore these signal and that the default handler will take place (CORE DUMP)
How do I revert the action performed ? I want to ignore all these as if the above function never was called
Read signal(7), sigaction(2) and perhaps signal(2).
You could call
signal(SIGILL, SIG_DFL);
signal(SIGABRT, SIG_DFL);
and so on early in your main (which is entered after dynamic loading)
You could also use sigaction with sa_handler set to SIG_DFL
Of course, things are more tricky if you want to default handle these signals before your main, e.g. in some static constructor!
I found it could lead unexpected behavior when mixed using sigaction and signal to set for one process.
From signal(2) posted above(wouldn't surprise me if this warning wasn't there 8 years ago):
WARNING: the behavior of signal() varies across UNIX versions,
and has also varied historically across different versions of
Linux. Avoid its use: use sigaction(2) instead.
Looking at https://docs.oracle.com/cd/E19455-01/806-5257/tlib-49639/index.html
int pthread_sigmask(int how, const sigset_t *new, sigset_t *old);
When the value of new is NULL, the value of how is not significant and the signal mask of the thread is unchanged. So, to inquire about currently blocked signals, assign a NULL value to the new argument.
So I guess you could use that to get the current sigmask and just wipe each one
sigset_t tempSet;
pthread_sigmask(SIG_SETMASK, NULL, &tempSet);
sigdelset(&tempSet, /*Signal you don't want to handle*/);
sigdelset(&tempSet, /*repeat for each signal*/);
pthread_sigmask(SIG_SETMASK, &tempSet, NULL);
It's pretty much the same thing with sigact to query the current action for a signal, from sigaction(2)
sigaction() can be called with a NULL second argument to query
the current signal handler.
It's not clear to me the ramifications of, in my case, having SIGKILL in the first call to sigaction
struct sigaction sigAct;
sigaction(SIGKILL, NULL, &sigAct);
sigAct.sa_handler = SIG_DFL; // Ensure default handling of Kill signal
sigaction(/*Signal you don't want to handle*/, &sigAct, NULL);
sigaction(/*repeat for each signal*/, &sigAct, NULL);
Using siggetmask is obsolete by sigprocmask, and sigprocmask is only for single threaded environments.
Is there a way to block certain signals and unblock other signals in the same set?
I just dont seem to get my head around it!
An example
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
// Block signal SIGUSR1 in this thread
pthread_sigmask(SIG_BLOCK, &set, NULL);
sigaddset(&set, SIGALRM);
// Listen to signal SIGUSR2
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
pthread_t printer_thread1, printer_thread2;
pthread_create(&printer_thread1, NULL, print, (void *)&f1);
pthread_create(&printer_thread2, NULL, print, (void *)&f2);
bool tl = true;
while(1)
{
if(tl)
{
// thread1 does something
kill(pid, SIGUSR1);
// main thread waits for SIGALRM
sigwait(&set, &sig);
tl = !tl;
}
else
{
// thread2 does something
kill(pid, SIGUSR2);
// main thread waits for SIGALRM
sigwait(&set, &sig);
tl = !tl;
}
}
I am not allowed to use Mutexs, semaphores etc only signals.
Can someone help? :)
Is there a way to block certain signals and unblock other signals in
the same set?
With pthread_sigmask, you can choose to either:
add a set of signals to the set of blocked signals, using the constant SIG_BLOCK
remove a set of signals to the set of blocked signals, using the constant SIG_UNBLOCK
define the set of signals to be blocked, using the constant SIG_SET
In other words, there's a current set of blocked signals for the thread, and you can modify it as specified above, one operation at a time.
The important point is that newly created threads inherit the signal mask of the creating thread, so you can set the mask of the new thread right before creating it, or in the function that the new thread will run, at your convenience.
Regarding your example, I suppose that you are trying to have printer_thread1 block SIGUSR2 and SIGALRM, and have printer_thread2 block SIGUSR1 and SIGALRM, and have the main thread block SIGUSR1 and SIGUSR2, so that each thread can send a signal that will be caught by a single thread (without the code of print, f1 and f2, it's impossible to know for sure what is your intent in your example).
You should be able to achieve that by the following code:
sigset_t set;
pthread_t printer_thread1, printer_thread2;
// Block signal SIGUSR1 & SIGALRM in printer_thread1
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_SET, &set, NULL);
pthread_create(&printer_thread1, NULL, print, (void *)&f1);
// Block signal SIGUSR2 & SIGALRM in printer_thread2
sigaddset(&set, SIGUSR2);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_SET, &set, NULL);
pthread_create(&printer_thread2, NULL, print, (void *)&f2);
// Block signal SIGUSR1 & SIGUSR2 in the main thread
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
// Listen to signal SIGALRM
pthread_sigmask(SIG_SET, &set, NULL);
bool tl = true;
while(1)
{
if(tl)
{
// thread1 does something
kill(pid, SIGUSR1);
// main thread waits for SIGALRM
sigwait(&set, &sig);
tl = !tl;
}
else
{
// thread2 does something
kill(pid, SIGUSR2);
// main thread waits for SIGALRM
sigwait(&set, &sig);
tl = !tl;
}
}
see these man pages :
pthread_sigmask
sigprocmask
for further details.
I think what you want to do here is
// Block signal SIGUSR1 in this thread
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &set, NULL);
// Listen to signal SIGALRM
sigemptyset(&set);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
The set is only used to tell it what to block or unblock. Once passed to the command, you are free to reset it and build up another signal mask. If you skip the sigemptyset, the set will still contain SIGUSR1, which will subsequently be unblocked again. Well, I think that is how it works, at least - it has been a long time since I used signals.