Basic concepts
The signal is a common concept in Linux, for example, we interrupt the foreground process by pressing CTRL + C, and ending the process through the kill command is done through the signal. The following is an example of CTRL + C for a simple description of the signal processing flow:
- The user presses CTRL-C and the keyboard input produces a hardware interrupt.
- The process's user-space code pauses execution, and the CPU switches from the user state to the kernel-state processing hardware interrupt.
- The terminal driver interprets the ctrl-c as a SIGINT signal, which is recorded in the PCB of the process (it can also be said that a SIGINT signal is sent to the process).
- When the kernel returns to the process's user space code before proceeding, the signal recorded in the PCB is processed first, and a SIGINT signal is found to be processed, and the default processing action of this signal is to terminate the process, so the process is terminated directly and no longer returns its user space code execution.
Use the Kill-l command to view a list of system-defined signals:
$ kill–l 1) SIGHUP 2) SIGINT 3) Sigquit 4) Sigill 5) SIGTRAP 6) SIGABRT 7) Sigbus 8) SIGFPE 9) SIGKILL) sigusr 1) SIGSEGV) SIGUSR213) sigpipe) sigalrm) SIGTERM) SIGSTKFLT17) SIGCHLD (SIGSTOP) SIGTSTP21) sigttin) Sigttou (Sigurg) SIGXCPU25) sigxfsz) sigvtalrm SIGPROF) (SIGWINCH29) SIGIO) SIGPWR Sigsys) SIGRTMIN35 sigrtmin+1) sigrtmin+2 37 ) (sigrtmin+3) sigrtmin+439) sigrtmin+5 () sigrtmin+6) sigrtmin+7) sigrtmin+843) sigrtmin+9 (sigrtmin+11) sigrtmin+1247) (sigrtmin+13) sigrtmin+14) sigrtmin+15) SIGRTMAX-1451) SIGRTMAX-13 -12 SIGRTMAX-11) SIGRTMAX-1055) SIGRTMAX-9 () SIGRTMAX-8 () SIGRTMAX-7) SIGRTMAX-659) SIGRTMAX-5 MAX-4) SIGRTMAX-3 (SIGRTMAX-263) SIGRTMAX-1) Sigrtmax
Each signal has a number and a macro definition name, which can be found in signal.h and can be viewed through the man signal (7) For detailed instructions:
Signal Value Action Comment-------------------------------------------------------------------------SIGHUP 1 Term Hangup detected on controlling terminal or death of controlling processSIGINT 2 Term Interrupt from keyboardSIGQUIT 3 Core Quit from keyboardSIGILL 4 Core Illegal Instruction...
The main conditions for generating signals are:
用户在终端按下某些键时,终端驱动程序会发送信号给前台进程。例如常见的Ctrl-C产生SIGINT信号,Ctrl-\产生SIGQUIT信号,Ctrl-Z产生SIGTSTP信号。硬件异常产生信号,这些条件由硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。一个进程调用kill函数可以发送信号给另一个进程。当内核检测到某种软件条件发生时也可以通过信号通知进程,例如闹钟超时产生SIGALRM信号,向读端已关闭的管道写数据时产生SIGPIPE信号。
Capturing signals
If you do not want to process the signal by default action, the user program can call the Sigaction function to take over the processing flow of the signal. Because the code of the signal processing function is in the user space, the processing process is more complicated, for example, as follows:
- The user program registers the processing function Sighandler of the sigquit signal.
- The main function is currently executing, when an interrupt or exception switch to the kernel state occurs.
- The signal sigquit recursion is checked before returning to the main function of the user state after the interrupt processing is complete.
- Instead of resuming the context of the main function after the kernel decides to return to the user state, the Sighandler function is executed, and the Sighandler and main functions use different stack spaces, and there is no call or call relationship between them, and it is two independent control processes.
- The Ighandler function returns and automatically executes a special system call Sigreturn again into the kernel state.
- If there is no new signal to be reached, this time back to the user state is resumed the context of the main function continues to execute.
The Sigaction function can read and modify the processing action associated with the specified signal, which is declared as follows:
#include <signal.h>int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
The key is the second parameter, act, which is a sigaction type with the following structure:
struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void);};
The key is sa_handler this parameter, it can usually have the following assignment:
- Constant sig_ign means ignoring the signal
- The constant SIG_DFL represents the execution of the system default action, which is typically used to restore signal processing
- Assignment to a function pointer means capturing a signal with a custom function
In addition, if the signal processing function is called, in addition to the current signal is automatically shielded, but also want to automatically block other signals, the Sa_mask field is used to illustrate these signals that require additional shielding, when the signal processing function returned automatically restore the original signal mask word.
Here is a simple example of how to implement the process of capturing the signal, the function is relatively simple, that is, when CTRL + C does not exit directly, but first output a gorgeous split line before exiting.
#include <stdio.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>void show_and_exit(int sig){ printf("\n----------------------------\n"); exit(0);}int main(void){ struct sigaction act = {0}, oldact = {0}; act.sa_handler = show_and_exit; //act.sa_flags = SA_RESETHAND | SA_NODEFER; //sigaddset(&act.sa_mask, SIGQUIT); sigaction(SIGINT, &act, &oldact); int count = 0; while(1) { sleep(1); printf("sleeping %d\n", count++); }}
The result of executing the function is as follows:
$./signsleeping 0sleeping 1sleeping 2sleeping 3sleeping 4----------------------------$
From for notes (Wiz)
Linux advanced Programming--11. Signal