Suspending thread execution within signal handler - c

This is a bit of a follow-up to this question.
Suppose I use sigaction to set up a signal handler of my own design. In this signal handler, I access information about the CPU state (the thread's stack pointer, for example) and copy it to a predetermined location in memory. I now want to examine a value on this thread's stack from another thread.
Is there a way to suspend execution of the thread in the signal handler from within the same signal handler, so that I can safely examine this thread's stack from another thread? (Note: I define "safely" here to mean "without worrying about the thread completing or returning from a function.)
If I was outside of the signal handler, I could use sigsupend; however, it's not safe to use within the signal handler according to the GNU documentation. I could also try extending a signal using the method described in this question, but I don't think any of the standard *nix signals will help me here.

A blocking read on a pipe is async-signal-safe, and provides a convenient way to wake up your "suspended" thread.
E.g.,
static int the_pipe[2] = {-1, -1}; // file descriptors allocated in main via pipe()
static void
siginfo_handler(int s, siginfo_t *si, void *ctx) {
char c;
// do something with (ucontext_t *)ctx
// now wait for someone else to wake us up
read(the_pipe[0], &c, 1);
...
}

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).

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.

Block signals for complete process in a multithreaded environment

I have a 'C' application in linux where in i have register SIGALRM handler. My SIGALRM handler updates some global data that other threads are also accessing.
Requirement:
In order to protect the global data, i need to block the signal completely while i am accessing it inside the thread. So i need a way to implement it.
Problem:
I am not able to block the signals completely.
sigprocmask is not working. Although it blocks signal if main is the only thread running. But when multiple threads are running SIGALRM keeps on coming.
I have tested pthread_sigmask but that updates the signal mask for current thread only.
Adding code logic:
sig_atomic_t atm_var;
void signal_handler()
{
atm_var++;
}
void thread_func()
{
pthread_sigmask(UNBLOCK,...);
while(1)
{
/* some stuff */
pthread_sigmask(BLOCK,...);
/* critical section, can easily access or modify atm_var */
pthread_sigmask(UNBLOCK,...);
}
}
int main()
{
sigprocmask(BLOCK,...);
pthread_create(...,thread_func,...);
sigaction(SIGALRM,...);
setitimer(ITIMER_REAL,...);
while(1)
{
}
}
Adding one more point: How safe it is to modify a sig_atomic_t variable (that signal handler is modifying) in main or other threads?
OR
Will it be safe practice to not to block signal while i modify the sig_atomic_t variable inside main or other threads?
Your problem is that various signals can be directed at the whole process or a particular thread. When directed at the whole process then they will be delivered to any thread that doesn't have them blocked.
man (7) signal
A process-directed signal may be delivered to any one of the threads that does not currently have the signal blocked. If more than one of the threads has the signal unblocked, then the kernel chooses an arbitrary thread to which to deliver the signal.
Because the signal masks are inherited by each thread from whatever thread created them, a fairly standard technique is to block them in the creator (for simplicity let's say that is main) and then let each spawned thread unblock signals as appropriate.
A common variation on this is to block them in main, and keep them blocked in all spawned threads except one. That one thread unblocks the signals and all process directed signals get aimed at it to handle.
The above is probably what you want to do. You probably are properly blocking SIGALRM in the thread which is running the signal handler. Unfortunately that isn't going to prevent SIGALRM from being delivered to a second thread.

Race condition in signal handler with static variable

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.)

Send and catch signals to pthreads in C

I know how to send signals to child process in C using the kill(pid_t pid, int sig) function. What about sending signals to threads? is it possible?. If so, how to catch signals on the "child" thread. For example, if the main thread sends me a terminate signal, how can I in the other thread catch it.
With POSIX threads, you have the functions pthread_cond_wait and pthread_cond_signal.
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex)
int pthread_cond_signal(pthread_cond_t *cond)
The signaled thread should block on a pthread_cond_wait call until another thread sends a signal using pthread_cond_signal, with the same condition variable.
Considering the analogy with signals delivered to processes, this is a bit different because the signaled thread has already suspended its execution waiting for a signal, unlike a process that simply gets interrupted and goes on.
Signals are sent to a process as a whole. Each signal sent to the process is received by a single thread (on behalf of the whole program). There are per-thread signal masks which influence whether a particular thread is eligible to handle a particular signal.
So, you need a signal handler - possibly in just one thread. Note that there are limits on what you're supposed to do in a thread's signal handler, though. Be wary of stepping far outside the promises made by the standard (which are minimal).
However, the pthread_kill() function can be used to send signals to other threads as long as the current thread can identify (has access to the thread ID values (pthread_t) that identify) the threads that are still executing within the process. You might decide to relay the signal to the other threads using a different signal number from the one originally caught (so one thread receives the external signal, but many threads receive the internal signal). Or you might use another Pthread synchronization or communication primitive instead of signals.
Signals do not have thread affinity. They are handled completely asynchronously. When you specify a signal handler with signal(2) or sigaction(2), it's a global signal handler. When a signal is raised, the signal handler runs on top of the stack of whatever thread happens to be running at the time, and you can't control that.
It sounds like you want some other sort of interthread communication. The simplest way to do this is with a volatile shared variable:
volatile bool should_terminate = false;
void ChildThread()
{
while(!should_terminate)
{
// do stuff
}
}
void MainThread()
{
// To terminate child thread:
should_terminate = true;
}
If you need stronger concurrency control, look into mutexes, condition variables, and semaphores.
I'm not sure this is possible as it is platform and implementation dependant and I highly suggest you don't use signals to communicate between threads. Sometimes only a specific thread will receive signals and sometimes all threads receive signals.
Better thread communucation mechanisms exist like queues, semaphores, and locks.

Resources