linux系统如何将一个信号通知到进程

信号的种类

  1. 硬件异常产生的错误。比如非法访问内存,除数为0…
  2. 外部信号。键盘上的Ctrl-C产生SGINT信号,定时器到期产生SIGALRM…
  3. 显示的请求。 主要是通过Kill函数发送信号给指定进程。

进程描述符

为了管理进程,内核必须知道每个进程的信息与其所做的事情(进程优先级、分配的地址空间、访问权限etc.)。 这正是通过 进程描述符 的作用。

  • 在Linux里面每个进程都是按照进程描述符 task_struct 结构创建的,还有一个叫task vector的东西,从名字上就能看出来这是一个数组,这里面保存的是指向每一个进程的指针,即指向每一个task_struct的指针,因此一个Linux系统最大的进程数,取决于task vector这个数组的大小,一般默认是512个。
  • 在进程描述符task_struct里面,其中一项是Signal_Strct,在Signal_Strct这里面有一项list_head的描述符,在这里面有一个sigset_t表,定义了64种信号的所代表的含义。

进程描述符主要包含:

  1. 标示符 : 描述本进程的唯一标识符,用来区别其他进程;
  2. 状态 :任务状态,退出代码,退出信号等;
  3. 优先级 :相对于其他进程的优先级;
  4. 程序计数器:程序中即将被执行的下一条指令的地址;
  5. 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针;
  6. 上下文数据:进程执行时处理器的寄存器中的数据;
  7. I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表;
  8. 记账信息:可能包含处理器时间总和,使用的时钟数总和,时间限制,记账列表等。

保存进程信息的数据结构叫做 task_struct,可以在 include/linux/sched.h 中找到它;

所有运行在系统中的进程都以 task_struct 链表的形式存在内核中;

进程的信息可以通过 /proc 系统文件夹查看。要获取PID为400的进程信息,你需要查看 /proc/400 这个文件夹。大多数进程信息同样可以使用top和ps这些用户级工具来获取。

信号发送到进程大致流程

  • 由于信号的触发和发送是随机的,也就是异步的。接收进程是无法预知什么时间,会收到哪个信号的。
  • 发送机制:举例说明,如果有A,B两个进程,A进程接收到出发条件,开始发送信号给B进程,信号并不是直接从进程A发送给进程B,而是要通过内核来进行转发。之所以要通过内核来转发,这样做的目的应该也是为了对进程的管理和安全因素考虑。因为在这些信号当中,SIGSTOP和SIGKILL这两个信号是可以将接收此信号的进程停掉的,而这类信号,肯定是需要有权限才可以发出的,不能够随便哪个程序都可以随便停掉别的进程。
  • A进程发送的信号消息,其实就是根据上面的那个信号表,根据需要对相应的表项进行设置。内核接受到这个信号消息后,会先检查A进程是否有权限对B进程的信号表对应的项进行设置,如果可以,就会对B进程的信号表进行设置,这里面信号处理有个特点,就是没有排队的机制,也就是说某个信号被设置之后,如果B进程还没有来及进行响应,那么如果后续第二个同样的信号消息过来,就会被阻塞掉,也就是丢弃。内核对B进程信号设置完成后,就会发送中断请求给B进程,这样B进程就进入到内核态,这个时候进程B根据那个信号表,查找对应的此信号的处理函数,然后设置frame,设置好之后,跳回到用户态执行信号处理函数,处理完成后,再次返回到内核态,再次设置frame,然后再次返回用户态,从中断位置开始继续执行。
  • 这个frame其实就是在用户态和内核态之间跳转的时候,对堆栈现场的压栈保存。大致的原理就是这么一个过程,在真正使用的时候,就比较简单了,用kill函数发送信号,在接收进程里,通过signal或者signalaction函数调用sighandler,来启动对应的函数处理信号消息。

linux信号基于轮训还是中断

中断,顾名思义,就是打断正在进行中的工作。 我们知道linux管理所有的硬件设备,要做的第一件事是处理器与硬件设备的通信。说的简单,怎么实现呢?简单一点,轮询(polling)可能就是一种解决方法,缺点是操作系统要做太多的无用功,在那里傻傻的做着不重要而要重复的工作。这里有更好的办法—中断,关键在于从硬件设备的角度上看,已经实现了化被动为主动的历史性突破。
中断,本质上是一种电信号,当硬件设备有某种事件发生时就会产生中断信号,由硬件设备把信号发送给处理器(中间还有一个中断控制器,在此不细说),处理器接收到中断后,会马上向操作系统反应此信号的到来,然后就由OS负责处理这些新到来的数据,中断可以随时发生,不用操心与处理器的时间同步问题。

当执行了一条指令后,cs和eip这对寄存器包含了下一条将要执行的指令的逻辑地址。在处理那条指令之前,控制单元会检查在运行前一条指令时是否已经发生了一个中断或异常,如果发生了一个中断或异常,那么控制单元执行下列操作:
……
——《深入理解linux内核》
这里介绍下书本中提到的异常,我们可以简单理解为中断的一种:同步中断。

标粗的这一句就是重点,中断也是需要CPU check的!也就是说:处理器在每个指令周期都会去查看中断寄存器,如果中断寄存器有效,也就是发生了中断,那么cpu会执行一系列与中断相关的操作。于是有人就说:“那么是否可以这么讲,中断的本质其实就是轮询,只是比直接在代码中轮询的效率高,反应快?”

探讨到这里你是不是也觉得中断和轮询并不是完全对立的两个概念?嗯,最终的结论:中断和轮询它俩是对立统一的,至少我是这么认为的!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VioletEvergarden丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值