- The various different signals and their purposes
- the circumstances in which the kernel may generate a signal for a process, and the syscall that one process may use to send a signal to another process
- how a process responds to a signal by default, and the means by which a process can change its response to a signal
- the use of a process signal mask to block signals, and the associated notion of pending signals
- how a process can suspend execution and wait for the delivery of a signal
Concepts and Overview
A signal is a notification to a process that an event has occurred. Signals are sometimes described as software interrupts. Signals are analogous to hardware interrupts in that they interrupt the normal flow of execution of a program.
Cases that kernel send signals to process:
- A hardware exception occurred, meaning that the hardware detected a fault condition that was notified to the kernel
- The user typed on of the terminal special characters that generate signals (ctrl+c, crtl+z)
- A software event occurred
Each signal is defined as a unique integer, starting sequentially from 1. (<signal.h>
, SIGxxxx
)
A pending signal is not always delivered to a process as soon as it is next scheduled to run.
Upon delivery of a signal, a process carries out one of the following default actions:
- The signal is ignored
- The process is terminated
- A core dump file is generated, and the process is terminated
- The process is stopped-execution of the process is suspended
- Execution of the process is resumed after previously being stopped
Signal types and default actions
Signal | Serial number | desc | default |
---|---|---|---|
SIGABRT | 6 | Abort process | core |
SIGALRM | 14 | Real-time timer expired | term |
SIGBUS | 7 | Memory access error | core |
SIGCHLD | 17 | Child terminated or stopped | ignore |
SIGCONT | 18 | Continue if stopped | cont |
SIGEMT | undef | Hardware fault | term |
SIGFPE | 8 | Arithmetic exception | core |
SIGHUG | 1 | Hangup | term |
SIGILL | 4 | Illegal instruction | core |
SIGINT | 2 | Terminal interrupt | term |
SIGIO / SIGPOLL | 29 | I/O possible | term |
SIGKILL | 9 | Sure Kill | term |
SIGPIPE | 13 | Broken pipe | term |
SIGPROF | 27 | Profiling timer expired | term |
SIGPWR | 30 | Power about to fail | term |
SIGQUIT | 3 | Terminal quit | core |
SIGSEGV | 11 | Invalid memory reference | core |
SIGTKFLT | 16 | Stack fault on coprocessor | term |
SIGSTOP | 19 | Sure stop | stop |
SIGSYS | 31 | Invalid system call | core |
SIGTERM | 15 | Terminate process | term |
SIGTRAP | 5 | Trace/breakpoint trap | core |
SIGTSTP | 20 | Terminal stop | stop |
SIGTTIN | 21 | Terminal read from BG | stop |
SIGTTOU | 22 | Terminal write from BG | stop |
SIGTURG | 23 | Urgent data on socket | ignore |
SIGUSR1 | 10 | User-defined signal 1 | term |
SIGUSR2 | 12 | User-defined signal 2 | term |
SIGVTALRM | 26 | Virtual timer expired | term |
SIGWINCH | 28 | Terminal window size change | ignore |
SIGXCPU | 24 | CPU time limit exceeded | core |
SIGXFSZ | 25 | File size limit exceeded | core |
Changing Signal Dispositions: signal()
|
|
Simple Sampler
|
|
Introduction to Signal Handlers
调用信号处理程序可能会随时打断主程序流程;内核代表进程来调用信号处理程序,当程序返回是,主程序会在被打断的地方恢复执行。
|
|
Sending signals: kill()
|
|
pid 的处理逻辑
- 如果 pid 大于 0,发送至 pid 指定的进程
- 如果 pid 等于 0,发送至与调用进程同组的每个进程
- 如果小于-1,那么会向组 id 等于该 pid 绝对值的进程组内所有子进程发送信号
- 如果 pid 等于-1,那么信号的发送范围:调用进程有权将信号发往每个目标进程,出去 init 和调用者本身
kill 所需权限
- 特权级(CAP_KILL)进程可以向任何进程发送信号
- init 是特例,仅能接收已配置 SigHandler 的信号
- 如果发送者的实际或有效用户 ID 匹配于接收者的实际用户 ID 活着保存设置用户 ID,那么非特权进程也可以向另一进程发送信号
Checking for the existence of a process
可以通过 kill(pid, 0)
来检查进程是否存在。
- 发送空信号失败,且 errno 为 ESRCH,则证明目标进程不存在
- 发送空信号失败,且 errno 为 EPERM,或调用成功,则表示进程存在
Other ways of sending signals: raise()
and killpg()
|
|
- single-threaded program:
kill(getpid(), sig);
- multi-threaded program:
pthread_kill(pthread_self(), sig);
killpg()
sends a signal to all of the members of a process group. kill(-pgrp, sig)
|
|
Displaying signal descriptions
|
|
Each signal has an associated printable description, those are listed in the array sys_siglist
.
strsignal
performs bounds checking on the sig argument, and then returns a pointer to a printable description of the signal, or a pointer to an error string if the signal number was invalid.psignal
displays the string given in its argument msg.
Signal Sets
Multiple signals are represented using a data structure called a signal set
, provided by the system data type sigset_t
.
|
|
sigemptyset
initializes a signal set to contain no memberssigfillset
initializes a set to contain all signals (including all realtime signals)
|
|
The signal mask (Blocking Signal Delivery)
For each process, the kernel maintains a signal mask
- a set of signals whose delivery to the process is currently blocked. If a signal that is blocked is sent to a process, delivery of that signal is delayed untial it is unblocked by being removed from the process signal mask.
add signal to the signal mask:
- When a signal handler is invoked, the signal that caused its invocation can be automatically added to the signal mask
- When a signal handler is established with
sigaction
, it is possible to specify an additional set of signals that are to be blocked when the handler is invoked
|
|
how
determines the changes that sigprocmask
makes to the signal mask:
- SIG_BLOCK -> the signal mask is set to the union of its current value and
set
- SIG_UNBLOCK -> remove the signal
set
from the signal mask - SIT_SETMASK -> assign the
set
to signal mask
Temporarily blocking delivery of a signal
|
|
Pending signals
If a process receives a signal that it is currently blocking, that signal is added to the process’s set of pending signals. When (and if) the signal is later unblocked, it is then delivered to the proess.
sigpending
determines which signals are pending.
|
|
Signals are not queued
The set of pending signals is only a mask; it indicates whether or not a signal has occurred, but not how many times it has occurred. (Receive Many, Deliver Once)
|
|
Changing signal dispositions: sigaction()
|
|
The sig
argument identifies the signal whose disposition we want to retrieve or change. This argument can be any signal except SIGKILL
or SIGSTOP
.
Waiting for a signal: pause()
Calls pause()
suspend execution of the process until the call is interrupted by a signal handler (or until an unhandled signal terminates the process)
|
|
Summary
A signal is a notification that some kind of event has occurred, and may be sent to a process by the kernel, by another process, or by itself. There is a range of standard signal types, each of which has a unique number and purpose.
Signal delivery is typically asynchronous, meaning that the point at which the signal interrupts execution of the process is unpredictable. In some cases (hardware-generated signals), signals are delivered synchronously, meaning that delivery occurs predictably and reproducibly at a certain point in the execution of a program.
By default, a signal either is ignored, terminated a process (optional core dump), stops a running process, or restarts a stopped process. The particular default action depends on the signal type. Alternatively, a program can use signal()
or sigaction()
to explicitly ignore a signal or to establish a programmer-defined signal handelr function that is invoked when the signal is delivered. For portability reasons, establishing a signal handler is best performed using sigaction()
.
A process (with suitable permissions) can send signal to another process using kill()
. Sending the num signal(0) is a way of determining if a particular process ID is in use.
Each process has a signal mask, which is the set of signals whose delivery is currently blocked. Signals can be aded to and removed from the signal mask using sigprocmask()
.
If a signal is received while it is blocked, then it remains pending until it is unblocked. Standard signals can’t be queued; that is, a signal can be marked as pending (and thus later delivered) only once. A process can use the sigpending()
syscall to retrieve a signal set (a data structure used to represent multiple different signals) identifying the signals that it has pending.
The sigaction()
syscall provides more control and flexibility than signal()
when setting the disposition of a signal. First, we can specify a set of additional signals to be blocked when a handler is invoked. In addition, various flags can be used to control the actions that occur when a signal handler is invoked. For example, there are flags that select the older unreliable signal semantics (not blocking the signal causing invocation of a handler, and having the disposition of the signal reset to its default before the handler is called).
Using pause()
, a process can suspend execution until a signal arrives.