Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are asynchronous signal handlers executed on Linux?

I would like to know exactly how the execution of asynchronous signal handlers works on Linux. First, I am unclear as to which thread executes the signal handler. Second, I would like to know the steps that are followed to make the thread execute the signal handler.

On the first matter, I have read two different, seemingly conflicting, explanations:

  1. The Linux Kernel, by Andries Brouwer, §5.2 "Receiving signals" states:

    When a signal arrives, the process is interrupted, the current registers are saved, and the signal handler is invoked. When the signal handler returns, the interrupted activity is continued.

  2. The StackOverflow question "Dealing With Asynchronous Signals In Multi Threaded Program" leads me to think that Linux's behavior is like SCO Unix's:

    When a signal is delivered to a process, if it is being caught, it will be handled by one, and only one, of the threads meeting either of the following conditions:

    1. A thread blocked in a sigwait(2) system call whose argument does include the type of the caught signal.

    2. A thread whose signal mask does not include the type of the caught signal.

    Additional considerations:

    • A thread blocked in sigwait(2) is given preference over a thread not blocking the signal type.
    • If more than one thread meets these requirements (perhaps two threads are calling sigwait(2)), then one of them will be chosen. This choice is not predictable by application programs.
    • If no thread is eligible, the signal will remain ``pending'' at the process level until some thread becomes eligible.

    Also, "The Linux Signals Handling Model" by Moshe Bar states "Asynchronous signals are delivered to the first thread found not blocking the signal.", which I interpret to mean that the signal is delivered to some thread having its sigmask not including the signal.

Which one is correct?

On the second matter, what happens to the stack and register contents for the selected thread? Suppose the thread-to-run-the-signal-handler T is in the middle of executing a do_stuff() function. Is thread T's stack used directly to execute the signal handler (i.e. the address of the signal trampoline is pushed onto T's stack and control flow goes to the signal handler)? Alternatively, is a separate stack used? How does it work?

like image 991
Daniel Trebbien Avatar asked Aug 04 '11 21:08

Daniel Trebbien


People also ask

How are signals handled in Linux?

There are several methods of delivering signals to a program or script. One of the most common is for a user to type CONTROL-C or the INTERRUPT key while a script is executing. When you press the Ctrl+C key, a SIGINT is sent to the script and as per defined default action script terminates.

How does a signal handler work?

A signal handler is a function which is called by the target environment when the corresponding signal occurs. The target environment suspends execution of the program until the signal handler returns or calls longjmp() . Signal handlers can be set with signal() or sigaction() .

Are signal handlers executed in kernel mode?

The user space process registers a signal handler function with the kernel. This adds the address of the signal handler function to the process descriptor. This function gets executed each time a certain signal is delivered.

How signals are generated in Linux?

Generation A signal is generated by a process via the kernel. Whichever generates the signal addresses process to a particular process. With the help of the process number, the signal is represented, and it does not contain any additional data or arguments. So, signals are lightweight.


1 Answers

These two explanations really aren't contradictory if you take into account the fact that Linux hackers tend to be confused about the difference between a thread and a process, mainly due to the historical mistake of trying to pretend threads could be implemented as processes that share memory. :-)

With that said, explanation #2 is much more detailed, complete, and correct.

As for the stack and register contents, each thread can register its own alternate signal-handling stack, and the process can choose on a per-signal basis which signals will be delivered on alternate signal-handling stacks. The interrupted context (registers, signal mask, etc.) will be saved in a ucontext_t structure on the (possibly alternate) stack for the thread, along with the trampoline return address. Signal handlers installed with the SA_SIGINFO flag are able to examine this ucontext_t structure if they like, but the only portable thing they can do with it is examine (and possibly modify) the saved signal mask. (I'm not sure if modifying it is sanctioned by the standard, but it's very useful because it allows the signal handler to atomically replace the interrupted code's signal mask upon return, for instance to leave the signal blocked so it can't happen again.)

like image 62
R.. GitHub STOP HELPING ICE Avatar answered Sep 17 '22 18:09

R.. GitHub STOP HELPING ICE