信号系统概述

更新时间:
2024-01-10
下载文档

信号系统概述

信号类似于软件层次上的“中断”,很多比较重要的应用程序都需要处理信号,信号提供了一种处理异步事件的方法。例如,终端用户键入中断键,会通过信号机制停止一个程序。

信号处理流程

每个信号都有自己的名字,信号的名字都以“SIG”开头。例如,SIGTERM 是终止信号,向进程发送此信号可以终止一个进程。目前 SylixOS 可支持 63 种不同的信号,其中包括标准信号和实时信号。

很多条件可以产生信号:

  • 当用户按某些键时,引发终端产生信号,例如:Ctrl+C 产生 SIGINT 信号。
  • alarm 函数设置的定时器超时后产生 SIGALRM 信号。
  • 子进程退出或被异常终止后产生 SIGCHLD 信号。
  • 访问非法内存产生 SIGSEGV 信号。
  • 用户可以调用 kill 命令将信号发送给其他进程,常用此命令终止一个失控的后台进程。

信号异步性意味着,应用程序不用等待事件的发生,当信号发生时应用程序自动陷入到对应的信号处理函数中。产生信号的事件对进程而言是随机出现的。进程不能简单地测试一个变量来判断是否发生了一个信号,而是必须告诉内核“在此信号发生时,请执行下列操作”。

在某个信号发生时,可以告诉内核按下列 3 种方式之一进行处理:

  • 忽略信号:大多数信号都可以使用这种方式进行处理,在 SylixOS 中有一类信号不能被忽略(例如:SIGSTOP、SIGKILL 等),这种信号不能被忽略的原因是:它们向内核提供了进程终止的可靠方法。另外,如果忽略某些由硬件异常产生的信号(如非法内存访问)则进程的运行行为是未定义的。
  • 捕捉信号:为了做到这一点,要通知内核在某种信号发生时,调用一个用户函数。在用户函数中,可执行用户想要的动作。例如,捕捉到 SIGALRM 信号后,用户可以在相应的处理函数中去控制某个线程。如果捕捉到 SIGCHLD 信号,则表示一个子进程已经终止,所以此信号的捕捉函数可以调用 waitpid 函数以取得该子进程的退出状态。又例如,如果进程创建了临时文件,那么可能要为 SIGTERM 信号编写一个信号捕捉函数以清除临时文件。需要注意的是,同样有一类信号不能被捕捉(例如:SIGSTOP、SIGKILL 等)。
  • 执行系统默认动作:对大多数信号的系统默认动作是终止该进程。

支持的信号

信号名说明
SIGHUP挂断控制终端或进程。通常用此通知守护进程再次读取它们的配置文件,因为守护进程不会有控制终端,通常决不会接收到这种信号
SIGINT来自键盘的中断。一般采用 Ctrl + C 来产生此信号。当一个进程在运行时失控,特别是他正在屏幕上产生大量不需要的输出时,常用此信号终止
SIGQUIT来自键盘的退出
SIGILL非法指令
SIGTRAP跟踪断点
SIGABRT异常结束
SIGUNUSED未使用
SIGFPE协处理出错,如除以 0、浮点溢出等
SIGKILL强迫进程结束(不能被忽略或捕捉)
SIGBUS总线错误,通常是指示一个实现定义的硬件故障
SIGSEGV无效内存引用
SIGUNUSED2未使用 2
SIGPIPE管道写错误,无读者
SIGALRM实时定时器报警
SIGTERM进程终止。这是 kill 命令的默认动作,由于这个信号是由应用程序捕获的,使用 SIGTERM 也让程序有机会在退出之前做好清理工作,从而优雅的终止
SIGCNCL线程取消
SIGSTOP停止进程执行。此信号不能被捕获和忽略(不能被忽略或捕捉)
SIGTSTPtty 发出停止进程
SIGCONT恢复进程继续执行
SIGCHLD子进程停止或者被终止。系统默认是忽略此信号
SIGTTIN后台进程请求输入
SIGTTOU后台进程请求输出
SIGCANCEL同 SIGTERM 相同
SIGIO异步 I/O 事件
SIGXCPU进程超出了软 CPU 事件限制
SIGXFSZ进程超出了软文件长度限制
SIGVTALRM函数 setitimer 设置的虚拟间隔定时器已经超时
SIGPROF函数 setitimer 设置的梗概间隔定时器已经超时
SIGWINCH更改了窗口的大小
SIGINFO信息请求
SIGPOLL同 SIGIO 相同
SIGUSR1用户定义信号 1
SIGUSR2用户定义信号 2
SIGPWR电源失败重新开始
SIGSYS错误的系统调用
SIGURG网络连接上接到带外的数据时,可选择地产生此信号
SIGRTMIN-SIGRTMAXSylixOS 实现 SIGRTMIN = 48、SIGRTMAX = 63,系统没有指定明确的含义,由用户自定义,并且不应该使用某数值

不可靠信号与可靠信号

在早期的 UNIX 版本中,信号是不可靠的,也就是说,信号可能会丢失,这通常会表现为,一个信号发生了,但进程却可能不知道这一点。早期版本中在进程每次接收到信号对其进行处理时,随即将该信号动作重置为默认值(介绍 signal 函数时,我们将详述这一点)。

前面我们说过,信号产生可以来自不同的途径,在 SylixOS 中,信号的来源包含如下表所示的几种类型,当一个信号产生时,内核通常在线程控制块中以某种形式设置一个标志。当信号执行了相应的动作时,代表向进程 / 线程 递送 了一个信号,在信号产生到递送之间的时间间隔内,信号是未决的(pending)。

信号产生源说明
SI_KILL/SI_USER使用 kill 函数发送的信号
SI_QUEUE使用 sigqueue 函数发送的信号
SI_TIMERPOSIX 定时器发送的信号
SI_ASYNCIO异步 I/O 系统完成发送的信号
SI_MESGQ接收到一条消息产生的信号
SI_KERNELSylixOS 内核内部使用

进程/线程可以屏蔽(或者说阻塞)信号,如果信号在被屏蔽期间,信号产生了并且对该信号的动作是系统默认或者捕捉,则此信号将保持为未决状态,直到该进程/线程对此信号解除屏蔽,或者设置信号动作为忽略。

如果在进程/线程解除对某个信号的屏蔽之前,这种信号发生了多次,SylixOS 内核将有两种对待方法,一种是 SI_KILL 方式产生的信号将只递送一次,也即信号不会排队,另一种是非 SI_KILL 方式产生的信号将递送多次,也即信号产生了排队。

SylixOS 内核实现中,如果多个不同信号从屏蔽状态被解除时,则优先递送信号数字小的信号。

由此可见,SylixOS 的信号机制摒弃了之前不可靠的信号机制,只要是非 SI_KILL 方式产生的信号,都将会排队。

因为线程是 SylixOS 调度的单位,而每一个需要处理的信号,都将嵌入到线程中去执行,所以以线程的方式来介绍信号更加符合 SylixOS 的特点。实际上,SylixOS 中向进程递送信号是递送给了进程的主线程。

文档内容是否对您有所帮助?
有帮助
没帮助