How to wait inside SIGABRT signal handler - c

I have a signal handler for SIGABRT , when the signal is received, i need some more time for other threads to exit gracefully. Then I will do _exit() inside signal handler to exit the entire process.
But I am not sure how to wait inside a signal handler. I think there are some limitations for using sleep inside signal handler. I dont want to use busy wait.
Somebody suggest any ideas please ?

There are no limitations of what kind of code you can execute inside a signal handler. You just have to keep in mind that another signal may arrive while executing your signal handler leaving you in the middle of half finished functions, locked mutexes or other things that should better remain uninterrupted.
Normally you would have the signal handler set a flag signalling to all threads to nicely exit, return from the signal handler and then have your code gracefully exit.

Related

Signal can't wake up sleeping process

I'm working on a project which requires to take care of process scheduling. I tried to stop certain process by sending SIGINT signal(ctrl+c), but i found out sleeping process doesn't wake up.
I solved this weird issue but couldn't find out why SIGINT signal couldn't wake up sleeping process.
Here's my original code (where process is stuck) :
set_current_state(TASK_INTERRUPTIBLE);
while (!item->assigned) {
schedule_timeout(2*HZ);
set_current_state(TASK_INTERRUPTIBLE);
}
set_current_state(TASK_RUNNING);
So inside of the while loop, when !item->assigned is still 1, SIGINT signal doesn't do anything even though process' state is set to TASK_INTERRUPTIBLE.
As far as I know, process takes care of signal in these ways:
execute the signal default action
block the signal setting a signal mask (this is done using the system call sigmask)
assign a custom handler to the signal, executing a custom action (using the system call signal)
So in this case I assumed It would execute the default action..
I added signal_pending(current) to check if there is any pending signal, and if it is, then break out of the loop so that the process can handle the pending signal.
set_current_state(TASK_INTERRUPTIBLE);
while (!item->assigned) {
schedule_timeout(2*HZ);
if (signal_pending(current))
{
break;
}
set_current_state(TASK_INTERRUPTIBLE);
}
set_current_state(TASK_RUNNING);
But still no idea why It didn't catch the SIGINT signal.

Does signal "auto-block" (when execution enters handler function) prevents another such signal from being delivered to another thread?

Signal mask is thread-specific, which means blocking a signal doesn't prevent it from being delivered to another thread where this signal isn't blocked. When execution enters into a handler function (assuming no SA_NODEFER) "current" signal becomes blocked.
Does it mean it will be blocked for all threads in current process or it is possible for next such signal to be delivered to another thread (while it is still being handled in first thread)?
Reading man sigaction:
sa_mask specifies a mask of signals which should be blocked (i.e., added to the signal mask of the thread in which the signal handler is invoked) during execution of the signal handler. In addition, the signal which triggered the handler will be blocked, unless the SA_NODEFER flag is used.
This sounds like the masking of the currently handled signal only affects the handling thread, so other threads may handle further signals.
I think it is typical for a multithreaded system to block all signals for all threads except one (or several) dedicated signal handling threads (e.g. one that is polling on a signalfd). That way you never have to worry about signals landing on some unpredictable thread.

pause() signal handler

The pause() function blocks until a signal arrives.
Assuming the process got a signal and pause() returned, does the signal handler will be executed before the code that follows the pause() call, or the result is unexpected?
Example:
void sigusr1_handler()
{
// .. handler code
}
void main()
{
// .. bind handler to SIGUSR1
pause(); // wait for SIGUSR1
// some more code
}
Does "some more code" will always be executed after sigusr1_handler() has finished, or there is a race condition? If so, what is the solution?
I cannot think of anything besides busy-waiting, but then the pause won't be needed at all..
Citing from the man page for pause(2):
pause() returns only when a signal was caught and the signal-catching function returned. In this case, pause() returns -1, and errno is set to EINTR.
You can be sure that your signal handler runs before some more code.
Signal handlers do not run concurrently; they interrupt the thread that handles them, and the interrupted flow only continues when the signal handler returns.
However, there may be other race conditions associated with your example; with just sparse pseudo-code and not a full explanation of your usage case, it's hard to say. For example a different signal might arrive and interrupt the pause before your signal does, and then your handler could end up running later than you expected.
There are several "right ways" to do this instead:
write a single byte to a pipe in the signal handler, and read from it in the main flow of execution.
sem_post a semaphore from the signal handler, and sem_wait in the main flow of execution.
Use sigwaitinfo or sigtimedwait instead of a signal handler.
Still use pause, but in a loop:
while(!signal_handler_finished) pause();
where signal_handler_finished has type volatile sig_atomic_t, and is set to a nonzero value in the signal handler.

Are all threads halted when one of them receives a signal and none of them block it?

I'm running a multithreaded application written in C on Linux.
To stop execution I send SIGINT and from the signal handler call a number of cleanup routines and, finally, call exit(0).
Are the other threads still running or may run (context switch) while the handler executes the cleanup routines?
Handling a signal does not cause the suspension of other threads during execution of the signal handler. Moreover, it's generally not safe to call most functions you would need for cleanup (including even exit!) from a signal handler unless you can ensure that it does not interrupt an async-signal-unsafe function.
What you should do is simply store the fact that SIGINT was received in some async-signal-safe manner and have the program act on that condition as part of its normal flow of execution, outside the signal handler. Then you can properly synchronize with other threads (using mutexes, condition variables, etc.) to achieve a proper, safe shutdown. The ideal method is not to even install a signal handler, but instead block all signals and have a dedicated signal-handling thread calling sigwaitinfo in a loop to accept signals.
Yes, a signal is delivered to one thread, chosen in an unspecified way. Only threads that aren't blocking the signal are considered, though; if all threads block the signal, it remains queued up until one thread unblocks it.
(So if you make all threads block the signal, you can use the signal as a deterministic, inter-process synchronization mechanism, e.g. using sigwait.)

Is there a way to make process-internal-only conditionally-interrupting signals?

I'm looking for a way to, from within a signal handler, conditionally interrupt a syscall that way taking place at the time the signal was handled. To make this concrete, suppose a call to read is in process, and SIGRT0 is received. This signal handler uses SA_RESTART because it does not want to unconditionally interrupt syscalls, but depending on a condition, I want to cause read to return EINTR immediately once the signal handler returns.
One way I could do this is by setting up another signal handler for SIGRT1, putting SIGRT1 in the signal mask for SIGRT0's handler, and omitting SA_RESTART from the SIGRT1 handler. Then the handler for SIGRT0 can raise SIGRT1, and when the first, non-interrupting signal handler returns, the second one will fire and read gets interrupted.
The problem with this solution is that other processes could send SIGRT1, causing unwanted EINTR occurrences.
Is there any way to achieve the result I'm looking for?
If you want to set a particular process to send that signal then you can any IPC techniques (e.g. pipe) to share its pid id and flags to make sure that signal was sent by that process. If signal wasn't sent by the process then just ignore it.
What I wanted was impossible for multiple reasons. Perhaps most importantly, the secondary signal that was intended to do the interrupting would potentially (and in reality on most systems) fire as soon as the first signal handler returned but before the interrupted syscall got restarted. Then the syscall would restart and continue to block.
Perhaps more importantly, any attempt to interrupt blocking syscalls with EINTR intentionally is subject to race conditions where the signal arrives just before the blocking syscall, but after whatever check would have prevented making the syscall due to having received the signal. The only time this might be acceptable is when you're prepared to fire off multiple signals with increasing delays between them until the "interupt request" is honored, but that's getting into the realm of flaky hacks...

Resources