I'm interested in hearing ideas on how to reliably deliver a signal generated for a process in a timely way. In the case of a signal generated for a thread, it's straightforward to queue it on the thread, wake the thread if needed, and deliver the signal the next time the thread returns to user space. If the thread never returns to user space (i.e., it exits), then the signal is never delivered and that is perfectly fine. However, things become a bit more challenging when a signal is generated for a process. In that case, in my current implementation, the signal is queued on the process, and each thread checks for deliverable signals on both itself and the process when returning to user space. To ensure that at least one thread in the process is awake, one of the threads is selected at the time of signal generation (based on criteria such as waiting on or not blocking the signal) and woken up if needed.
Now consider the case where the selected thread never returns to user space, and all the other process threads are sleeping. In this situation, the signal can stay pending on the process for an arbitrarily long time even if it is not blocked, which seems quite suboptimal. The only options for avoiding this seem to be to either wake all threads not blocking the signal at the time of generation (cue the thundering herd), or create a new thread just for delivering the signal. Is there a better way?
Signal generated for a process
Re: Signal generated for a process
If I understood you correctly, you are worried about the signal getting lost/delayed if the thread you selected to receive the signal exits instead of returning. Well, then isn't the simplest option to resend the signal when the thread exits? As part of the thread exit cleanup, look for pending process signals in the thread queue and send them again to a different thread. That would require you keeping track of process signals separately, of course.
Carpe diem!
Re: Signal generated for a process
I’m concerned about the signal being delayed, not lost. I maintain a signal queue on each thread and a signal queue on the process. Whenever a thread is about to return to user space, it checks its own signal queue and also the process signal queue for any deliverable signals. If it finds one, it de-queues the signal and delivers it. This way process signals cannot be lost unless the process exits (which is fine). The problem is how to ensure that some thread delivers the signal in a reasonable timeframe (we don’t care which thread).
The options seem to be:
The options seem to be:
- Do nothing after queuing the signal and hope one of the threads will do a return to user space soon. But if all the threads are sleeping then it could take arbitrarily long.
- Ensure that at least one thread is awake. This is what I do currently, but it still doesn’t guarantee timely delivery, since the thread might just exit, in which case we’re back to the previous option with the remaining threads (i.e., hope for the best).
- Wake up all the threads. This will at least ensure that either the signal gets delivered soon or the process exits - both are acceptable outcomes. But it’s pretty inefficient.
- Create a new thread just to ensure someone does a return to user space soon. This comes with overhead and a whole new set of complications.
Re: Signal generated for a process
Yeah, I got that. And I repeat what I'd do: Use option 2 from your previous post (so just keep doing what you're doing), then additionally on thread exit, if an unblocked signal is pending for the process and all other threads are sleeping, wake up another thread. That way, the signal cascades down all the threads until either some thread has handled it, or all threads are dead, which is the death of the process. The only exception is uninterruptible sleep, but that is always a spanner in the works and ought to not last long if your drivers are working correctly.
By the way, thank you for the idea, I hadn't thought of that problem yet.
By the way, thank you for the idea, I hadn't thought of that problem yet.
Carpe diem!
Re: Signal generated for a process
Seems like an approach worth considering. There might be challenges around determining if all threads are sleeping, since there's no straightforward way to do that atomically. But perhaps all that matters is determining if there is at least one thread that is awake and not blocking the signal. I'll think through it a bit.nullplan wrote:on thread exit, if an unblocked signal is pending for the process and all other threads are sleeping, wake up another thread.
By the way, it occurred to me that there are also situations involving threads updating their signal masks that can lead to unnecessary delays in delivering process signals. For example, imagine the same scenario I described in my previous post, but instead of exiting, the one thread that is awake updates its mask to block the signal before it gets a chance to deliver it. Now we have a situation where there is a live thread blocking the signal, and other sleeping threads that are not blocking the signal. Once again, the signal will not get delivered for an indeterminate period even though there are threads that could deliver it. I suppose one can take a similar approach to what you suggested for thread exit and check when updating a signal mask whether any pending process signals will be blocked, and if so, whether another thread might need to be woken up. Starts to feel a bit messy though, and there might still be remaining edge cases.
You are welcome. And thank you for suggesting a potential solution.By the way, thank you for the idea, I hadn't thought of that problem yet.