Race condition in signal handler with static variable - c

In a single threaded program, does a race condition is possible in a signal handler?
void signal_handler(...)
{
static int i = 0;
i = i + 10 * 10;
}
Imagine that two very close signals are thrown, so close that they enter the function at the same time.
I can't find informations about how recent Linux OS handle this. I just know that both signals are correctly handled but I don't know how. Does race conditions are possible ?
Any helps appreciated, thanks!

There is no race condition in the sense that you mean (between two signals). Multiple signals of the same signal are not delivered simultaneously. Unless precautions are taken, multiple signals for different signal numbers may be delivered simultaneously, as described in torek's answer.
Whenever you involve variables of static duration (or global variables), your function may no longer reentrant. This is typically not important for the signal handler function itself. However, if it calls some other function that accesses global or static data, then that function will see an access pattern that is similar to two threads racing through a critical section. That is, your program is calling such a function to do its normal processing, but the signal arrives in the middle of that function, and then your signal handler calls into that same function. The global/static variables may be in an inconsistent state, and might cause your program to have non-deterministic behavior.
POSIX defines a set of APIs that are safe to be called from within a signal handler. Your code should take similar precautions when you plan to let your signal handler call functions that you implement.

Single threaded means only one app touching the static at a time yes? If there are 2 apps, there are 2 statics and no race condition.
If this is an interrupt handler and i += 100 is not atomic (which it may be depending on the platform/CPU), then it would race.

One additional, important note: if you're using "reliable signals" (POSIX sigaction with the corresponding sa_mask field), you get control over how signals behave in a single-thread-single-process situation.
Consider the case of single process P1, with a signal-handler like the one you show above. Suppose that you are catching signal SIGUSR1 and having that enter the function signal_handler. While you are inside signal_handler, some other process P2 sends another SIGUSR1 to P1 (e.g., via kill). This signal is "blocked" (temporarily) via sa_mask until signal_handler returns in P1. This is true even if you don't set any bits in sa_mask (as long as you don't set SA_NODEFER in sa_flags, see below).
But, suppose you've also decided to catch SIGUSR2 with function signal_handler. Suppose that P2 also sends a SIGUSR2. In this case, the SIGUSR2 is (or may be) caught, starting another instance of signal_handler running, this time on behalf of the SIGUSR2 signal.
You can prevent this by making sure that when SIGUSR1 is being handled, SIGUSR2 is temporarily blocked as well. In general you'd probably want to make SIGUSR1 blocked while SIGUSR2 is being handled. To do this, set both corresponding bits in sa_mask:
struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_flags = SA_RESTART | SA_SIGINFO; /* (decide for yourself which flags) */
sigaddset(&sa.sa_mask, SIGUSR1);
sigaddset(&sa.sa_mask, SIGUSR2);
sa.sa_sigaction = signal_handler;
error = sigaction(SIGUSR1, &sa, NULL);
if (error) ... handle error ...
error = sigaction(SIGUSR2, &sa, NULL);
if (error) ... handle error ...
The two sigaddset calls make sure that both SIGUSR1 and SIGUSR2 are held-off (blocked, temporarily) for the duration of the function.
If you're only catching one signal, there is no need for this extra complexity, because as long as SA_NODEFER is not set, the OS automatically adds whatever signal triggered entry to your signal handler to the "currently blocked signals" set at entry.
(Note that the OS's automatic blocking and unblocking of signals at entry and exit to your signal handler is done with sigprocmask, using SIG_BLOCK and SIG_SETMASK—not SIG_UNBLOCK—with the mask for the SIG_SETMASK at exit set by saving the previous mask filled in via SIG_BLOCK. Well, it's normally done inside kernel code, rather than actually calling sigprocmask, but the effect is the same, just more efficient.)

Related

Use mutex to wait for exit signal

I want the process exit when it receive an exit signal. So the main thread needs to wait for the exit signal, which I wrote like this before.
int signal(int a) {
exit_flag = 0;
}
//wait in main thread
while(exit_flag){
sleep(1);
}
But it reacts a little slowly. So I find a new method like this,
//signal function
int signal(int a) {
pthread_mutex_unlock(&mutex);
}
//main thread
pthread_mutex_lock(&lock);
pthread_mutex_lock(&lock);
I'm not sure if it's correct. My question is that if it's a propper way to wait for an exit signal or you can tell me a better way?
Sincerely thank you all for your replies.
I know that it's undefined beahiver and unsafe to use the mutex in signal handler. But is the above code correct if I send the exit message through some other method, like a jrpc call or something like that?
My question is that if it's a propper way to wait for an exit signal or you can tell me a better way?
No, for reasons that #AndrewHenle describes very well in his answer.
There are multiple correct ways to do it, but many of them reinvent the wheel of the pause() function and its improved alternative sigsuspend(). These two are specifically for the purpose of waiting for a signal to be delivered. The Glibc manual contains a section on how to use them for the purpose.
Alternatively, if your process is multithreaded and you want to devote only one thread to waiting, then there is sigwait(), sigwaitinfo() and sigtimedwait().
For the whole process to wait
Suppose you want the whole process to stop until a SIGUSR1 is delivered to it, then exit. After installing your signal handler, you might use something like this:
// sufficient for this case even in a multi-threaded program:
volatile sig_atomic_t exit_flag;
// ...
/*
* Wait, if necessary, until a SIGUSR1 is received, then exit with status 0.
*
* Assumes that a signal handler for SIGUSR1 is already installed, that the
* handler will set variable `exit_flag` to nonzero when it runs, and that
* nothing else will modify exit_flag incompatibly.
*/
void wait_to_exit(void) {
sigset_t temp_mask, mask;
sigemptyset(&temp_mask);
sigaddset(&temp_mask, SIGUSR1);
/*
* Temporarily block the signal we plan to wait for, to ensure that we
* don't miss a signal.
*/
sigprocmask(SIG_BLOCK, &temp_mask, &mask);
// Prepare to wait for the expected signal even if it is presently blocked
sigdelset(&mask, SIGUSR1);
// if we haven't already received the signal, then block the whole process until we do
while (!exit_flag) {
sigsuspend(&mask);
}
// No need to reset any signal masks because we're about to ...
exit(0);
}
About the flag's data type
To expand on one of the comments in the above code, volatile sig_atomic_t is a sufficient type for the purpose even in a multithreaded program. sigsuspend() is specified to return after the signal handler returns, and the signal handler will not return until after the write to the flag actually happens (because of volatility). The thread calling sigsuspend must then read the value that was written by the handler, or some other value subsequently written to the same variable, again because of volatility.
volatile typically is not enough for thread safety, however, so even though it is not necessary in this case, you could consider sidestepping the issue and any uncertainty about it by instead using atomic_flag (declared in stdatomic.h); this requires support for C11 or later.
For just one thread to wait
For the case of one thread out of many waiting for a signal, it should be structured rather differently. You do not need a signal handler or flag in this case, but you should block the expected signal for all threads via sigprocmask():
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigprocmask(SIG_BLOCK, &mask, NULL);
That prevents the default (or custom) disposition of the expected signal from being executed in any thread, and ensures that threads other than the one that is to wait do not consume the signal. Typically, it should be done very early in the program's execution.
Then, to await the signal, a thread does this:
void wait_to_exit(void) {
sigset_t mask;
int sig;
sigemptyset(&temp_mask);
sigaddset(&temp_mask, SIGUSR1);
// if we haven't already received the signal, then block this thread until we do
if (sigwait(&mask, &sig) != 0) {
// Something is terribly wrong
fputs("sigwait failed\n", stderr);
abort();
}
assert(sig == SIGUSR1);
// Terminate the process (all threads)
exit(0);
}
If you mean a generic "signal"
If you mean "signal" as a generic term for a synchronous notification, as opposed to an exercise of the C signal-handling facility, then #AndrewHenle's suggestion of a semaphore would be perfect. In that case, be sure to accept that answer.
No, it is not correct.
First, pthread_mutex_unlock() is not an async-signal-safe function and can not be safely called from within a signal handler.
Second, mutexes are locked by a thread. If the signal handler is run in a different thread than the thread that has the mutex locked, it can not unlock the mutex:
If a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked, pthread_mutex_unlock() shall behave as described in the Unlock When Not Owner column of the following table.
The only entries in that table are "undefined behavior" and "error returned". And you have no real control over which thread the signal will be delivered to (at least not without writing complex signal-handling code...)
Third, this code
pthread_mutex_lock(&lock);
pthread_mutex_lock(&lock);
per that same table, will not block safely for any type of mutex. That code will either deadlock, continue with the mutex locked, or invoke undefined behavior which might even appear to "work" but leaves your program in an unknown state that could cause errors later.
Edit:
Fourth, if the signal is delivered multiple times, multiple calls to pthread_mutex_unlock() will again result either in errors or undefined behavior.
But there is an async-signal-safe way to block waiting for a signal: sem_wait().
sem_post() is async-signal-safe and can safely be called from within a signal handler, and can also be call multiple times safely - multiple calls to sem_post() will merely allow a corresponding number of calls to sem_wait() to obtain the semaphore, but you only need one to work:
//signal function
int signal(int a) {
sem_post(&sem);
}
//main thread
sem_wait(&sem);
Note that it is not safe to call sem_wait() within a signal handler.
Besides accepting signals (via sigwait or sigtimedwait), I'm a fan of the venerable self-pipe trick: "Maintain a pipe and select for readability on the pipe input. Inside the [signal] handler, write a byte (non-blocking, just in case) to the pipe output."
I'd further add to the above that the signal handler ought to be installed by sigaction as SA_RESTARTable.
Now you can safely mix the signal delivery with IO (via select or poll, e.g., or just blockingly read until that byte comes across).

Does multi-thread program handle multiple signals in parallel?

Platform is Linux/POSIX.
The signal is sent to a whole process, not a specific thread.
No signal is set to blocked, all default.
The process is multi-thread process.
From what I've googled, a signal may be handled by a random thread.
And when that signal's handler is executing, it's temporarily blocked until handler returns.
QUESTION: Multiple signals of different types reached simultaneously. Do their handler execute simultaneously on multiple thread or all of them go to one randomly picked thread (SUB-QUESTION: in this case a handler could interrupt another handler's execution started previously, so there could be a interrupt stack?) ? Or mixed? For instance there are 3 type of signals received but only 2 thread free (this is actually the first case).
EXAMPLE: SIGHUP, SIGINT, SIGTERM reached almost simultaneously. The program has two available thread to dispatch signal handler execution.
SIDE-QUESTION: If signal handlers run in parallel, I'll have to use mutex to synchronize them properly. Otherwise 'volatile sig_atomic_t' would be enough, right?
Expected: all signals go to one thread (randomly picked) despite of their different signal types, I haven't seen an example of using mutexes and atoms to synchronize signal handlers.
Your understanding is correct - unless a signal was directed
to a specific thread, there's no guarantee which thread will handle a signal.
See POSIX's Signal Generation and Delivery and pthreads(7):
POSIX.1 distinguishes the notions of signals that are directed
to the process as a whole and signals that are directed to
individual threads. According to POSIX.1, a process-directed
signal (sent using kill(2), for example) should be handled by
a single, arbitrarily selected thread within the process.
So it may be delivered & handled by the same thread that's currently handling another signal (in that case, the previous handler may be interrupted by the new signal). Or may be delivered to another signal.
You can block other signals while one is being handled using sa_mask field
of sigaction to avoid a signal handler being interrupted.
SIDE-QUESTION: If signal handlers run in parallel, I'll have to use mutex to synchronize them properly. Otherwise 'volatile sig_atomic_t' would be enough, right?
You almost certainly don't want to use mutex in a signal handler. There are only few functions that can be safely called from a signal handler (you can only call the functions that are async-signal-safe).
See signal-safty for more information.
If you can use volatile sig_atomic_t for whatever the purpose (do you need to co-ordinate execution of different signal handlers?), it should be preferred.
Expected: all signals go to one thread (randomly picked) despite of their different signal types, I haven't seen an example of using mutexes and atoms to synchronize signal handlers.
This is commonly done by blocking signals that you're interested in from main and fetching/handling them in a specific thread. See pthread_sigmask which also has an example on how to implement this.

pthread_cond_wait returns after sign_handler()?

Fellow coders.
If I send a SIGINT signal to a thread stuck on pthread_cond_wait(), when sign_handler() returns, will pthread_cond_wait() return as well?
If not, is there any way to make pthread_cond_wait() return?
If I send a SIGINT signal to a thread stuck on pthread_cond_wait(), when sign_handler() returns, will pthread_cond_wait() return as well?
No.
If not, is there any way to make pthread_cond_wait() return?
No, you're trying to use the wrong tool to solve whatever underlying problem you have.
(Technically, pthread_cond_timedwait() is allowed to return when interrupted by a signal delivery, but it does not do so, at least when using GNU glibc 2.27 on x86-64 running kernel 5.3.0. Yes, I checked.)
How can I fix my problem?
Let's assume that a condition variable is the best option for your use case. (That's just a guess, though; you didn't tell us about your real problem you're trying to solve, only how your chosen solution isn't working.)
Then, the recommended solution is to use a helper thread to catch signals like SIGINT, using sigwaitinfo() or sigtimedwait(). That helper thread can then set a specific volatile sig_atomic_t you_need_to_exit flag, and pthread_cond_signal() or pthread_cond_broadcast() on the relevant condition variables to let them know something important happened. Those waiting on the condition variables should obviously first check the helper flag; and if set, assume that that was the source for the wakeup signal. Usually I name such flags need_to_exit or similar.
The key in such signal handling helper threads is that the signals need to be blocked in all threads (including the handling helper thread itself). It is best to do this in the main thread before creating any other threads, as then the created threads inherit that same signal mask.
The siginfo_t structure contains all kinds of useful information. Most useful is perhaps the .si_pid field, which tells which process (or 0 if kernel) sent the signal. That way, if you use say SIGRTMIN+0 to SIGRTMAX-0 signals for internal purposes, you can ignore them unless they come from the process itself (other threads, .si_pid == getpid()).
Thread cancellation (deferred, at cancellation points; pthread_cond_wait() being a cancellation point) is another option. You can use pthread_cleanup_push() to set/add functions to be run if the thread is cancelled. This basically forcibly kills the target thread, but it can run any cleanup functions it has set up before it dies. You can also defuse any cleanup functions using pthread_cleanup_pop() -- a parameter specifies whether the cleanup function is run and discarded, or just discarded. But, when cancelled, the thread always dies.
Do use pthread_attr_t to limit the stack size to a sane power of two. If you don't have any large arrays or structures on stack (local variables), then something like
#include <limits.h>
#ifndef THREAD_STACK_SIZE
#define THREAD_STACK_SIZE (4 * PTHREAD_STACK_MIN)
#endif
with
sigset_t mask;
pthread_attr_t attrs;
int err;
/* Block SIGINT in this (and all created threads) */
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
err = pthread_sigmask(SIG_BLOCK, &mask, NULL);
if (err) {
fprintf(stderr, "Cannot block signals: %s.\n", strerror(err));
return EXIT_FAILURE;
}
/* Create stack size attribute. */
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, THREAD_STACK_SIZE);
/*
* Create threads, use &attrs for the second parameter.
*/
/* Optional cleanup - it's a good idea to be careful. */
pthread_attr_destroy(&attrs);
should work fine, for both stack size and blocking some signals in all threads (by blocking them first in the thread that creates the other threads; they'll inherit the signal mask).
You can add any other signals to the blocked mask you like, except that SIGKILL and SIGSTOP cannot be blocked, caught, or ignored.
The pthread_attr_t second parameter to pthread_create() is just a collection of settings (or attributes), like configuration; they are not "consumed" by the pthread_create() call. You can use the same set of attributes any number of times. This one contains only the desired stack size. (It does not contain the stack itself, only the desired size.)
The default stack size is very large, typically 8 MiB, which means that a lot of virtual memory is reserved for thread stacks for no good reason, really. Also, it severely limits the number of threads a process can create.
In many ways, having a helper thread for signal handling is easier than actual signal handlers, because only async-signal safe functions are safe to use in a signal handler; whereas in the helper thread, you can use all.

How to avoid race condition in signal handler

I am working on a project involving signal-driven I/O which may end up using a signal handler created with sigaction(). My concern is that the handler might be called multiple times. In other words, it will be processing message A, when it gets interrupted by message B and start processing B, possibly causing a problem. I have seen some code on the web that uses sigprocmask to avoid this, but it appears wrong to me. For example:
void handle_signal(int sig_num)
{
sigset_t mask_set; /* used to set a signal masking set. */
sigset_t old_set; /* used to store the old mask set. */
/* re-set the signal handler again to catch_int, for next time */
signal(SIGINT, catch_int);
/* mask any further signals while we're inside the handler. */
sigfillset(&mask_set);
sigprocmask(SIG_SETMASK, &mask_set, &old_set);
.... (content handling code here) ....
/* restore the old signal mask */{{/COMMENT_FONT}*/
sigprocmask(SIG_SETMASK, &old_set, NULL);
}
This is obviously wrong because sigprocmask is not atomic with the signal. In other words, there is a window of time between when the signal handler is called and when sigprocmask is called, and the signal handler could be called a second or third time in that window, creating a race condition.
My options:
(1) Use a semaphore inside of the handler to queue any redundant calls of the handler.
(2) Write the handler to be re-entrant, so it is fine for it to be called multiple times concurrently.
(3) Some other solution?
If I go for option (2) above, can I consider a socket read queue to be thread safe? For example, let's say a socket handler gets called twice. Instance A starts reading from the socket, then it is interrupted, and Instance B starts finishes reading the packet. Will this cause A to just find the queue empty and finish up or will I be at risk for some kind of error?
If you're using sigaction to setup the signal handler then the signal that caused the handler to be triggered will by default already be blocked inside the handler.
In your code then the blocking of all signals and then the restore of the old mask is about blocking all other signals, the original signal (that triggered the handler) will be blocked until you return from the handler (or you specifically unblock it).
With sigaction you can avoid doing this block and restore in the handler by setting the sa_mask field of the struct sigaction, which is the set of signals blocked in the handler.
Further, your use of signal to "re-set" the handler is a little confusing, you call your function handle_signal then you re-set to catch_int (assuming this handler is actually handling SIGINT...
The older signal API did used to reset the signal handler back to the default each time the handler was triggered. However, by default sigaction does not do this, so you shouldn't need to "re-set" the signal handler if you're using the sigaction API. I personally would avoid mixing calls to signal and sigaction in the same program, I'd choose one and stick to it.
In conclusion, I think your concerns about sigprocmask not being atomic are unnecessary as the signal in question is already blocked, your mixed use of signal and sigaction worries me more.

What is sigaddset used for?

I have this code where I use sigaddset and sigaction. However if I comment segaddset the result is the same
struct sigaction act;
act.sa_handler = process_alarm;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
//sigaddset(&act.sa_mask, SIGINT);
sigaction(SIGALRM, &act, NULL);
for(;;)
{
alarm(3);
pause();
}
Why do I need to use it?
You are doing 2 things here:
Populating a sigset_t. A sigset_t is just a collection of values for signals, and are used in various system calls. You can:
Create an empty sigset_t (sigemptyset()
Add a signal to the set (sigaddset())
Remove a signal to the set (sigdelset())
etc...
Setting the signal mask for the signal handler. You do that by manipulating the sigset_t sa_mask member of the struct sigaction when you set up a signal handler in with a call to sigaction().
The signal mask of a signal handler means that while the signal handler is executing, the signals that are in the mask will be blocked - i.e. those signals will not be handled as long as they are blocked. When the signal handler are finished, the signals in will be unblocked.
A signal that is blocked isn't "lost", it will be handled when that particular signal is unblocked again.
The sigaddset(&act.sa_mask, SIGINT); means the the SIGINT signal cannot occur while the code for the SIGALRM handler is running.
On the other hand, if you comment out sigaddset(&act.sa_mask, SIGINT);, you're left with just an empty list of signals created with sigemptyset(&act.sa_mask);. So any signals that occur while the SIGALRM handler function is running might preempt that handler and execute the signal handler for that other signal.
For a SIGINT, you would normally not notice any difference with manual testing - it's unlikely you manage to hit CTRL-C exactly when your handler for SIGALRM is running, and your SIGALRM handler probably runs quickly enough that you would not notice if the SIGINT was slightly delayed.
Signals sets are manipulated via sigset_t type. Several operations are available for signals sets:
create an empty set S via sigemptyset, S=∅
add a signal s to a set S via sigaddset, S=S∪{s}
remove a signal s from a set via sigdelset, S=S\{s}
create the set of all possible signals via sigfillset.
test is a signal s is in a given set S via sigismember, s∈S?
Such a set is used at different places: setting a new process signal mask, blocking set during signal handling, requesting the set of pending signals, etc.
If you want to catch different signals, it may appears that some catching functions must not be interrupted with others, so you can add a set of signals to be blocked during the delivery of a given signal. You actually decided (when uncommented) to block SIGINT during SIGALRM delivery. So you can only observe this by sending a SIGINT during the execution of the handler; which is difficult to realize.
A example where it can be important ?
Suppose that the handler of SIGUSR1 modify a given data structure and that the handler for SIGUSR2 uses that same data structure. It is very important to make both handlers not concurrent, one can be run after the other but you probably don't want to be interrupted by one during the delivery of the other. Your code is self-concurrent, say that even in the case of only one thread, signals can lead you to concurrency.
sigaddset is used for adding the corresponding signal mask to that sigset_t variable.
In sigaction, it is not required. You can use that when you are using the sigprocmask which is for blocking the signal which we mentioning in that variable.

Resources