信号概念

来源:互联网 发布:常见软件项目风险 编辑:程序博客网 时间:2024/05/16 08:41

首先,每个信号有个名字。这些名字都以字符串SIG开头。例如SIGABRT是当一个进程调用abort函数时产生的终止信号。SIGALRM是当 alram函数设置的计时器到时时产生的闹铃信号。版本7有15个不同的信号;SVR4和4.4BSD有31个不同的信号。FreeBSD 5.2.1、Mac OS X 10.3和Linux2.4.22支持31个不同的信号,而Sloaris 9支持38个不同的信号。然而,Linux和Solaris都支持应用定义的信号作为实时扩展(POSIX里的实时扩展没有被本文包括)。


这些名字都用正常量(信号号)定义在头文件<signal.h>里。


实现真正把独立的信号定义在一个替代的头文件里,但是这个头文件被包含在<signal.h>里。对内核来说为用户级应用程序包含头文件被认为是坏的形式,所以如果应用和内核都需要相同的定义,那么信息被放入一个被用户级头文件包含的内核头文件里。因而,FreeBSD 5.2.1和Mac OS X 10.3把信号定义在<sys/signal.h>里。Linux 2.4.22把信号定义在<bits/signum.h>里,而Soloaris 9把它们定义在<sys/iso/signal_iso.h>。


没有一个信号的信号号为0。我们将在10.9节看到kill函数使用信号号0用作特殊情况。POSIX.1称这个值为空信号。

许多条件可以产生一个信号。


1、终端产生的信号在用户被按下特定终端键时发生。在终端上按下DELETE键(或在许多系统上的Control-C)一般会导致中断信号(SIGINT)被产生。这是停止失控程序的方法。(我们将在18章看到这些信号如何被映射到终端的任一字符。)


2、硬件异常产生信号:由0除,无效内存引用,等等。这些条件通常被硬件察觉,而内核被通知。内核然后在条件发生的时刻为运行的进程产生恰当的信号。例如,SIGSEGV为执行一个无效内存引用的进程而产生。


3、kill命令允许一个进程发送任何信号给其它进程。这个程序只是一个kill函数的接口。这个命令经常用来终止一个失控的后台进程。


4、当发生一些进程应该被通知的事情时,软件条件可以产生信号。这不是硬件产生的条件(如被0除),而是软件条件。例子是SIGURG(当通过网络连接到达的不同频道的数据时产生)、SIGPIPE(当进程在管道的读者终止之后向管道写入时产生)和SIGALRM(当进程设置的闹铃过期时产生)。


信号是异步事件的经典例子。信号在进程的任意时间点发生。这个进程不能简单地测试一个变量(比如errno)来看一个信号是否发生;相反,进程比如告诉内核“如果信号发生时,做如下的事”。


我们可以告诉内核当一个信号发生时,做如下三件事中的一件。我们称它为信号的布署(disposition),或都一个信号的关联动作。


1、忽略这个信号。这对于多数信号都工作,但是两个信号决不能被忽略:SIGKILL和SIGSTOP。这两个信号不能被忽略的原因是为了向内核和超级用户提供杀死或停止任何进程的必定成功的方法。同样,如果我们忽略了一些由硬件异常产生的信号(比如非法内存引用或被0除),进程的行为会没有定义。


2、捕获这个信号。为了这样做,我们告诉内核每当信号发生时调用一个我们的函数。在我们的函数里,我们可以做任何我们要做的事来处理这个条件。例如,如果我们在写一个命令解释器,当用户从键盘产生中断信号时,我们可能想从程序的主循环里返回,终止我们为这个用户执行的任何命令。如果SIGCHLD信号被捕获,它表示一个子进程已经终止了,所以信号捕获函数可以调用waitpid来获取这个子进程ID和终止状态。另一个例子是,如果进程已经创建了临时文件,我们可能想要为SIGTERM信号写一个信号捕获函数(由kill命令发送的默认的终止信号)来清理临时文件。注意SIGKILL和SIGSTOP这两个信号不能被捕获。


3、让默认行为发生。每个信号有一个默认的动作,如下表所示。注意多作信号的默认动作是终止这个进程。

UNIX系统信号名字描述ISO CSUSFreeBSD 5.2.1Linux 2.4.22Mac OS X 10.3Solaris 9默认动作SIGABRT异常终止(abort)******终止+核心SIGALRM计时器到期(alarm) *****终止SIGBUS硬件错误 *****终止+核心SIGCANCEL线程库内部使用     *忽略SIGCHLD子进程的状态改变 *****忽略SIGCONT继续停止的进程 *****继续/忽略SIGEMT硬件错误  ****终止+核心SIGFPE算术异常******终止+核心SIGFREEZE检查点冻结     *忽略SIGHUP挂起 *****终止SIGILL非法指令******终止SIGINFO键盘状态请求    * 忽略SIGINT终端中断字符******终止SIGIO异步I/O  ****终止/忽略SIGIOT硬件错误  ****终止+核心SIGKILL终止 *****终止SIGLWP线程库内部使用     *忽略SIGPIPE向没有读者的管道写 *****终止SIGPOLL可查询的事件(poll) XSI * *终止SIGPROF轮廓时间闹铃(setitimer) XSI****终止SIGPWR电源失败/重启   * *终止/忽略SIGQUIT终端退出字符 *****终止+核心SIGSEGV无效内存引用******终止+核心SIGSTKELT协处理器栈错误   *  终止SIGSTOP停止 *****停止进程SIGSYS无效系统调用 XSI****终止+核心SIGTERM终止******终止SIGTHAW检查点解冻     *忽略SIGTRAP硬件错误 XSI****终止+核心SIGSTP终端停止字符 *****停止进程SIGTTIN后台从控制tty读 *****停止进程SIGTTOU后台向控制tty写 *****停止进程SIGURG紧急条件(套接字) *****忽略SIGUSR1用户定义信号 *****终止SIGUSR2用户定义信号 *****终止SIGVTALRM虚拟时间响铃(setitimer) XSI****终止SIGWAITNG线程库内部使用     *忽略SIGWINCH终端窗口尺寸改变  ****忽略SIGXCPUCPU限制超过(setrlimit) XSI****终止+核心/忽略SIGXFSZ文件尺寸限制超过(setrlimit) XSI****终止+核心/忽略SIGXRES资源控制超过     *忽略

上表列出了所有信号的名字,哪些系统支持该信号的指示,和信号的默认动作。如果信号是基本POSIX.1的一部分则SUS列包含“*”,如是是基础的XSI扩展则包含“XSI”。


当默认的动作被标为“终止+核心”时,它意思是进程的一个内存映像留在了进程的当前工作目录里的名为core的文件里。(因为文件被命名为core,所以可以看出这个特性作为UNIX系统的一部分有多久。)这个文件被多数UNIX系统调试器使用来检查进程终止时的状态。


core文件的产生是多数UNIX系统版本的一个实现特性。尽管这个特性不是POSIX.1的一部分,但是被提到为SUS的XSI扩展的潜在动作。


核心文件在不同的实现上有所区别。例如,在FreeBSD 5.2.1上,核心文件被命名为cmdname.core,cmdname是对应于收到信号的进程的命令名。在Mac OS X 10.3,核心文件被命名为core.pid,pid是收到信号的进程的ID。(这些系统允许核心文件名通过sysctl参数配置。)


多数系统实现把核心文件放在对应进程的当前工作目录里;但Mac OS X把所有核心文件放在/cores里。


核心文件不会被产生,如果a、进程是设置用户ID的,而当前用户不是这个程序文件的属主,或者b、进程是设置组ID的,而当前用户不是文件所属组,c、用户没有在当前工作目录写的权限;d、文件已经存在而用户没有权限去写它;或e、文件太大(回想下7.11节的RLIMIT_CORE限制。)核心文件的权限(假定这个文件原本不存在)通常是用户读和用户写的,尽管Mac OS X设置为用户只读。


在上表时,用“硬件错误”描述的信号对应于实现定义的硬件错误。这些名字里的许多都从UNIX系统的原始PDP-11实现而来。检查你的系统手册来决定这些信号精确地对应着哪种类型的错误。


我们现在更细节地描述每个信号。


SIGABRT:这个信号通过调用abort函数产生(10.17节)。进程异常终止。


SIGALRM:这个信号当一个用alarm函数设置的计时器过期时产生(10.10节)。这个信号在通过setitime设置的间隔计时器过期时也会产生。


SIGBUS:这指定一个实现定义的硬件错误。实现通常在内存错误的特定类型时产生这个信号。(14.9节)。


SIGCANCEL:这个信号被Solaris线程库内部使用,不被广泛使用。


SIGCHLD:每当一个进程终止或停止,SIGCHLD信号被发送给父进程。默认情况下,这个信号被忽略,所以父进程并须捕获这个信号,如果它想在子进程状态改变时得到通知。信号捕获函数里的通常动作是调用某个wait函数来获取子进程的ID和终止状态。

系统V的早期版本有一个名为SIGCLD(没有H)的类似的信号。这个信号的语义和其它信号不同,早在SVR2,手册页强烈反对它在新程序里使用。(足够奇怪,这个警告在手册而的SVR3和SVR4版本里消失了。)应用应该使用标准的SIGCHLD信号,但是要知道多数系统定义SIGCLD为和 SIGCHLD相同以保持向后兼容。如果你维护一个使用SIGCLD的软件,你必须检查系统手册页来看它遵循哪种语义。我们在10.7节讨论这两个信号。


SIGCONT:这个工作控制信号被发送给一个停止的进程,当它被继续时。默认动作是继续一个停止的进程,但是如果这个进程没有停止过则忽略这个信号。例如,一个全屏的编辑器,可以捕获这个信号并使用信号处理器在终端作一个重绘的注释。10.20节有更多细节。


SIGEMT:这指定一个实现定义的硬件错误。

名字EMT从PDP-11的“emulator trap”指令而来。不是所有平台都支持这个信号。例如在Linux上,SIGEMT只被选定的架构支持,比如SPARC、MIPS和PA-RISC。


SIGFPE:这个信号是一个算术异常,比如被0除,浮点溢出,等等。


SIGFREEZE:这个信号只被Solaris定义。它用来通知需要在冻结系统状态之前采取特殊动作的进程,比如当一个系统进入冬眠(hibernation)或暂停(suspended)模式。


SIGHUP: 这个信号被发送给控制终端关联的控制进程(会话领导),如果一个连接断开被终端接口察觉。在第9章,我们看到信号被发送给由session结构体的 s_leader域指向的进程。这个信号仅当终端的CLOCAL标志没有被设置时被产生。(一个进程的CLOCAL标志当附加的终端是本地的时被设置。这个标志告诉终端驱动器来忽略所有猫状态行。我们将在第18章描述如何设置这个标志。)

注意收到这个消息的会话领导可以在后台。这不同于普通的终端产生的信号(中断、退出和挂起),它们总是分发给前台进程组。

如果会话领导终止时,这个信号也会被产生。在这种情况下,信号被发送给前台进程组的每个进程。

这个信号通常用来通知守护进程(第13章)来重新读取它们的配置文件。SIGHUP被选择用作这种目的的原因是一个守护进程不应该有一个控制终端,而且一般不会收到这个信号。


SIGILL:这个信号指出进程已经执行了一个非法硬件指令。4.3BSD从abort函数产生这个信号。SIGABRT现在用作这个。


SIGINFO:这个BSD信号当我们输入状态键(通常是Control-T)时由终端驱动器产生。这个信号被发送给前台进程组的所有进程。这个信号通常导致前台进程组里的进程的状态信息被显示在终端上。

Linux没有提供对SIGINFO的支持,除了在Alpah平台上,那么它被定义为和SIGPWR一样的值。


SIGINT:这个信号当我们输入中断键(通常是DELETE或Control-C)时由终端驱动器产生。这个信号被发送给前台进程组的所有进程。这个信号经常用来终止一个失控的程序,特别是当它在屏幕上产生许多不被期望的输出。


SIGIO:这个信号指出一个异步I/O事件。我们将在14.6.2节讨论。

在上表,我们把SIGIO的默认动作标为“终止”或者“忽略”。不幸的是,这个默认动作取决于系统。在系统V下,SIGIO与SIGPOLL相同,所以它的默认动作是终止这个进程。在BSD下,默认是忽略这个信号。

Linux2.4.22和Soloaris 9定义SIGIO为和SIGPOLL一样的值,所以默认行为是终止这个进程。在FreeBSD 5.2.1和Mac OS X 10.3上,默认是忽略这个信号。


SIGIOT:它指明一个实现定义的硬件错误。

名字IOT从PDP-11的“input/output TRAP”指令而来。系统V的早期版本从abort函数产生。现在SIGABRT被使用在这里。

在FreeBSD 5.2.1、Linux 2.4.22、Mac OS X 10.3和Solaris 9上,SIGIOT被定义为和SIGABRT一样的值。


SIGKILL:这个信号是不能被捕获或忽略的两个信号之一。它为系统管理员提供了一个杀死任何进程的必定成功的方式。


SLGLWP:这个信号被Solaris线程库内部使用,不被广泛使用。


SIGPIPE:如果我们向读者已经终止的管道写时,SIGPIPE被产生。我们在15.2节描述管道。这个信号当一个进程向不再连接的SOCK_STREAM类型的套接字写时也会产生。我们在16章描述套接字。


SIGPOLL:这个信号可以当一个特定事件发生在可查询的设备上时产生。我们在14.5.2节用poll函数讨论这个信号。SIGPOLL起源于SVR3,并松散地对应于BSD的SIGIO和SIGURG信号。在Linux和Solaris,SIGPOLL被定义为和SIGIO一样的值。


SIGPROF:这个信号当一个通过setittimer函数设置的轮廓间隔计时器过期时产生。


SIGPWR:这个信号是系统相关的。它的主要用在有一个不可中断的电源供给(uninterruptible power supply,UPS)的一个系统上。如果电源失败,UPS接管而软件通常会被通知。此时不必做什么事,因为系统仍在电池电源上运行。但是如果电池电量很少(如果电源被关闭了很长时间),那么软件会被再次通知。此时,它适应系统在15-30秒内关闭所有东西。这是SIGPWR应该被发送的时间。多数系统让被低电量条件通知到的进程发送一个SIGPWR信号给init进程,init处理关闭事宜。

Linux2.4.22和Solaris 9在inittab文件里有为这个目的的项:powerfail和powerwait(或powerokwait)。

在上表,我们标出SIGPWR的默认动作为“终止”或“忽略”。不幸的是,默认行为取决于系统。Linux上的默认行为是终止进程,在Solaris上,信号默认被忽略。


SIGQUIT:这个信号当我们输入终端退出键(通常是Control-backslash)时由终端驱动发出。这个信号被发送给前台进程组的所有进程。这个信号只终止前台进程组(和SIGINT一样),但也产生一个核心文件。


SIGSEGV:这个信号指出进程做了一个无效的内存引用。名字SEGV表示“segmentation violation”。


SIGSTKFLT:这个信号只被Linux定义。这个信号在Linux的最早版本里出现,意图为数学协处理器的栈错误所使用。这个信号不由内核产生,但是为向后兼容而被保留。


SIGSTOP:这个工作控制信号停止了一个进程。它像交互的停止信号(SIGTSTP),但SIGSTOP不能被捕获或忽略。


SIGSYS:这个信号是无效系统调用。然而,信号执行了一个内核本以为是一个系统调用的机器指定,但是这个指定的参数指出系统调用的类型是无效的。如果你创建一个使用新的系统调用的程序然后尝试在一个老版本的没有这个系统调用的操作系统上运行相同的机器码时会发生。


SIGTERM:这是由kill命令默认发出的终止信号。


SIGTHAW:这个信号只被Solaris定义,被用来通知需要在系统在挂起后恢复操作后采取特殊动作的进程。


SIGTRAP:这指明一个实现定义的硬件错误。

信号名从PDP-11的TRAP指定而来。实现经常使用这个信号把控制传递给一个调试器,当一个中断(breakpoint)指定被执行时。


SIGTSTP:这个交互的停止信号在我们输入终端暂停键时(经常是Control-Z)由终端驱动产生。这个信号被发送给前台进程组的所有进程。

不幸的是,术语“停止”有不同的含义。当讨论工作控制和信号时,我们说停止和继续工作。然而,终端驱动历史上使用这个术语来指热线服务Control-S和 Control-Q字符来停止和启动终端输出。因此,终端驱动称这个产生交互停止信号的字符为暂停(suspend)字符,而不是停止字符。


SIGTTIN:这个信号当后台进程组里的进程尝试从它的控制终端读时由终端驱动产生。(加想9.8节关于这个话题的讨论。)作为特殊的情况,如果a、读进程正忽略或阻塞这个信号或b、读进程的进程组是孤立的,那么信号不会产生。相反,读操作返回一个错误,errno为EIO。


SIGTTOU:这个信号当一个后台进程组里的进程尝试向控制终端写时由终端驱动产生。不像刚刚提到的SIGTTIN信号,一个进程可以选择允许后台像控制终端写。我们将在18章描述如何改变这个选项。

如果后台写不被允许,那么像SIGTTIN信号,有两种特殊情况:如果a、写进程正忽略或阻塞信号或b、写进程的进程组是孤立的,那么信号不会被产生,相反,写操作会返回一个错误,errno为EIO。

不管后台写是否被允许,特定的终端操作(除了写)也可以产生SIGTTOU信号:tcsetattr、tcsendbreak、tcdrain、tcflush、tcflow和tcsetpgrp。我们在18章描述这些终端操作。


SIGURG:这个信号通知进程一个紧急条件发生。这个信号当不同频道的数据在一个网络连接上收到是可选地产生。


SIGUSR1:这是一个用户定义的信号,为应用程序的用户。


SIGUSR2:这是另一个用户定义的信号,和SIGUSR1相似,为应用程序的用户。


SIGVTALRM:这个信号当由setitimer设置的一个虚拟间隔计时器过期时产生。


SIGWAITING:这个信号被Sloaris线程库内部使用,外部不可用。


SIGWINCH:内核维护每个终端和伪终端关联的窗口尺寸。一个进程可以用ioctl函数得到或设置窗口尺寸,18.12节。如果一个进程使用ioctl设置窗口尺寸命令来改变了窗口尺寸,内核为前台进程组产生SIGWINCH信号。


SIGXCPU:SUS支持资源限制的概念,作为一个XSI扩展。7.11节。如果进程超过了它的软CPU时间限量,SIGXCPU信号被产生。

在上表,我们标出SIGXCPU的默认动作是“带有核心文件的终止”或“忽略”。不幸的是,默认行为取决于操作系统。Linux和Solaris支持带有核心文件终止的默认动作,而FreeBSD和Mac OS X支持忽略的默认动作。SUS要求默认动作为异常终止这个进程。核心文件是否产生取决于实现。


SIGXFSZ:信号如果进程超过它的软文件尺寸限量时产生。7.11节。

和SIGXCPU一样,SIGXFSZ的默认动作取决于操作系统。Linux和Solairs默认终止进程和创建一个核心文件。FreeBSD和Solaris默认忽略。SUS要求默认动作是异常终止这个进程。是否产生核心文件取决于实现


SIGXRES:信号只被Solaris定义。信号可选地用来通知进程已经超过预配置的资源值。Solaris资源控制机制是一个控制独立应用集之间共享资源的使用的通用设施。

原创粉丝点击