linux信号机制代码,Linux的信号机制

信号signal,是Linux进程间通信(IPC)的基础机制之一,也是Linux内核的进程管理的关键机制之一。

例如:

1,程序中经常出现的段错误SIGSEGV,就是系统内核检测到内存错误之后发给进程的信号,结果就是进程退出并留下core文件,以备程序员查BUG。

2,手工杀进程时发送的kill -9 进程pid,也是给目标进程发送信号9(SIGKILL),让进程退出。

3,还一个是TCP连接被对方关闭之后的SIGPIPE,也是常见的信号。

在服务器程序里需要忽略该信号,防止服务被它打断。

4,检测另一个进程是否还存在,则可以发送信号0。如果不存在时会返回-1并且设置ESRCH错误码,存在则返回0。

5,最后一个就是子进程退出时会给父进程发送SIGCHILD,用于提示父进程调用wait()回收子进程的遗留资源。

下图为Linux man手册对发送信号的kill()函数的介绍,只有两个参数,一个是进程号,一个是信号数字。

3ee02b1c44fb6190da025305d67416eb.png

系统有默认的信号处理函数,一般都是让进程退出,也可以自定义或者忽略某些信号(SIGKILL和SIGSTOP除外,这俩不能忽略,不可拦截)。

信号处理函数的设置是signal()系统调用,它的定义见下图:

两个参数,一个是信号数字,一个是处理函数的指针。如果把处理函数的指针设为SIG_IGN则忽略该信号。

处理函数只有一个参数,int型的信号数字,返回值类型为void,即没有返回值。

它是在进程收到信号之后由Linux系统使用的函数,与进程的代码是异步执行,没法把信号处理结果同步返回给进程代码,所以返回值为void。

6f0a33b4a3f814e36a7247ab7d856776.png

在我们上篇模拟fork()的程序上稍加修改,就可以模拟信号处理。

如下图,先在task_t里加一个signal变量。

这里用了intptr_t类型,它的字节数与void*一样都是8,计算偏移量比较简单。

这次因为参数太多了,我们把task_t的指针传给switch_to()函数,然后用偏移量去访问它的各个成员变量。

2ef57ae428c9cc915975e522d6f34802.png

下图是信号处理函数t_signal(),和发送函数t_kill(),为了简单直接把task_t的指针传过去,就不需要根据id去找这个指针了。

发送信号的t_kill()函数就是设置t->signal = signal,t为目标进程的task_t指针,这样信号就发送到了。

59b467379062db31bff28f0e8cc4c0c9.png

信号处理函数t_signal()在进程调度的时候异步调用,与进程的主代码无关。

我们在进程每次被调度执行的时候,在返回主代码之前,处理信号。

24(%rsi)存的就是主代码的返回地址。

%rsi存的就是即将被调度执行的进程task_t的指针。

第16行的%rdi就是信号处理函数t_signal()的参数,它只有一个参数。

1,我们先把主代码的返回地址压栈,

2,然后把参数task_t* t放到%rdi里,

它之前作为switch_to()函数的第二个参数在%rsi里,

3,最后跳转t_signal()函数执行,

这样在t_signal()返回时就会把栈上的主代码返回地址弹出,返回主代码。

t_signal()函数可以写得更复杂一点,例如根据信号值选择不同的处理,不同信号的处理函数可以作为指针设置在task_t结构里,这样就类似Linux的样式了。

实际上,Linux系统因为有内核态和用户态,调度器是在内核态运行的,信号处理函数是在用户态运行的,还有个从内核返回用户态的过程。

cfd0bb50193575ceae8d61735c6947a9.png

运行效果图:

717200bf92b96c1edc6caae93a2a197e.png

举报/反馈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值