- Unix / Linux — Signals and Traps
- List of Signals
- Default Actions
- Sending Signals
- Trapping Signals
- Cleaning Up Temporary Files
- Ignoring Signals
- Resetting Traps
- All about Linux signals
- Table of Contents:
- What is signaled in Linux
- Signal handlers
- Traditional signal() is deprecated
- The recommended way of setting signal actions: sigaction
- Example use of sigaction()
- SA_SIGINFO handler
- Compiler optimization and data in signal handler
- Atomic Type
- Signal-safe functions
- Alternative method of handling signals: signalfd()
- Linux signals
- Description
- Finding system-specific signals
- Signals in Linux
- Signals not supported by Linux
- Sending signals from the keyboard
- Real-time signals
- Examples: sending signals
- Related commands
Unix / Linux — Signals and Traps
In this chapter, we will discuss in detail about Signals and Traps in Unix.
Signals are software interrupts sent to a program to indicate that an important event has occurred. The events can vary from user requests to illegal memory access errors. Some signals, such as the interrupt signal, indicate that a user has asked the program to do something that is not in the usual flow of control.
The following table lists out common signals you might encounter and want to use in your programs −
Signal Name | Signal Number | Description |
---|---|---|
SIGHUP | 1 | Hang up detected on controlling terminal or death of controlling process |
SIGINT | 2 | Issued if the user sends an interrupt signal (Ctrl + C) |
SIGQUIT | 3 | Issued if the user sends a quit signal (Ctrl + D) |
SIGFPE | 8 | Issued if an illegal mathematical operation is attempted |
SIGKILL | 9 | If a process gets this signal it must quit immediately and will not perform any clean-up operations |
SIGALRM | 14 | Alarm clock signal (used for timers) |
SIGTERM | 15 | Software termination signal (sent by kill by default) |
List of Signals
There is an easy way to list down all the signals supported by your system. Just issue the kill -l command and it would display all the supported signals −
The actual list of signals varies between Solaris, HP-UX, and Linux.
Default Actions
Every signal has a default action associated with it. The default action for a signal is the action that a script or program performs when it receives a signal.
Some of the possible default actions are −
Terminate the process.
Ignore the signal.
Dump core. This creates a file called core containing the memory image of the process when it received the signal.
Stop the process.
Continue a stopped process.
Sending Signals
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.
The other common method for delivering signals is to use the kill command, the syntax of which is as follows −
Here signal is either the number or name of the signal to deliver and pid is the process ID that the signal should be sent to. For Example −
The above command sends the HUP or hang-up signal to the program that is running with process ID 1001. To send a kill signal to the same process, use the following command −
This kills the process running with process ID 1001.
Trapping Signals
When you press the Ctrl+C or Break key at your terminal during execution of a shell program, normally that program is immediately terminated, and your command prompt returns. This may not always be desirable. For instance, you may end up leaving a bunch of temporary files that won’t get cleaned up.
Trapping these signals is quite easy, and the trap command has the following syntax −
Here command can be any valid Unix command, or even a user-defined function, and signal can be a list of any number of signals you want to trap.
There are two common uses for trap in shell scripts −
- Clean up temporary files
- Ignore signals
Cleaning Up Temporary Files
As an example of the trap command, the following shows how you can remove some files and then exit if someone tries to abort the program from the terminal −
From the point in the shell program that this trap is executed, the two files work1$$ and dataout$$ will be automatically removed if signal number 2 is received by the program.
Hence, if the user interrupts the execution of the program after this trap is executed, you can be assured that these two files will be cleaned up. The exit command that follows the rm is necessary because without it, the execution would continue in the program at the point that it left off when the signal was received.
Signal number 1 is generated for hangup. Either someone intentionally hangs up the line or the line gets accidentally disconnected.
You can modify the preceding trap to also remove the two specified files in this case by adding signal number 1 to the list of signals −
Now these files will be removed if the line gets hung up or if the Ctrl+C key gets pressed.
The commands specified to trap must be enclosed in quotes, if they contain more than one command. Also note that the shell scans the command line at the time that the trap command gets executed and also when one of the listed signals is received.
Thus, in the preceding example, the value of WORKDIR and $$ will be substituted at the time that the trap command is executed. If you wanted this substitution to occur at the time that either signal 1 or 2 was received, you can put the commands inside single quotes −
Ignoring Signals
If the command listed for trap is null, the specified signal will be ignored when received. For example, the command −
This specifies that the interrupt signal is to be ignored. You might want to ignore certain signals when performing an operation that you don’t want to be interrupted. You can specify multiple signals to be ignored as follows −
Note that the first argument must be specified for a signal to be ignored and is not equivalent to writing the following, which has a separate meaning of its own −
If you ignore a signal, all subshells also ignore that signal. However, if you specify an action to be taken on the receipt of a signal, all subshells will still take the default action on receipt of that signal.
Resetting Traps
After you’ve changed the default action to be taken on receipt of a signal, you can change it back again with the trap if you simply omit the first argument; so −
This resets the action to be taken on the receipt of signals 1 or 2 back to the default.
Источник
All about Linux signals
Table of Contents:
- All about Linux signals
- Introduction
- What is signaled, signal handlers
- Handling specific signals: SIGCHLD, SIGBUS, SIGSEGV, SIGABRT
- What happens when a process receives a signal, system call interruption
- Blocking signals
- Waiting for a signal
- Sending signals
- Real-time signals
- Signals and fork()
- Signals and threads
- Other uses of signals
- That’s not everything!
What is signaled in Linux
For a complete list of signals see the signal(7) manual page.
Signal handlers
Traditional signal() is deprecated
The recommended way of setting signal actions: sigaction
As you can see you don’t pass the pointer to the signal handler directly, but instead a struct sigaction object. It’s defined as:
For a detailed description of this structure’s fields see the sigaction(2) manual page. Most important fields are:
- sa_handler — This is the pointer to your handler function that has the same prototype as a handler for signal(2).
- sa_sigaction — This is an alternative way to run the signal handler. It has two additional arguments beside the signal number where the siginfo_t * is the more interesting. It provides more information about the received signal, I will describe it later.
- sa_mask allows you to explicitly set signals that are blocked during the execution of the handler. In addition if you don’t use the SA_NODEFER flag the signal which triggered will be also blocked.
- sa_flags allow to modify the behavior of the signal handling process. For the detailed description of this field, see the manual page. To use the sa_sigaction handler you must use SA_SIGINFO flag here.
What is the difference between signal(2) and sigaction(2) if you don’t use any additional feature the later one provides? The answer is: portability and no race conditions. The issue with resetting the signal handler after it’s called doesn’t affect sigaction(2), because the default behavior is not to reset the handler and blocking the signal during it’s execution. So there is no race and this behavior is documented in the POSIX specification. Another difference is that with signal(2) some system calls are automatically restarted and with sigaction(2) they’re not by default.
Example use of sigaction()
In this example we use the three arguments version of signal handler for SIGTERM . Without setting the SA_SIGINFO flag we would use a traditional one argument version of the handler and pass the pointer to it by the sa_handler field. It would be a replacement for signal(2). You can try to run it and do kill PID to see what happens.
In the signal handler we read two fields from the siginfo_t * siginfo parameter to read the sender’s PID and UID. This structure has more fields, I’ll describe them later.
The sleep(3) function is used in a loop because it’s interrupted when the signal arrives and must be called again.
SA_SIGINFO handler
We’ll see more examples of use of siginfo_t later.
Compiler optimization and data in signal handler
What it does? It depends on compiler optimization settings. Without optimization it executes a loop that ends when the process receives SIGTERM or other sgnal that terminates the process and was not handler. When you compile it with the -O3 gcc flag it will not exit after receiving SIGTERM . Why? because whe while loop is optimized in such way that the exit_flag variable is loaded into a processor register once and not read from the memory in the loop. The compiler isn’t aware that the loop is not the only place where the program accesses this variable while running the loop. In such cases — modifying a variable in a signal handler that is also accessed in some other parts of the program you must remember to instruct the compiler to always access this variable in memory when reading or writing them. You should use the volatile keyword in the variable declaration:
Atomic Type
- It doesn’t work like a mutex: it’s guaranteed that read or write of this type translates into an uninterruptible operation but code such as:
Isn’t safe: there is read and update in the if operation but only single reads and single writes are atomic.
- Don’t try to use this type in a multi-threaded program as a type that can be used without a mutex. It’s only intended for signal handlers and has nothing to do with mutexes!
- You don’t need to worry if data are modified or read in a signal handler are also modified or read in the program if it happens only in parts where the signal is blocked. Later I’ll show how to block signals. But you will still need the volatile keyword.
Signal-safe functions
Alternative method of handling signals: signalfd()
First we must block the signals we want to handle with signalfd(2) using sigprocmask(2). This function will be described later. Then we call signalfd(2) to create a file descriptor that will be used to read incoming signals. At this point in case of SIGTERM or SIGINT delivered to your program it will not be interrupted, no handler will be called. It will be queued and you can read information about it from the sfd descriptor. You must supply a buffer large enough to read the struct signalfd_siginfo object that will be filled with information similar to the previously described siginfo_t . The difference is that the fields are named a bit different (like ssi_signo instead of si_signo ). What is interesting is that the sfd descriptor behaves and can be used just like any other file descriptor, in particular you can:
- Use it in select(2), poll(2) and similar functions.
- Make it non-blocking.
- Create many of them, each handling different signals to return different descriptors as ready by select(2) for every different signal.
- After fork() the file descriptor is not closed, so the child process can read signals that were send to the parent.
This is perfect to be used in a single-process server with the main loop executes a function like poll(2) to handle many connections. It simplifies signal handling because the signal descriptor can be added to the poll’s array of descriptors and handled like any other of them, without asynchronous actions. You handle the signal when you are ready for that because your program is not interrupted.
Источник
Linux signals
On Unix-like operating systems such as Linux, signals are software interrupts. They provide a way for the user (or a process) to directly communicate with a process.
Software may be programmed to respond intelligently to a wide array of signals, and certain signals cause processes to behave in a standardized, predefined way at the kernel level.
Description
Process signals were developed as part of UNIX in the 1970s. They are used on all modern Unix-like operating systems, including Linux, BSD, and macOS X.
When a signal is sent to a process, the operating system interrupts the normal flow of the process execution and delivers the notification. If the process has previously registered a way to handle that particular signal, that routine is executed, otherwise the system executes the default signal handler.
Signals can be sent with the kill command, which is named for its default signal (SIGKILL) that instructs the OS to forcefully terminate a process before doing anything else.
Signal names are commonly abbreviated without their SIG prefix, e.g., «KILL», including in the command arguments of kill.
Finding system-specific signals
Signals are defined in the system library signal.h. To view the signals used by your operating system, open a terminal and run man signal or man 7 signal.
Signals in Linux
Signal | Number | Description | Standard |
---|---|---|---|
SIGHUP | 1 | The HUP signal is sent to a process when its controlling terminal is closed. It was originally designed to notify a serial line drop (HUP stands for «Hang Up»). In modern systems, this signal usually indicates the controlling pseudo or virtual terminal is closed. | POSIX |
SIGINT | 2 | The INT signal is sent to a process by its controlling terminal when a user wants to interrupt the process. This signal is often initiated by pressing Ctrl + C , but on some systems, the «delete» character or «break» key can be used. | ANSI |
SIGQUIT | 3 | The QUIT signal is sent to a process by its controlling terminal when the user requests that the process perform a core dump. | POSIX |
SIGILL | 4 | Illegal instruction. The ILL signal is sent to a process when it attempts to execute a malformed, unknown, or privileged instruction. | ANSI |
SIGTRAP | 5 | Trace trap. The TRAP signal is sent to a process when a condition arises that a debugger is tracing — for example, when a particular function is executed, or when a particular variable changes value. | POSIX |
SIGABRT, SIGIOT | 6 | Abort process. ABRT is usually sent by the process itself, when it calls the abort() system call to signal an abnormal termination, but it can be sent from any process like any other signal. SIGIOT is a synonym for SIGABRT. (IOT stands for input/output trap, a signal which originated on the PDP-11.) | 4.2 BSD |
SIGBUS | 7 | The BUS signal is sent to a process when it causes a bus error, such as an incorrect memory access alignment or non-existent physical address. In Linux, this signal maps to SIGUNUSED, because memory access errors of this kind are not possible. | 4.2 BSD |
SIGFPE | 8 | Floating point exception. The FPE signal is sent to a process when it executes erroneous arithmetic operations, such as division by zero. | ANSI |
SIGKILL | 9 | Forcefully terminate a process. With STOP, this is one of two signals which cannot be intercepted, ignored, or handled by the process itself. | POSIX |
SIGUSR1 | 10 | User-defined signal 1. This is one of two signals designated for custom user signal handling. | POSIX |
SIGSEGV | 11 | The SEGV signal is sent to a process when it makes an invalid virtual memory reference, or segmentation fault, i.e., when it performs a segmentation violation. | |
SIGUSR2 | 12 | User-defined signal 2. This is one of two signals designated for custom user signal handling. | POSIX |
SIGPIPE | 13 | The PIPE signal is sent to a process when it attempts to write to a pipe without a process connected to the other end. | POSIX |
SIGALRM | 14 | The ALRM signal notifies a process that the time interval specified in a call to the alarm() system function has expired. | POSIX |
SIGTERM | 15 | The TERM signal is sent to a process to request its termination. Unlike the KILL signal, it can be caught and interpreted or ignored by the process. This signal allows the process to perform nice termination releasing resources and saving state if appropriate. It should be noted that SIGINT is nearly identical to SIGTERM. | ANSI |
SIGSTKFLT | 16 | Stack fault. Maps to SIGUNUSED in Linux. | |
SIGCHLD | 17 | The CHLD signal is sent to a process when a child process terminates, is interrupted, or resumes after being interrupted. One common usage of the signal is to instruct the operating system to clean up the resources used by a child process after its termination without an explicit call to the wait system call. | POSIX |
SIGCONT | 18 | Continue executing after stopped, e.g., by STOP | POSIX |
SIGSTOP | 19 | The STOP signal instructs the operating system to stop a process for later resumption. This is one of two signals, along with KILL that cannot be intercepted, ignored, or handled by the process itself. | POSIX |
SIGTSTP | 20 | The TSTP signal is sent to a process by its controlling terminal to request it to stop temporarily. It is commonly initiated by the user pressing Ctrl + Z . Unlike SIGSTOP, this process can register a signal handler for or ignore the signal. | POSIX |
SIGTTIN | 21 | The TTIN signal is sent to a process when it attempts to read from the tty while in the background. This signal can be received only by processes under job control. Daemons do not have controlling terminals and should never receive this signal. | POSIX |
SIGTTOU | 22 | TTOU signal is sent to a process when it attempts to write from the tty while in the background. The compliment to TTIN. | POSIX |
SIGURG | 23 | The URG signal is sent to a process when a socket has urgent or out-of-band data available to read. | 4.2 BSD |
SIGXCPU | 24 | The XCPU signal is sent to a process when it has used up the CPU for a duration that exceeds a certain predetermined user-settable value. The arrival of an XCPU signal provides the receiving process a chance to quickly save any intermediate results and to exit gracefully, before it is terminated by the operating system using the SIGKILL signal. | 4.2 BSD |
SIGXFSZ | 25 | The XFSZ signal is sent to a process when it grows a file larger than the maximum allowed size. | 4.2 BSD |
SIGVTALRM | 26 | Virtual alarm clock. May be sent by the alarm() system call. By default, this signal kills the process, but it’s intended for use with process-specific signal handling. | 4.2 BSD |
SIGPROF | 27 | Profiling alarm clock. Indicates expiration of a timer that measures CPU time used by the current process («user» time), and CPU time expended on behalf of the process by the system («system» time). These times may be used to implement code profiling facilities. By default, this signal terminates the process, but it’s intended for use with process-specific signal handling. | 4.2 BSD |
SIGWINCH | 28 | Window change. The WINCH signal is sent to a process when its controlling terminal changes size, for instance if you resize it in your window manager. | 4.3 BSD, Sun |
SIGIO, SIGPOLL | 29 | Input/output is now possible. SIGPOLL is a synonym for SIGIO, and in Linux its behavior is identical to SIGURG. | 4.2 BSD |
SIGPWR, SIGLOST | 30 | Power failure. The PWR signal is sent to a process when the system detects a power failure. SIGLOST is a synonym for SIGPWR. | System V |
SIGUNUSED, SIGSYS | 31 | Unused signal. This signal is provided for compatibility reasons, for example when porting software from an operating system with different or unsupported signals in Linux. In Linux, SIGSYS is a synonym for SIGUNUSED. | System V r4 |
Signals not supported by Linux
The following signals may be used by other systems, such as BSD, but are interpreted as SIGUNUSED in Linux.
SIGEMT | The EMT signal is sent to a process when an emulator trap occurs. Unused in Linux. |
SIGINFO | The INFO signal is sent to a process when a status request is received from the controlling terminal. Unused in Linux |
SIGLOST | The LOST signal is sent to a process when a file lock is lost. Unused in Linux. |
SIGSYS | The SYS signal is sent to a process when it passes a bad argument to a system call. Unused in Linux. |
Sending signals from the keyboard
Signals may be sent from the keyboard. Several standard defaults are listed below. Default key combinations for sending interrupt signals can be defined with the stty command.
Ctrl-C | Send SIGINT (Interrupt). By default, this causes a process to terminate. |
Ctrl-Z | Send SIGTSTP (Suspend). By default, this causes a process to suspend all operation. |
Ctrl-\ | Send SIGQUIT (Quit). By default, this causes a process to terminate immediately and dump the core. |
Ctrl-T | Send SIGINFO (Info). By default, this causes the operating system to display information about the command. Not supported on all systems. |
Real-time signals
Real-time signals are a set of signals with no predefined purpose, for programmers to use as they want in their software. Two signal names, SIGRTMIN and SIGRTMAX, define the minimum and maximum signal numbers of the real-time signals. For example, the programmer may use the signal number as SIGRTMIN+3 to refer to the fourth real-time signal number.
Examples: sending signals
The kill command sends signals to processes. Your shell may have a built-in version of kill, which supersedes the version installed at /bin/kill. The two versions have slightly different options, but basic functions are the same. The following examples may run using either version of kill.
The process to be signaled is referred to by PID (process ID). If you’re not sure of the process ID, you can find it with the ps command, for example ps -aux.
Send the KILL signal to the process with PID 1234.
Kill three processes: PIDs 123, 456, and 789.
Send signal number 15 (TERM) to processes 1234 and 5678.
Same as the previous command.
List all available signals. Example output:
The special process ID -1 refers to all processes other than kill and the system root process. This command attempts to kill (-9) every possible process (-1) on the system. For more information, see the documentation of kill, linked below.
Related commands
kill — End a process.
stty — Change terminal line settings.
Источник