一、Linux信号的基本概念
-
信号的介绍
-
Linux的消息机制是基于信号的
-
携带的信息量少
-
优先级很高
-
-
信号的本质
操作系统给进程发送信号,本质上是往进程的PCB(进程控制块)中写入数据,修改相应的PCB字段,进程在合适的时间去处理所接受的信号。例如:
(1)启动一个前台进程
(2)按下Ctrl+c,产生一个硬件中断
(3)CPU从用户态切换至内核态处理中断,进程的用户区的代码将被暂停执行
(4)终端驱动程序将Ctrl+c解释为一个SIGINT信号,写入该进程的PCB中
(5)内核处理完中断,准备返回内核区前先处理当前进程的未决信号
(6)SIGINT信号的默认处理方式是终止进程,所以不返回用户区
-
系统定义的信号列表
$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 -
信号的详细信息
$man 7 signal Signal Value Action Comment ────────────────────────────────────────────────────────────────────── SIGHUP 1 Term Hangup detected on controlling terminal or death of controlling process SIGINT 2 Term Interrupt from keyboard SIGQUIT 3 Core Quit from keyboard SIGILL 4 Core Illegal Instruction SIGABRT 6 Core Abort signal from abort(3) SIGFPE 8 Core Floating-point exception SIGKILL 9 Term Kill signal SIGSEGV 11 Core Invalid memory reference SIGPIPE 13 Term Broken pipe: write to pipe with no readers; see pipe(7) SIGALRM 14 Term Timer signal from alarm(2) SIGTERM 15 Term Termination signal SIGUSR1 30,10,16 Term User-defined signal 1 SIGUSR2 31,12,17 Term User-defined signal 2 SIGCHLD 20,17,18 Ign Child stopped or terminated SIGCONT 19,18,25 Cont Continue if stopped SIGSTOP 17,19,23 Stop Stop process SIGTSTP 18,20,24 Stop Stop typed at terminal SIGTTIN 21,21,26 Stop Terminal input for background process SIGTTOU 22,22,27 Stop Terminal output for background process ........- Term:终止进程
- Ign:当前进程忽略该信号
- Core:终止进程,并生成一个core文件。默认情况下core文件的大小为0,需要使用
ulimit -c 文件大小指定生成core文件的大小 - Stop:暂停当前进程
- Cont:继续执行当前进程
-
信号的状态
- 产生
- 未决(没有被处理)
- 递达(被处理了)
- 阻塞(阻塞是未决的一种特殊状态)
-
可选的信号的处理动作
-
系统默认的处理动作
-
用户自定义的处理动作
-
忽略
如果不执行系统默认处理动作,需要对信号进行捕捉,但是9号信号(SIGKILL)和19号信号(SIGSTOP)不允许被捕捉,阻塞和忽略。
-
二、信号相关的函数
-
raise/abort
#include <signal.h> //给当前进程发送信号 int raise(int sig); 参数: - sig:要发送的信号 返回值: - 0:成功 - 非0:失败 #include <stdlib.h> //发送SIGABRT信号给当前进程,杀死当前进程 void abort(void); -
kill
#include <sys/types.h> #include <signal.h> //发送信号给指定的进程 int kill(pid_t pid, int sig); 参数: - pid:进程ID - sig:要发送的信号 返回值: - 0:成功 - -1:失败 -
alarm
#include <unistd.h> //倒计时函数,当倒计时结束,函数给当前进程发送一个信号:SIGALRM,终止当前进程 unsigned int alarm(unsigned int seconds); 参数: - seconds:倒计时时长,单位:秒,参数值大于0,参数为0取消倒计时 返回值: 返回倒计时剩余时间 -
setitimer
#include <sys/time.h> //获取定时器当前计时器的值 int getitimer(int which, struct itimerval *curr_value); 参数: - whitch:定时器以什么时间计时 ITIMER_REAL:真实时间,时间到达发送信号:SIGALRM ITIMER_VIRTUAL:用户时间,时间到达发送信号:SIGVALRM ITIMER_PROF:内核时间,时间到达,发送信号:SIGPROF - curr_value:传出参数,记录当前定时器的值 //设置定时器的值 int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value); 参数: - whitch:定时器以什么时间计时 ITIMER_REAL:真实时间,时间到达发送信号:SIGALRM ITIMER_VIRTUAL:用户时间,时间到达发送信号:SIGVALRM ITIMER_PROF:内核时间,时间到达,发送信号:SIGPROF - new_value:设置定时器 - old_value:记录了上次定时器设置的值 struct itimerval { struct timeval it_interval; /* 隔多久触发一次 */ struct timeval it_value; /* 第一次触发定时器的时长 */ }; struct timeval { time_t tv_sec; /* 秒 */ suseconds_t tv_usec; /* 微秒 */ };三、信号捕捉
-
信号捕捉的介绍
进程运行时,PCB中默认有一个阻塞信号集,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,捕捉到该信号后,会调用该函数,函数执行期间的阻塞信号集与默认阻塞信号集不同。
-
信号捕捉的过程
- 进程由于中断、异常或系统调用进入内核
- 内核处理完毕,先处理当前进程的未决信号
- 如果信号有自定义动作,则返回到用户区的信号处理函数
- 信号处理函数执行完毕,返回到内核
- 内核返回到第一步用户区执行的位置
-
信号捕捉函数
-
signal
#include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); 参数: - signum:要捕捉的信号 - handler:接收参数为int,返回值类型为void*的回调函数 handler也可以是特殊的值: SIG_IGN:用于设置信号忽略 SIG_DFL:用于恢复信号的默认处理动作 返回值: - 成功:返回前一次的信号捕捉函数指针,若没有则返回NULL - 失败:返回SIG_ERR -
sigaction
#include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 参数: - signum:要捕捉的信号 - act:捕捉到信号后的处理动作 - oldact:上一次的处理动作 返回值: - 0:成功 - -1:失败 struct sigaction { void (*sa_handler)(int); //回调函数 void (*sa_sigaction)(int, siginfo_t *, void *); //回调函数 sigset_t sa_mask; //阻塞信号集 int sa_flags; //选用哪个回调函数 sa_flags = 0,使用sa_handler sa_flags = SA_SIGINFO,使用sa_sigaction void (*sa_restorer)(void); //废弃了 };
-
四、信号集
-
信号集介绍
在PCB中有两个非常重要的信号集。一个称之为“阻塞信号集”,另一个称之为“未决信号集”。这两个信号集都是内核使用位图机制来实现的。但操作系统不允许我们直接对这两个信号集进行位操作。需自定义另外一个集合,借助信号集操作函数来对PCB中的这两个信号集进行修改。
-
未决信号/阻塞信号
- 未决信号,指的是从信号产生到被处理前的状态。
- 阻塞信号,指的是信号处理动作被阻止,但是不影响信号的产生。
-
信号集相关操作函数
#include <signal.h> //将自定义信号集添加到内核中 int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 参数: - how:决定如何调用该函数 SIG_BLOCK:将用户设置的阻塞信号集添加到内核中,内核原来数据不变 SIG_UNBLOCK:清除用户在内核中设置的数据 SIG_SETMASK:覆盖内核中原来的值 - set:自定义的阻塞信号集 - oldset:上次内核中的阻塞信号集 返回值 - 0:成功 - -1:失败 //将信号集中的数据设置为0 int sigemptyset(sigset_t *set); //将信号集中的数据设置为1 int sigfillset(sigset_t *set); //向信号集中添加阻塞信号 int sigaddset(sigset_t *set, int signum); //将信号从设置好的信号集中删除 int sigdelset(sigset_t *set, int signum); //判断信号是否在信号集中 int sigismember(const sigset_t *set, int signum);
-