摘要:
- 本章讲述了信号和信号处理;介绍了信号和中断的统一处理,有助于从正确的角度看待信号;将信号视为进程中断,将进程从正常执行转移到信号处理;
- 解释了信号的来源,包括来自硬件、异常和其他进程的信号;然后举例说明了信号在Unix/Linux中的常见用法;
- 详细解释了Unix/Linux中的信号处理,包括信号类型、信号向量位、信号掩码位、进程PROC结构体中的信号处理程序以及信号处理步骤;
- 用示例展示了如何安装信号捕捉器来处理程序异常,如用户模式下的段错误;还讨论了将信号用作进程间通信(IPC)机制的适用性。
一、知识点归纳
信号和中断
中断是从I/O设备或协处理器发送到CPU的外部请求,将CPU从正常执行转移到中断处理。信号是发送给进程的请求,将进程从正常执行转移到中断处理。
(1)人员中断
人员的每个动作函数都是通过本能或经验实现的,每个中断都分配由一个唯一的ID识别号和一个预先安装的动作函数,人在收到中断请求时“执行”动作函数。
- 来自硬件的中断
- 来自其他人的中断
- 自己造成的中断
- 不可屏蔽(NMI)
- 可屏蔽
(2)进程中断
每个进程中断都被转换为一个唯一ID号,发送给进程。Unix/Linux中的进程中断成为信号,编号为1—31.进程也可屏蔽某些类型的信号以推迟处理,必要时可能修改信号动作函数。
- 来自硬件的中断:终端、间隔定时器的“^C”组合键等。
- 来自其他进程的中断:kill(pid,SIG#)、death_of_child等。
- 自己造成的中断:除以0、无效地址等。
(3)硬件中断
每个中断都有唯一的中断向量号。CPU不会导致任何自己造成的中断(除非出错)。
- 来自硬件的中断:定时器、I/O设备等。
- 来自其他处理器的中断:FFP、DMA、多处理器系统中的其他CPU。
- 自己造成的中断:除以0、保护错误、INT指令。
(4)进程的陷阱错误
进程可能会自己造成中断,是由被CPU识别为异常的错误引起的(除以0、无效地址、非法指令、越权……),它会陷入操作系统内核,将陷阱原因转换为信号编号发送给自己。
Unix/Linux信号示例
- Ctrl+C组合键:转换为SIGINT(2)信号,发送给终端,终止当前运行的进程。进程对大多数信号的默认操作是调用内核的kexit(exitValue)函数来终止。
- 用户可使用
nohup a.out
命令在后台运行程序,nohup会使sh复刻子进程来执行程序,但子进程会忽略SIGNUP(1)信号。 - 通过
ps -u LTD
发现后台进程仍在运行,可使用kill pid (or kill -s 9 pid)
杀死进程。执行杀死的进程向pid标识的目标进程发送一个SIGTERM(15)信号,请求它死亡。
如果进程忽略该信号,可能拒绝死亡,可以使用kill -s 9 pid
必能杀死。
Unix/Linux中的信号处理
1.信号类型
Unix/Linux支持31种不同的信号,每种信号在signal.h文件中都有定义,每种信号都有一个符号名。
#define SIGHUP 1 #define SIGINT 2 #define SIGQUIT 3 #define SIGILL 4 #define SIGTRAP 5 #define SIGABRT 6 #define SIGIOT 6 #define SIGBUS 7 #define SIGFPE 8 #define SIGKILL 9 #define SIGUSR1 10 #define SIGSEGV 11 #define SIGUSR2 12 #define SIGPIPE 13 #define SIGALRM 14 #define SIGTERM 15 #define SIGSTKFLT 16 #define SIGCHLD 17 #define SIGCONT 18 #define SIGSTOP 19 #define SIGTSTP 20 #dpfine STGTTTN 21 #define SIGTTOU 22 #define SIGURG 23 #define SIGXCPU 24 #define SIGXFSZ 25 #define SIGVTALRM 26 #define SIGPROF 27 #define SIGWINCH 28 #define SIGPOLL 29 #define SIGPWR 30 #define SIGSYS 31
2.信号来源
- 来自硬件中断的信号
中断健(Ctrl+C)产生一个SIGINT(2)信号
间隔定时器:SIGALRM(14)、SIGVTALRM(26)或SIGPROF(27)
其他硬件错误:总线错误、I/O陷阱等 - 来自异常的信号
SIGFPE(8):浮点异常(除以0)
SIGSEGV(11):段错误 - 来自其他进程的信号
可使用kill(pid,sig)系统调用向pid标识的目标进程发送信号。
信号处理步骤
- 处于内核模式会检查思念好并处理未完成的信号。
- 重置用户安装的信号捕捉函数
- 信号和唤醒
信号与异常
- 进程遇到异常,会陷入内核模式。若在内核模式下发生异常,则打印一条PANIC错误信息并停止;若在用户模式下发生异常,则终止并以内存转储进行调试。
- 让进程通过预先安装的信号捕捉函数处理用户模式下的程序错误。
- 特殊情况下,会让某个进程通过信号杀死另一个进程。
Linux中的IPC
- 管道和FIFO
- 信号
- System V IPC
- POSIX消息队列
- 线程同步机制
- 套接字
二、实践
段错误捕捉函数
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<signal.h> #include<setjmp.h> #include<string.h> jmp_buf env; int count = 0; void handler(int sig, siginfo_t *siginfo, void *context) { printf ("handler: sig=%d from PID=%d UID=%d count=%d\n", sig, siginfo->si_pid, siginfo->si_uid, ++count); if (count >= 4) // let it occur up to 4 times longjmp(env, 1234); } int BAD() { int *ip = 0; printf("in BAD(): try to dereference NULL pointer\n"); *ip = 123; // dereference a NULL pointer printf("should not see this line\n"); } int main (int argc, char *argv[]) { int r; struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_sigaction = &handler; act.sa_flags = SA_SIGINFO; sigaction(SIGSEGV,&act,NULL); if ((r = setjmp(env)) == 0) BAD(); else printf("proc %d survived SEGMENTATION FAULT: r=%d\n",getpid(), r); printf("proc %d looping\n",getpid()); while(1); }
标签:中断,pid,笔记,学习,进程,int,信号,第六章,define From: https://www.cnblogs.com/MRC-/p/16841904.html