信 (Signal)是一种软件中断,比如Ctrl+C的退出命令实质上就是使用了信 。信 在Linux操作系统中提供了一种处理异步事件的方法,可以很好地在多个进程之间进行同步和简单的数据交互。
目录
Linux的信 机制
1. 信 的产生
2. 信 的处理方式
3. 信 的缺陷
4. 信 的执行过程
5. 信 处理的注意事项
Linux的信 机制
信 机制是一种使用信 来进行进程之间的传递消息的方法,其中信 的全称为软中断信 ,简称软中断。
软中断信 (Singal,又简称为信 )用来通知进程发生了异步事件,进程之间可以互相通过系统调用kill函数来发送软中断信 ,而Linux内核也可以因为内部时间而给进程发送信 ,通知进程发生了某个事件。
note:信 只是用来通知进程发生了什么事件,但并不给改进程传递任何数据。
每个信 都有一个名字,这些名字都义三个字符SIG开头,在头文件
note:没有编 为0的信 ,kill函数对编 0有特殊的应用,在POSIX.1规范中,将此信 编 值称为空信 。
Linux内核支持64种不同的信 ,这些信 种的大部分都有了预先定义好的意义,但是都支持自定义动作,并且还提供了类似SIGUSR1这样由应用程序来定义的信 。
1. 信 的产生
Linux中信 可以由以下几种方式产生:
-
当用于按下某些终端按键之后引发终端产生的信 ,例如在程序运行中按下“Ctrl + ”组合键将终止程序的运行。
-
硬件产生的一个异常信 ,例如除数为0,无效的内存引用等,这种异常信 通常会由硬件检测得到并将其通知Linux内核,然后内核为该条件发生时正在运行的进行产生适当的信 。
-
进程调用系统调用kill函数可以给一个进程或者进程组发送一个信 ,需要注意的是此时发送和接收信 的进行/进程组的所有者必须相同
-
用户也可以调用kill命令将信 发送给其它进程
-
当检测到某种软件条件已经发生,并应将其通知有关进程的时候也会产生一个信 ,例如SIGURG信 就是在接收到一个通过 络传送的外部数据时产生的。
2. 信 的处理方式
Linux的每一个信 都有一个缺省的动作,典型的缺省动作是终止进程,当一个信 到来的时候收到这个信 的进程会根据信 的具体情况提供以下三种不同的处理方式:
- 类似中断的处理程序,对于需要处理的信 ,进程可以指定处理函数,由该函数来处理。
- 忽略某个信 ,对该信 不做任何处理,就像从未发生过一样。
- 对该信 的处理保留系统的默认值,这种缺省操作大多数是使得进程终止。进程通过系统调用signal函数来指定进程对某个信 的处理行为。
3. 信 的缺陷
作为一种进程交互机制,信 有一些局限性:
- 信 的系统开销太大。
- 发送信 的进程要进行系统调用。
- 内核要终端接收信 的进程,而且要管理它的堆栈,同时还要调用处理程序,之后恢复执行被中断的进程。
- 信 的数量非常有限,因为为只存在有限的不同信 。
- 信 能传送的信息量十分有限,用户产生的信 不可能发送附加信息以及各种参数。
所以,在实际使用中,信 机制常常用于进程之间的事件通知,而不应用于复杂的交互操作。
4. 信 的执行过程
一个典型的执行过程是使用“Ctrl + C”组合键来中断一个车进程的运行,对其操作部分说明如下,需要注意的是只有在前台运行的程序才能接收到“Ctrl + C”组合键的输入:
-
01)用户输入命令,在Shell下启动一个前台进程。
-
02)用户按下“Ctrl + C”,这个键盘输入产生一个硬件中断。
-
03)如果处理器当前正在执行这个进程的代码,则该进程的用户空间代码暂停执行,CPU从用户态切换到内核台处理硬件中断。
-
04)终端驱动程序将“Ctrl + C“解释成一个SIGINT信 ,记在该进程的PCB中(也可以说发送了一个SIGINT信 给该进程)。
-
05) 当某个时刻要从内核返回到该进程的用户空间代码继续执行之前,首先处理PCB中记录的信 ,发现有一个SIGINT信 待处理,而这个信 的默认处理动作是终止进程,所以直接终止进程,而不再返回它的用户空间代码。
Linux内核给一个进程发送软中断信 的方法是:在进程所在的进程表项的信 域设置对应于该信 的位(内核通过在该进程的struct task_struct 结构体中设置相应的位来实现向一个进程发送信 )。
如果信 发送给一个正在睡眠的进程,那么要看该进程进入睡眠的优先级,如果进程睡眠在可被中断的优先级之上,则唤醒进程;否则仅设置进程表中信 域相应的位,而不唤醒进程。这一点比较重要,因为进程检查是否收到信 的时机是:一个进程在即将从内核态返回到用户态时;或者,在一个进程要进入或离开一个是适当的低调度优先级睡眠状态时。
内核处理一个进程收到的信 的时机是:在一个进程从内核态返回用户态时。所以,当一个进程在内核态下运行时,软中断信 并不立即起作用,要等到将返回用户态时才处理。进程只有处理完信 才会返回用户态,进程在用户态下不会有未处理完的信 。
内核处理一个进程收到的软中断信 是在该进程的上下文中,因此,进程必须处于运行状态。
Linux中处理信 有三种类型:进程接收到信 后退出;进程忽略该信 ;进程收到信 后执行用户自定义的使用系统调用signal注册的函数。当进程接收到一个它忽略的信 时,进程丢弃该信 并继续运行。如果进程收到一个要捕捉的信 ,那么进程从内核态返回用户态时执行用户定义的函数,而且执行用户定义的函数方法很巧妙,内核是在用户栈上创建一个新的层,该层将返回地址的值设置成用户定义的处理函数的地址,这样进程从内核返回栈顶时就返回到用户定义的函数处,从函数返回在弹出栈顶时,才返回原先进入内核的地方。这样操作的原因是用户定义的处理函数不能且不允许在内核态下执行(如果用户定义的函数在内核态下运行的话,用户就可以获得任何权限)。
5. 信 处理的注意事项
在信 的处理方法中有几点特别要引起注意:
- 在一些系统中,当一个进程处理完中断信 返回用户态之前,内核清楚用户区中设定的对该信 的处理例程的地址,即将下一次进程对该信 的处理方法改为默认值,除非在下一次信 到来之前再次使用signal系统调用。
- 如果要捕捉的信 发生于进程正在一个系统调用中时,并且该进程睡眠在可中断短优先级上,这时该信 引发进程调用longjmp函数跳出睡眠状态,返回用户态并执行信 处理例程;当从信 处理例程返回时,进程就像从系统调用返回一样,但返回了一个错误代码,指出该系统调用曾被中断。
- 若进程睡眠在可中断的优先级上,则当它收到一个要忽略的信 时,该进程被唤醒,但不再longjmp函数调用,一般是继续睡眠,一般情况下e,用户感觉不到进程曾经被唤醒,而是像没有产生国信 一样。
- 内核对用子进程终止(SIGCLD)信 的处理方法与其他信 有所区别。
- 如果一个进程调用signal系统,并设置了SIGCLD的处理方式,且该进程有子进程处于僵死状态,则内核将向该进程发送一个SIGCLD信 。
6. 信 的分类
Linux下的信 分为如下几大类
- 与进程终止相关的信 :当进程退出,或者子进程终止时,发出这类信 。
- 与进程例外事件相关的信 :如进程越界,或企图写入一个只读的内存区域(如程序正文区),或执行一个特权指令及其他各种硬件错误。
- 与在系统调用期间遇到不可恢复条件相关的信 :如执行系统调用exec时,原有资源已经释放,而目前系统资源又已经耗尽。
- 与执行系统调用时遇到非预测错误条件相关的信 :如执行一个并不存在的系统调用。
- 在用户态下的进程发出的信 :如进程调用kill向其他进程发出信 。
- 与终端交互相关的信 :如用户关闭一个终端,或按下”Break“键等情况。
- 跟踪进程执行的信 。
在Linux下可以使用“kill -l”命令来查看当前系统支持的全部信 ,通常来说有64个默认的信 。
除了使用“kill -l”命令之外,在Linux的帮助手册中对信 也有详细的定义,可以使用 man 7 signal 命令来查看更为详尽的说明,其中第1列为信 名称,第二列为对应的信 编 ,第3列为对信 的处理方式,而第4列是对信 的详细说明。
使用 kill -l 和 man 7 signal命令中可以查看到信 的具体说明为:
参考文献:程国钢, 张玉兰. Linux C编程从基础到实践, 清华大学出版 , 2015.
文章知识点与官方知识档案匹配,可进一步学习相关知识CS入门技能树Linux入门初识Linux25109 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!