How does SIGINT relate to the other termination signals such as SIGTERM, SIGQUIT and SIGKILL?
Asked Answered
H

6

162

On POSIX systems, termination signals usually have the following order (according to many MAN pages and the POSIX Spec):

  1. SIGTERM - politely ask a process to terminate. It shall terminate gracefully, cleaning up all resources (files, sockets, child processes, etc.), deleting temporary files and so on.

  2. SIGQUIT - more forceful request. It shall terminate ungraceful, still cleaning up resources that absolutely need cleanup, but maybe not delete temporary files, maybe write debug information somewhere; on some system also a core dump will be written (regardless if the signal is caught by the app or not).

  3. SIGKILL - most forceful request. The process is not even asked to do anything, but the system will clean up the process, whether it like that or not. Most likely a core dump is written.

How does SIGINT fit into that picture? A CLI process is usually terminated by SIGINT when the user hits CRTL+C, however a background process can also be terminated by SIGINT using KILL utility. What I cannot see in the specs or the header files is if SIGINT is more or less forceful than SIGTERM or if there is any difference between SIGINT and SIGTERM at all.

UPDATE:

The best description of termination signals I found so far is in the GNU LibC Documentation. It explains very well that there is an intended difference between SIGTERM and SIGQUIT.

It says about SIGTERM:

It is the normal way to politely ask a program to terminate.

And it says about SIGQUIT:

[...] and produces a core dump when it terminates the process, just like a program error signal. You can think of this as a program error condition “detected” by the user. [...] Certain kinds of cleanups are best omitted in handling SIGQUIT. For example, if the program creates temporary files, it should handle the other termination requests by deleting the temporary files. But it is better for SIGQUIT not to delete them, so that the user can examine them in conjunction with the core dump.

And SIGHUP is also explained well enough. SIGHUP is not really a termination signal, it just means the "connection" to the user has been lost, so the app cannot expect the user to read any further output (e.g. stdout/stderr output) and there is no input to expect from the user any longer. For most apps that mean they better quit. In theory an app could also decide that it goes into daemon mode when a SIGHUP is received and now runs as a background process, writing output to a configured log file. For most daemons already running in the background, SIGHUP usually means that they shall reexamine their configuration files, so you send it to background processes after editing config files.

However there is no useful explanation of SIGINT on this page, other than that it is sent by CRTL+C. Is there any reason why one would handle SIGINT in a different way than SIGTERM? If so what reason would this be and how would the handling be different?

Hornsby answered 28/10, 2010 at 10:59 Comment(3)
Good question. I suspect some of the historical Unix cruft would be involved in the answer.Uproarious
I know this question is old, but in case anybody came here for an extensive list of signals for your (Linux) OS, they can be found by typing sudo fuser -l on your command prompt. For me this brings up: HUP INT QUIT ILL TRAP ABRT IOT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH IO PWR SYS UNUSEDUrga
Also try kill -l for a list of signals.Rockling
M
137

SIGTERM and SIGKILL are intended for general purpose "terminate this process" requests. SIGTERM (by default) and SIGKILL (always) will cause process termination. SIGTERM may be caught by the process (e.g. so that it can do its own cleanup if it wants to), or even ignored completely; but SIGKILL cannot be caught or ignored.

SIGINT and SIGQUIT are intended specifically for requests from the terminal: particular input characters can be assigned to generate these signals (depending on the terminal control settings). The default action for SIGINT is the same sort of process termination as the default action for SIGTERM and the unchangeable action for SIGKILL; the default action for SIGQUIT is also process termination, but additional implementation-defined actions may occur, such as the generation of a core dump. Either can be caught or ignored by the process if required.

SIGHUP, as you say, is intended to indicate that the terminal connection has been lost, rather than to be a termination signal as such. But, again, the default action for SIGHUP (if the process does not catch or ignore it) is to terminate the process in the same way as SIGTERM etc.

There is a table in the POSIX definitions for signal.h which lists the various signals and their default actions and purposes, and the General Terminal Interface chapter includes a lot more detail on the terminal-related signals.

Mirza answered 28/10, 2010 at 23:35 Comment(5)
This is the key point: SIGINT and SIGQUIT can be generated from the terminal using single characters, while the program is running. The other signals have to be generated by another program, somehow (eg by the kill command). SIGINT is less violent than SIGQUIT; the latter produces a core dump. SIGKILL cannot be trapped. SIGHUP is generated if your connection hangs up (window closes, etc). So, they all have different meanings.Camper
TTY Demystified has some easily digestable information on how signals interact with the tty subsystem of the kernel. Adds some context to your answer.Freud
Looks like the specs are not very precise, but my understanding is that SIgint asks the program to stop it's current action, not necessarily quit. For a program only designed do one action per run that implies quiting, but for an interactive program that has some sort of read-eval-print loop, it can mean give up on the current eval and go back to reading user input. I think less does that on sigint.Keener
What signal is sent during reboot?Impartible
@Keener thanks, man. I've searched half of the internet and finally found your comment. It's exactly how you say and I've checked it with ftp - this is an interactive program, when typing open hostname the program may block and hitting C-c only stops this open operation and not the whole program! Besides, it should be clear that this is only a hint for the program: other programs may not behave the same way but imo they should handle these signals just like ftp does because it's a good programming practice to make things predictable. Guys, vote for bdsl's comment!Czar
S
20

man 7 signal

This is the convenient non-normative manpage of the Linux man-pages project that you often want to look at for Linux signal information.

Version 3.22 mentions interesting things such as:

The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.

and contains the table:

Signal     Value     Action   Comment
----------------------------------------------------------------------
SIGHUP        1       Term    Hangup detected on controlling terminal
                              or death of controlling process
SIGINT        2       Term    Interrupt from keyboard
SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction
SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal
SIGSEGV      11       Core    Invalid memory reference
SIGPIPE      13       Term    Broken pipe: write to pipe with no
                              readers
SIGALRM      14       Term    Timer signal from alarm(2)
SIGTERM      15       Term    Termination signal
SIGUSR1   30,10,16    Term    User-defined signal 1
SIGUSR2   31,12,17    Term    User-defined signal 2
SIGCHLD   20,17,18    Ign     Child stopped or terminated
SIGCONT   19,18,25    Cont    Continue if stopped
SIGSTOP   17,19,23    Stop    Stop process
SIGTSTP   18,20,24    Stop    Stop typed at tty
SIGTTIN   21,21,26    Stop    tty input for background process
SIGTTOU   22,22,27    Stop    tty output for background process

which summarizes signal Action that distinguishes e.g. SIGQUIT from SIGQUIT, since SIGQUIT has action Core and SIGINT Term.

The actions are documented in the same document:

The entries in the "Action" column of the tables below specify the default disposition for each signal, as follows:

Term   Default action is to terminate the process.

Ign    Default action is to ignore the signal.
Core   Default action is to terminate the process and dump core (see core(5)).
Stop   Default action is to stop the process.
Cont   Default action is to continue the process if it is currently stopped.

I cannot see any difference between SIGTERM and SIGINT from the point of view of the kernel since both have action Term and both can be caught. It seems that is just a "common usage convention distinction":

  • SIGINT is what happens when you do CTRL-C from the terminal
  • SIGTERM is the default signal sent by kill

Some signals are ANSI C and others not

A considerable difference is that:

  • SIGINT and SIGTERM are ANSI C, thus more portable
  • SIGQUIT and SIGKILL are not

They are described on section "7.14 Signal handling " of the C99 draft N1256:

  • SIGINT receipt of an interactive attention signal
  • SIGTERM a termination request sent to the program

which makes SIGINT a good candidate for an interactive Ctrl + C.

POSIX 7

POSIX 7 documents the signals with the signal.h header: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html

This page also has the following table of interest which mentions some of the things we had already seen in man 7 signal:

Signal    Default Action   Description
SIGABRT   A                Process abort signal.
SIGALRM   T                Alarm clock.
SIGBUS    A                Access to an undefined portion of a memory object.
SIGCHLD   I                Child process terminated, stopped,
SIGCONT   C                Continue executing, if stopped.
SIGFPE    A                Erroneous arithmetic operation.
SIGHUP    T                Hangup.
SIGILL    A                Illegal instruction.
SIGINT    T                Terminal interrupt signal.
SIGKILL   T                Kill (cannot be caught or ignored).
SIGPIPE   T                Write on a pipe with no one to read it.
SIGQUIT   A                Terminal quit signal.
SIGSEGV   A                Invalid memory reference.
SIGSTOP   S                Stop executing (cannot be caught or ignored).
SIGTERM   T                Termination signal.
SIGTSTP   S                Terminal stop signal.
SIGTTIN   S                Background process attempting read.
SIGTTOU   S                Background process attempting write.
SIGUSR1   T                User-defined signal 1.
SIGUSR2   T                User-defined signal 2.
SIGTRAP   A                Trace/breakpoint trap.
SIGURG    I                High bandwidth data is available at a socket.
SIGXCPU   A                CPU time limit exceeded.
SIGXFSZ   A                File size limit exceeded.

BusyBox init

BusyBox's 1.29.2 default reboot command sends a SIGTERM to processes, sleeps for a second, and then sends SIGKILL. This seems to be a common convention across different distros.

When you shutdown a BusyBox system with:

reboot

it sends a signal to the init process.

Then, the init signal handler ends up calling:

static void run_shutdown_and_kill_processes(void)
{
    /* Run everything to be run at "shutdown".  This is done _prior_
     * to killing everything, in case people wish to use scripts to
     * shut things down gracefully... */
    run_actions(SHUTDOWN);

    message(L_CONSOLE | L_LOG, "The system is going down NOW!");

    /* Send signals to every process _except_ pid 1 */
    kill(-1, SIGTERM);
    message(L_CONSOLE, "Sent SIG%s to all processes", "TERM");
    sync();
    sleep(1);

    kill(-1, SIGKILL);
    message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
    sync();
    /*sleep(1); - callers take care about making a pause */
}

which prints to the terminal:

The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes

Here is a minimal concrete example of that.

Signals sent by the kernel

Sphygmograph answered 15/4, 2015 at 19:57 Comment(0)
D
10

As DarkDust noted many signals have the same results, but processes can attach different actions to them by distinguishing how each signal is generated. Looking at the FreeBSD kernel source code (kern_sig.c) I see that the two signals are handled in the same way, they terminate the process and are delivered to any thread.

SA_KILL|SA_PROC,             /* SIGINT */
SA_KILL|SA_PROC,             /* SIGTERM */
Diarrhoea answered 28/10, 2010 at 15:49 Comment(0)
Y
10

After a quick Google search for sigint vs sigterm, it looks like the only intended difference between the two is whether it was initiated by a keyboard shortcut or by an explicit call to kill.

As a result, you could, for example, intercept sigint and do something special with it, knowing that it was likely sent by a keyboard shortcut. Perhaps refresh the screen or something, instead of dying (not recommended, as people expect ^C to kill the program, just an example).

I also learned that ^\ should send sigquit, which I may start using myself. Looks very useful.

Yapok answered 29/10, 2010 at 13:39 Comment(0)
F
4

Using kill (both the system call and the utility) you can send almost any signal to any process, given you've got the permission. A process cannot distinguish how a signal came to life and who has sent it.

That being said, SIGINT really is meant to signal the Ctrl-C interruption, while SIGTERM is the general terminal signal. There is no concept of a signal being "more forceful", with the only exception that there are signals that cannot be blocked or handled (SIGKILL and SIGSTOP, according to the man page).

A signal can only be "more forceful" than another signal with respect to how a receiving process handles the signal (and what the default action for that signal is). For example, by default, both SIGTERM and SIGINT lead to termination. But if you ignore SIGTERM then it will not terminate your process, while SIGINT still will.

Foreign answered 28/10, 2010 at 11:23 Comment(0)
M
0

With the exception of a few signals, signal handlers can catch the various signals, or the default behavior upon receipt of a signal can be modified. See the signal(7) man page for details.

Marcellmarcella answered 28/10, 2010 at 11:20 Comment(3)
Yes, but if I don't know "the meaning" of a singnal, catching the signal is pointless, because I won't know what to do in my application. GNU C e.g. explains the difference between SIGQUIT and SIGTERM. But it gives little information about SIGINT: gnu.org/s/libc/manual/html_node/Termination-Signals.htmlHornsby
"The SIGINT (“program interrupt”) signal is sent when the user types the INTR character (normally C-c)." "SIGINT 2 Term Interrupt from keyboard" You hit Ctrl-C, SIGINT is sent. The process normally dies. What more to give?Marcellmarcella
Potentially there could be a description of the intention the programmer should assume the user will have when they hit ctrl-c, I.e.the semantics of the message. As an example the HTTP spec makes clear that when a user sends a GET request the server should not be assume that they wish it to do anything except send back a response.Keener

© 2022 - 2024 — McMap. All rights reserved.