36

I sometimes get a little confused by all of the signals that a process can receive. As I understand it, a process has a default handler (signal disposition) for each of these signals, but it can provide its own handler by calling sigaction().

So here is my question: what causes each of the signals to be sent? I realize that you can manually send signals to running processes via the -s parameter to kill, but what are the natural circumstances under which these signals are sent? For example, when does SIGINT get sent?

Also, are there any restrictions on which signals can be handled? Can even SIGSEGV signals be processed and control returned to the application?

3

3 Answers 3

53

In addition to processes calling kill(2), some signals are sent by the kernel (or sometimes by the process itself) in various circumstances:

  • Terminal drivers send signals corresponding to various events:
    • Key press notifications: SIGINT (please go back to the main loop) on Ctrl+C, SIGQUIT (please quit immediately) on Ctrl+\, SIGTSTP (please suspend) on Ctrl+Z. The keys can be changed with the stty command.
    • SIGTTIN and SIGTTOU are sent when a background process tries to read or write to its controlling terminal.
    • SIGWINCH is sent to signal that the size of the terminal window has changed.
    • SIGHUP is sent to signal that the terminal has disappeared (historically because your modem had hung up, nowadays usually because you've closed the terminal emulator window).
  • Some processor traps can generate a signal. The details are architecture and system dependent; here are typical examples:
    • SIGBUS for an unaligned access memory;
    • SIGSEGV for an access to an unmapped page;
    • SIGILL for an illegal instruction (bad opcode);
    • SIGFPE for a floating-point instruction with bad arguments (e.g. sqrt(-1)).
  • A number of signals notify the target process that some system event has occured:
    • SIGALRM notifies that a timer set by the process has expired. Timers can be set with alarm, setitimer and others.
    • SIGCHLD notifies a process that one of its children has died.
    • SIGPIPE is generated when a process tries to write to a pipe when the reading end has been closed (the idea is that if you run foo | bar and bar exits, foo gets killed by a SIGPIPE).
    • SIGPOLL (also called SIGIO) notifies the process that a pollable event has occured. POSIX specifies pollable events registered through the I_SETSIG ioctl. Many systems allow pollable events on any file descriptor, set via the O_ASYNC fcntl flag. A related signal is SIGURG, which notifies of urgent data on a device (registered via the I_SETSIG ioctl) or socket.
    • On some systems, SIGPWR is sent to all processes when the UPS signals that a power failure is imminent.

These lists are not exhaustive. Standard signals are defined in signal.h.

Most signals can be caught and handled (or ignored) by the application. The only two portable signals that cannot be caught are SIGKILL (just die) and STOP (stop execution).

SIGSEGV (segmentation fault) and its cousin SIGBUS (bus error) can be caught, but it's a bad idea unless you really know what you're doing. A common application for catching them is printing a stack trace or other debug information. A more advanced application is to implement some kind of in-process memory management, or to trap bad instructions in virtual machine engines.

Finally, let me mention something that isn't a signal. When you press Ctrl+D at the beginning of a line in a program that's reading input from the terminal, this tells the program that the end of the input file is reached. This isn't a signal: it's transmitted via the input/output API. Like Ctrl+C and friends, the key can be configured with stty.

7
  • And SIGHUP, your modem has hung up. :-)
    – Keith
    Jan 24, 2011 at 7:10
  • 1
    Another thing to note: SIGFPE, somewhat unintuitively, is also signaled on integer divide-by-zero, and sometimes on signed integer overflow.
    – ephemient
    Jan 24, 2011 at 19:53
  • @ephemient does not happen on Ubuntu 18.04 with bash/dash, when I execute echo $((1/0)).
    – jarno
    Mar 21, 2020 at 10:12
  • 1
    @jarno It's raised by the kernel if a process attempts it. Most higher-level languages, including shells, check before dividing. Mar 21, 2020 at 19:23
  • As for SIGPOLL, I tried killing by that signal in Dash and Bash, but it gave 'kill: SIGPOLL: invalid signal specification' or similar error message.
    – jarno
    Jul 5, 2020 at 9:30
22

To answer your second question first: SIGSTOP and SIGKILL cannot be caught by the application, but every other signal can, even SIGSEGV. This property is useful for debugging -- for instance, with the right library support, you could listen for SIGSEGV and generate a stack backtrace to show just where that segfault happened.

The official word (for Linux, anyway) on what each signal does is available by typing man 7 signal from a Linux command line. http://linux.die.net/man/7/signal has the same information, but the tables are harder to read.

However, without some experience with signals, it's hard to know from the short descriptions what they do in practice, so here's my interpretation:

Triggered from the keyboard

  • SIGINT happens when you hit CTRL+C.
  • SIGQUIT is triggered by CTRL+\, and dumps core.
  • SIGTSTP suspends your program when you hit CTRL+Z. Unlike SIGSTOP, it is catchable, which gives programs like vi a chance to reset the terminal to a safe state before suspending themselves.

Terminal interactions

  • SIGHUP ("hangup") is what happens when you close your xterm (or otherwise disconnect the terminal) while your program is running.
  • SIGTTIN and SIGTTOU pause your program if it tries to read from or write to the terminal while it's running in the background. For SIGTTOU to happen, I think the program needs to be writing to /dev/tty, not just default stdout.

Triggered by a CPU exception

These mean your program tried to do something wrong.

  • SIGILL means an illegal or unknown processor instruction. This might happen if you tried to access processor I/O ports directly, for example.
  • SIGFPE means there was a hardware math error; most likely the program tried to divide by zero.
  • SIGSEGV means your program tried to access an unmapped region of memory.
  • SIGBUS means the program accessed memory incorrectly in some other way; I won't go into details for this summary.

Process interaction

  • SIGPIPE happens if you try to write to a pipe after the pipe's reader closed their end. See man 7 pipe.
  • SIGCHLD happens when a child process you created either quits or is suspended (by SIGSTOP or similar).

Useful for self-signaling

  • SIGABRT is usually caused by the program calling the abort() function, and causes a core dump by default. Sort of a "panic button".
  • SIGALRM is caused by the alarm() system call, which will cause the kernel to deliver a SIGALRM to the program after a specified number of seconds. See man 2 alarm and man 2 sleep.
  • SIGUSR1 and SIGUSR2 are used however the program likes. They could be useful for signaling between processes.

Sent by the administrator

These signals are usually sent from the command prompt, via the kill command, or fg or bg in the case of SIGCONT.

  • SIGKILL and SIGSTOP are the unblockable signals. The first always terminates the process immediately; the second suspends the process.
  • SIGCONT resumes a suspended process.
  • SIGTERM is a catchable version of SIGKILL.
2
  • Which signal is sent when the shutdown command is used? Jan 24, 2011 at 0:51
  • That depends on the shutdown scripts. Typically, SIGTERM is sent first, followed by a delay, followed by SIGKILL. In principle, for a hard, immediate shutdown, the kernel doesn't need to send a signal at all; it could just stop running the process.
    – Jander
    Jan 24, 2011 at 6:28
1

This is a supplement or addition to other answers already given, including these:

  1. List of Kill Signals [duplicate]_
  2. What causes various signals to be sent?

For an even more-detailed explanation of most of these signals, see Wikipedia: https://en.wikipedia.org/wiki/Signal_(IPC)

One of the most-common signals is the SIGINT (or just INT) program interrupt signal sent by pressing Ctrl + C while a process is running.

From the Wikipedia article above:

SIGINT

"Signal interrupt"
The SIGINT signal is sent to a process by its controlling terminal when a user wishes to interrupt the process. This is typically initiated by pressing Ctrl+C, but on some systems, the "delete" character or "break" key can be used.[12]

How to manually send any signal to any running process

What causes various signals to be sent [to a running process]?

In addition to other programs or keystrokes causing signals to be sent, you do!

Run kill -l or kill --list to list all signals you can send to a running process.

Example run and output:

$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX    

So, to send the "alarm" signal (as SIGALRM, ALRM, or signal number 14), for example, you can do any one of the following:

kill -SIGALRM <pid>
kill -ALRM <pid>
kill -14 <pid>

Example kill commands to send the alarm signal to pid 123456:

kill -SIGALRM 123456
kill -ALRM 123456
kill -14 123456

Read this from man kill (emphasis added):

DESCRIPTION

The default signal for kill is TERM. Use -l or -L to list available signals. Particularly useful signals include HUP, INT, KILL, STOP, CONT, and 0. Alternate signals may be specified in three ways: -9, -SIGKILL or -KILL. Negative PID values may be used to choose whole process groups; see the PGID column in ps command output. A PID of -1 is special; it indicates all processes except the kill process itself and init.

To find any process ID (pid) of interest, run this:

ps aux | grep "some program name string or regular expression to search for"

Look for the signal number in the far left of the output row. The 2nd column from the left is the PID (Process ID) number.

How to trap any signal in your program

1. In Bash

To "trap", or catch and act on a signal in a custom bash program you can do the following (this traps the SIGALRM signal):

trap <any_comand_to_run_when_signal_is_received> SIGALRM

Here is a common trap I use to capture the Ctrl + C "interrupt" (SIGINT, INT, or signal number 2) signal in my custom bash programs:

# Trap the Ctrl + C SIGINT signal from this point onward in the bash program so
# that whenever the user presses Ctrl + C, this program prints `Ctrl + C` and
# then exits with exit code 2 (change that to any exit code you'd like to
# return when Ctrl + C is pressed!).
trap 'printf "%s\n" " Ctrl + C"; exit 2' SIGINT

See: Server Fault: Bash Loop - How to stop the loop when I press Control-C inside a command?.

2. In C and C++

To trap and act on any given signal in C or C++ on Linux you can use sigaction() (best) or signal() (not as good, but part of the C standard). See my comprehensive answer on that here, with detailed usage examples: Stack Overflow: What is the difference between sigaction and signal?

Examples of sending (via kill) and trapping (via trap) signals in bash

Search for the trap command (which receives and acts on a signal) and kill command (which sends a signal to a process) in these programs:

  1. See this bash Centipede game:
    1. Ask Ubuntu: Command-line snake game?
    2. In my eRCaGuy_hello_world repo here: centipede_game.sh

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .