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.
Related
I've tried to implement a user-level thread library, using makecontext(), swapcontext() and getcontext() functions. I've read that a good practice is to use signals for schedule function (with a cyclic timer), but while a new thread is adding, block signals.
My problem is that: I can implement function to block signals, but it does not work when I use context switching.
void initSignals()
{
printf("initSignals\n");
act.sa_handler = schedule;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, &oact);
}
void blockSignals()
{
printf("blockSignals\n");
//sigset_t sig_mask;
sigemptyset(&sig_mask);
sigaddset(&sig_mask, SIGALRM);
sigprocmask(SIG_BLOCK, &sig_mask, NULL);
}
void unblockSignals()
{
printf("unblockSignals\n");
//sigset_t sig_mask;
sigemptyset(&sig_mask);
sigaddset(&sig_mask, SIGALRM);
sigprocmask(SIG_UNBLOCK, &sig_mask, NULL);
runTimer();
}
About sigset_t sig mask now it is global, but I tried to set it like a local variable too.
Moreover I tried to use another signals SIGPROF, SIGVTALRM, because my cyclic timer looks like:
void runTimer()
{
printf("runTimer\n");
it.it_interval.tv_sec = 1;
it.it_interval.tv_usec = 0;
it.it_value.tv_sec = 1;
it.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &it, NULL);
}
And itimer allow to use this 3 types of alarm...
So the question is: how to block signals while code is using context switching functions? Is it possible? Maybe another functions exist which can do that?
I thought that signals are being used for all processes, so I was surprised that it is not working...
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.
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.
I have sigaction defined and it works fine. However I want to restore the original signal after my action is completed. This is my sigaction:
static void signal_handler(int signal, siginfo_t *info, void *reserved)
{
//Some logging statements
//How do I restore the original signal here??
}
The signal handler is set from JNI_Onload:
extern "C" jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
{
struct sigaction handler, action_old;
memset(&handler, 0, sizeof(handler));
handler.sa_sigaction = signal_handler;
handler.sa_flags = SA_SIGINFO;
sigaction(SIGILL, &handler, &action_old);
sigaction(SIGABRT, &handler, &action_old);
sigaction(SIGBUS, &handler, &action_old);
sigaction(SIGFPE, &handler, &action_old);
sigaction(SIGSEGV, &handler, &action_old);
sigaction(SIGSTKFLT, &handler, &action_old);
//Can I restore prior signal here???
return JNI_VERSION_1_6;
}
Save the old actions in global (or file-scope) variables (or an array indexed by signal id) and call sigaction from inside your signal handler to restore the previous behavior. sigaction is guaranteed to be async-signal safe.
See also: http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03
http://www.gnu.org/s/hello/manual/libc/Basic-Signal-Handling.html - says:
The signal function returns the action that was previously in effect for the specified signum. You can save this value and restore it later by calling signal again.
I have implemented a POSIX timer using timer_create( ) API, and this will generate SIGUSR1 when the timer expires for which i have put a handler code. Now the problem is, if this program receives another SIGUSR1, then the same signal handler will be invoked and caught.
Is there any way to prevent this, so that the handler can catch signals only generated by the timer?
Will this work for you? (Modified the code from example in timer_create man page.)
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#define CLOCKID CLOCK_REALTIME
#define SIG SIGUSR1
timer_t timerid;
static void handler(int sig, siginfo_t *si, void *uc)
{
if(si->si_value.sival_ptr != &timerid){
printf("Stray signal\n");
} else {
printf("Caught signal %d from timer\n", sig);
}
}
int main(int argc, char *argv[])
{
struct sigevent sev;
struct itimerspec its;
long long freq_nanosecs;
sigset_t mask;
struct sigaction sa;
printf("Establishing handler for signal %d\n", SIG);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sigaction(SIG, &sa, NULL);
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIG;
sev.sigev_value.sival_ptr = &timerid;
timer_create(CLOCKID, &sev, &timerid);
/* Start the timer */
its.it_value.tv_sec = 10;
its.it_value.tv_nsec = 0;
its.it_interval.tv_sec = its.it_value.tv_sec;
its.it_interval.tv_nsec = its.it_value.tv_nsec;
timer_settime(timerid, 0, &its, NULL);
sleep(100);
exit(EXIT_SUCCESS);
}
When signal from timer is caught Caught signal 10 from timer will be displayed. Otherwise Stray signal will be displayed.
The question is whether you really need to use signals. You may think of using callback that will be called when the timer expires:
void cbf(union sigval);
struct sigevent sev;
timer_t timer;
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = cbf; //this function will be called when timer expires
sev.sigev_value.sival_ptr = (void*) arg;//this argument will be passed to cbf
timer_create(CLOCK_MONOTONIC, &sev, &timer);
The callback function will be called in a new thread.
No, there is no easy way. Why don't you use SIGUSR2 instead for your timers if you have something else generating SIGUSR1 together with your timer. If that is not enough, use one of the real time signals for your application.
If it must be able to handle the same signal from the timer and some other source, then depending on how fast, how many, what system, etc etc you could try setting a timestamp before registering a timer on when the timer will approximately exit, and then in the signal handler try to deduce if it was within time margin. I would strongly advise not to use this approach, but instead redesign what you are doing.
Use another RT signals. See answers on Is there any way to create a user defined signal in Linux?