Linux-信号产生-注册-注销-处理方式

文章目录

  • 1. 信号的产生
    • 1.1 硬件产生
    • 1.2 软件产生
  • 2. 信号的注册
  • 3. 信号的注销
    • 3.1 非可靠信号
    • 3.2 可靠信号
  • 4. 信号的处理方式

1. 信号的产生

1.1 硬件产生

ctrl + c:SIGINT(2)
ctrl + z:SIGTSTP(20)
ctrl + |:SIGQUIT(3)

  如何查看信号的信息以及查看信号的默认处理动作?

man 7 signal

  操作系统对信号的处理动作:
Linux-信号产生-注册-注销-处理方式_第1张图片
  Term:终止
  Ign:忽略
  Core:终止+产生coredump文件
  Stop:停止
  Cont:继续

如果某一个信号的处理动作是“core”:
  1.默认是需要完成终止进程+产生coredump文件
  2.产生coredump文件,依赖ulimit -a==>“core file size”和磁盘大小
core file size 设置成为unlimited

信号具体的信息:信号的名称 + 信号的值(整数)+ action + 描述
Linux-信号产生-注册-注销-处理方式_第2张图片

1.2 软件产生

kill命令:
  kill [pid]可以终止一个进程
  kill -[num] [pid] :给进程号为pid的进程发送一个信号值为num的信号

kill函数
  int kill(pid_t pid, int sig);
  功能:给pid进程发送sig信号
  给自己发信号
eg:kill (getpid(),9)
  int raise(int sig);
  功能:谁调用给谁发送sig信号

2. 信号的注册

  1.一个进程收到一个信号,这个过程我们称之为注册。
  2.信号的注册和信号的注销并不是一个过程,是两个独立的过程。
  3.信号的注册分为两种情况,非可靠信号的注册和可靠信号的注册
Linux-信号产生-注册-注销-处理方式_第3张图片
  1.在操作系统内核“struct task_struct”结构体内部有一个变量:“struct sigpending pending”
  2.内核定义的结构体“struct sigpending”当中有两个变量:一个是内核定义的双向链表第二个是:sigset_t signal
  3.内核定义的类型“sigset_t”为一个结构体,在结构体内部有一个变量,该变量为一个数组,是无符号长整型的数组
  unsigned long sig[_NSIG_WORDS];

  1.信号的注册本质上就是在使用sig数组,但是并不是按照数组类型的方式在使用,而是按照位图(比特为)的方式在使用:
  eg:某一个信号注册,则将某一个信号对应的比特位置为1
  2.sig数组的比特位个数远远大于62,剩余的比特位为保留位
    struct sigpending ==> sigset_t signal ==> sig[xxx]
  一般在信号注册的时候,称之为操作sig位图(sig[xxx]),内核当中对于注册的时候,还有一个sigqueue队列,信号的注册逻辑位,将信号对应的sig位图当中的比特位置为1,并且在sigqueue队列当中添加一个sigqueue节点;通过注册第一个信号两次,来区分可靠信号和非可靠信号的注册逻辑。

非可靠信号的注册:
第一次:
  1.更改信号对应在sig位图当中的比特位(0–1)
  2.在sigqueue队列当中添加sigqueue节点
第二次:
  1.更改信号对应的sig位图当中的比特位(1–1)
  2.对于第二次的信号,不添加sigqueue节点到sigqueue队列当中
注意:
  如果有多个同一个信号来注册,那么对于非可靠信号而言,只会添加一次sigqueue节点,换言之,只注册了一次。

可靠信号的注册:
第一次:
  1.更改信号对应在sig位图当中的比特位(0–1)
  2.在sigqueue队列当中添加sigqueue节点
第二次:
  1.更改sig位图(1–1)
  2.在sigqueue队列当中添加sigqueue节点
注意:
  如果有多次同一个可靠信号来注册,那么对于可靠信号而言,会添加多次sigqueue节点,换言之,会注册多次

3. 信号的注销

3.1 非可靠信号

  1.将信号对应到sig位图当中的比特位置为0
  2.将对应的非可靠信号的sigqueue节点进行出队操作

3.2 可靠信号

  1.先将可靠信号对应的sigqueue进行出队操作
  2.判断sigqueue队列当中是否有同类的可靠信号的sigqueue节点,如果有,不会将sig位图当中对应的比特位置为0,如果没有,将sig位图当中对应的比特位置为0

Linux-信号产生-注册-注销-处理方式_第4张图片

4. 信号的处理方式

默认处理方式: 在操作系统内核当中定义好了
  宏:SIG_DFL
忽略处理方式: 操作系统定义进程收到某一个信号之后,忽略掉(进程即使收到了某个信号,进程也不会做任何事情)
  宏:SIG_IGN
  eg:僵尸进程:子进程先于父进程退出,子进程会向父进程发送SIGCHLD信号,父进程对SIGCHLD信号是忽略处理的,所以父进程并不会做任何事情,导致子进程的资源没有进程进行回收,从而子进程变成僵尸进程
自定义处理方式:
  1.程序员可以定义某一个信号的处理方式
  2.函数
  typedef void (*sighandler_t)(int);
  sighandler_t signal(int signum,sighandler_t handler);
  signum:待要更改的信号的值
  handler:函数指针,接收一个函数的地址,这个函数没有返回值,有一个int类型的参数自定义signum这个信号的处理方式,定义为handler这个函数指针保存的函数地址对应的函数,换句话说,当进程收到signum这个信号的时候,就会调用handler当中保存的函数。

代码
Linux-信号产生-注册-注销-处理方式_第5张图片
现象
Linux-信号产生-注册-注销-处理方式_第6张图片
  1.signal函数向内核注册了一个信号的处理函数,调用signal函数的时候,并没有调用注册的函数(注册的函数在进程收到进程之后才调用),这种方式称之为“回调”。
  int sigaction(int signum, const struct sigaction *act, struct sigaction * oldact);
  signum:待要自定义处理的信号
  act:要将信号处理方式更改为act
  oldact:原来的处理方式

struct sigaction
{
	void (*sa_hander)(int);//保存信号默认函数处理方式的函数指针
	void (*sa_sigaction)(int, siginfo_t * , void *);//函数指针,但是这个函数指针需要配合sa_flags一起使用,当sa_flags当中的值为SA_SIGINFO的时候,信号处理是按照“sa_sigaction”当中保存的函数地址来处理的
	sigset_t sa_mask;//当进程在处理某一个信号的时候,有可能还会收到其他的信号,此时,其他的信号就暂时存在sa_mask当中。
	int sa_flags;
	void (*sa_restorer)(void);//保留字段
};

你可能感兴趣的:(Linux)