Signal handling with multiple threads in Linux

79,095

Solution 1

This is slightly nuanced, based on which version of the Linux kernel you are using.

Assuming 2.6 posix threads, and if you are talking about the OS sending SIGTERM or SIGHUP, the signal is sent to process, which is received by and handled by root thread. Using POSIX threads, you can also sent SIGTERM to individual threads as well, but I suspect you are asking about what happens when the OS sends the signal to the process.

In 2.6, SIGTERM will cause child threads to exit "cleanly", where as 2.4, child threads were left in an indeterminate state.

Solution 2

pthreads(7) describes that POSIX.1 requires all threads in a process share attributes, including:

  • signal dispositions

POSIX.1 also requires some attributes to be distinct for each thread, including:

The Linux kernel's complete_signal routine has the following code block -- the comments are quite useful:

/*
 * Now find a thread we can wake up to take the signal off the queue.
 *
 * If the main thread wants the signal, it gets first crack.
 * Probably the least surprising to the average bear.
 */
if (wants_signal(sig, p))
        t = p;
else if (!group || thread_group_empty(p))
        /*
         * There is just one thread and it does not need to be woken.
         * It will dequeue unblocked signals before it runs again.
         */
        return;
else {
        /*
         * Otherwise try to find a suitable thread.
         */
        t = signal->curr_target;
        while (!wants_signal(sig, t)) {
                t = next_thread(t);
                if (t == signal->curr_target)
                        /*
                         * No thread needs to be woken.
                         * Any eligible threads will see
                         * the signal in the queue soon.
                         */
                        return;
        }
        signal->curr_target = t;
}

/*
 * Found a killable thread.  If the signal will be fatal,
 * then start taking the whole group down immediately.
 */
if (sig_fatal(p, sig) &&
    !(signal->flags & SIGNAL_GROUP_EXIT) &&
    !sigismember(&t->real_blocked, sig) &&
    (sig == SIGKILL || !p->ptrace)) {
        /*
         * This signal will be fatal to the whole group.
         */

So, you see that you are in charge of where signals are delivered:

If your process has set a signal's disposition to SIG_IGN or SIG_DFL, then the signal is ignored (or default -- kill, core, or ignore) for all threads.

If your process has set a signal's disposition to a specific handler routine, then you can control which thread will receive the signals by manipulating specific thread signal masks using pthread_sigmask(3). You can nominate one thread to manage them all, or create one thread per signal, or any mixture of these options for specific signals, or you rely on the Linux kernel's current default behavior of delivering the signal to the main thread.

Some signals, however, are special according to the signal(7) man page:

A signal may be generated (and thus pending) for a process as a whole (e.g., when sent using kill(2)) or for a specific thread (e.g., certain signals, such as SIGSEGV and SIGFPE, generated as a consequence of executing a specific machine-language instruction are thread directed, as are signals targeted at a specific thread using pthread_kill(3)). 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.

Share:
79,095
Admin
Author by

Admin

Updated on October 19, 2020

Comments

  • Admin
    Admin over 3 years

    In Linux, what happens when a program (that possibly has multiple threads) receives a signal, like SIGTERM or SIGHUP?

    Which thread intercepts the signal? Can multiple threads get the same signal? Is there a special thread dedicated entirely to handling signals? If not, what happens inside the thread that is to handle the signal? How does the execution resume after the signal handler routine finishes?

  • Admin
    Admin almost 12 years
    And what happens inside the root thread when a signal is received? Let's say I wrote a custom signal handler for SIGUSR1, and now I'm sending that signal to the process. The root thread will get that signal. Maybe it's in the middle of some function at that moment. What is going to happen?
  • Alan
    Alan almost 12 years
    if you have a handler setup, it will be treated as an interrupt, and program flow will halt and your custom handler will be executed. Once it's executed, control will return, assuming you haven't done anything to alter the normal flow (exit etc).
  • Alan
    Alan almost 12 years
    Note that this is specific to SIGUSR1, which IIRC doesn't interrupt system calls. If you tried this with SIGINT for example, it could interrupt a stream read, and when you went to return to reading, the stream may return an error that it was interrupted.
  • houstond
    houstond over 9 years
    I'm a little confused about what is meant by "root thread". Does this mean that the handler for SIGTERM will always run in the main thread, or can it run in any thread?
  • user202729
    user202729 over 5 years
    This answer, whic states that an arbitrary thread is chosen to handle the signal, contradicts your answer.