首先,每个信号都有一个名字。这些名字都以3个字符SIG开头。

例如:

  • SIGABRT:夭折信号,当进程调用abort函数时产生这种信号。
  • SIGALRM:闹钟信号,由alarm函数设置的定时器超时后将产生此信号。

V7 有 15 种不同的信号,SVR4 和4.4BSD 均有 31 种不同的信号。FreeBSD 8.0支持32种信号,Mac OS X 10.6.8以及Linux 3.2.0都支持31种信号,而So-laris 10支持40种信号。但是,FreeBSD、Linux和Solaris作为实时扩展都支持另外的应用程序定义的信号。虽然本书不包括POSIX实时扩展(有关信息请参阅Gallmeister[1995]),但是SUSv4已经把实时信号接口移至基础规范说明中。

在头文件<signal.h>中,信号名都被定义为正整数常量(信号编号)。

实际上,实现将各信号定义在另一个头文件中,但是该头文件又包括在<signal.h>中。

? : 内核包括对用户级应用程序有意义的头文件,这被认为是一种不好的形式,所以如若应用程序和内核两者都需使用同一定义,那么就将有关信息放置在内核头文件中,然后用户级头文件再包括该内核头文件。

于是,FreeBSD 8.0和Mac OS X 10.6.8将信号定义在<sys/signal.h>中,Linux3.2.0将信号定义在<bits/signum.h>中,Solaris 10将信号定义在<sys/iso/signal_iso.h>中。

不存在编号为 0 的信号。在 10.9 节中将会看到,kill 函数对信号编号 0 有特殊的应用。POSIX.1将此种信号编号值称为空信号。


信号的产生

很多条件可以产生信号。

  • 当用户按某些终端键时,引发终端产生的信号。在终端上按Delete 键(或者很多系统中的Ctrl+C键)通常产生中断信号SIGINT。这是停止一个已失去控制程序的方法。(第18章将说明此信号可被映射为终端上的任一字符。)
  • 硬件异常产生信号:除数为0、无效的内存引用等。这些条件通常由硬件检测到,并通知内核。然后内核为该条件发生时正在运行的进程产生适当的信号。例如,对执行一个无效内存引用的进程产生SIGSEGV信号。
  • 进程调用kill(2)函数可将任意信号发送给另一个进程或进程组。自然,对此有所限制:接收信号进程和发送信号进程的所有者必须相同,或发送信号进程的所有者必须是超级用户。
  • 用户可用kill(1)命令将信号发送给其他进程。此命令只是kill函数的接口。常用此命令终止一个失控的后台进程。
  • 当检测到某种软件条件已经发生,并应将其通知有关进程时也产生信号。这里指的不是硬件产生条件(如除以 0),而是软件条件。例如 SIGURG(在网络连接上传来带外的数据)、SIG-PIPE(在管道的读进程已终止后,一个进程写此管道)以及SIGALRM(进程所设置的定时器已经超时)。

信号是异步事件的经典实例。产生信号的事件对进程而言是随机出现的。进程不能简单地测试一个变量(如errno)来判断是否发生了一个信号,而是必须告诉内核“在此信号发生时,请执行下列操作”。


信号的处理

在某个信号出现时,可以告诉内核按下列3种方式之一进行处理,我们称之为信号的处理或与信号相关的动作。

  • 忽略此信号。大多数信号都可使用这种方式进行处理,但有两种信号却决不能被忽略。它们是SIGKILLSIGSTOP。这两种信号不能被忽略的原因是:它们向内核和超级用户提供了使进程终止或停止的可靠方法。另外,如果忽略某些由硬件异常产生的信号(如非法内存引用或除以0),则进程的运行行为是未定义的。
  • 捕捉信号。为了做到这一点,要通知内核在某种信号发生时,调用一个用户函数。在用户函数中,可执行用户希望对这种事件进行的处理。例如,若正在编写一个命令解释器,它将用户的输入解释为命令并执行之,当用户用键盘产生中断信号时,很可能希望该命令解释器返回到主循环,终止正在为该用户执行的命令。如果捕捉到 SIGCHLD 信号,则表示一个子进程已经终止,所以此信号的捕捉函数可以调用waitpid以取得该子进程的进程ID以及它的终止状态。又例如,如果进程创建了临时文件,那么可能要为 SIGTERM 信号编写一个信号捕捉函数以清除临时文件(SIGTERM 是终止信号,kill 命令传送的系统默认信号是终止信号)。注意,不能捕捉SIGKILLSIGSTOP信号。
  • 执行系统默认动作。图10-1给出了对每一种信号的系统默认动作。注意,对大多数信号的系统默认动作是终止该进程。

图10-1列出了所有信号的名字,说明了哪些系统支持此信号以及对于这些信号的系统默认动作。在SUS 列中,“•”表示此种信号定义为基本POSIX.1 规范部分,“XSI”表示该信号定义在XSI扩展部分。在系统默认动作列,“终止+core”表示在进程当前工作目录的core文件中复制了该进程的内存映像(该文件名为core,由此可以看出这种功能很久之前就是UNIX的一部分)。大多数UNIX系统调试程序都使用core文件检查进程终止时的状态。

图10-1 UNIX系统信号

core文件

产生core文件是大多数UNIX系统的实现功能。虽然该功能不是POSIX.1的组成部分,但在Single UNIX Specification XSI的扩展部分中,这一功能作为一个潜在的特定实现的动作被提及。

在不同的实现中,core 文件的名字可能不同。例如,在FreeBSD 8.0 中,core 文件名为cmdname.core,其中cmd-name是接收到信号的进程所执行的命令名。在Mac OS X10.6.8中,core文件名是core.pid,其中,pid是接收到信号的进程的ID。(这些系统允许经sysctl参数配置core文件名。在Linux 3.2.0中,core文件名通过/proc/sys/kernel/core_pattern进行配置。)

大多数实现在相应进程的工作目录中包含core文件项;但Mac OS X将所有core文件都放置在/cores目录中。

在下列条件下不产生core文件:

  • ?: 进程是设置用户ID的,而且当前用户并非程序文件的所有者;

  • ? :进程是设置组ID的,而且当前用户并非该程序文件的组所有者;

  • 用户没有写当前工作目录的权限;
  • 文件已存在,而且用户对该文件设有写权限;
  • 文件太大(回忆7.11节中的RLIMIT_CORE限制)。core文件的权限(假定该文件在此之前并不存在)通常是用户读/写,但Mac OS X只设置为用户读。

在图10-1说明中的“硬件故障”对应于实现定义的硬件故障。这些名字中有很多取自UNIX系统早先在PDP-11上的实现。请查看你所使用系统的手册,以确切地弄清楚这些信号对应于哪些错误类型。


信号的详细说明

  • SIGABRT调用abort函数时(见10.17节)产生此信号。进程异常终止。
  • SIGALRM当用alarm函数设置的定时器超时时,产生此信号。详细情况见10.10节。若由setitimer(2)函数设置的间隔时间已经超时时,也产生此信号。
  • SIGBUS指示一个实现定义的硬件故障。当出现某些类型的内存故障时(如 14.8 节中说明的),实现常常产生此种信号。
  • SIGCANCEL这是Solaris线程库内部使用的信号。它不适用于一般应用。
  • SIGCHLD在一个进程终止或停止时,SIGCHLD信号被送给其父进程。按系统默认,将忽略此信号。如果父进程希望被告知其子进程的这种状态改变,则应捕捉此信号。信号捕捉函数中通常要调用一种wait函数以取得子进程ID和其终止状态。System V的早期版本有一个名为SIGCLD(无H)的类似信号。这一信号具有与其他信号不同的语义,SVR2的手册页警告在新的程序中尽量不要使用这种信号。(令人奇怪的是,在SVR3和SVR4版的手册页中,该警告消失了。)应用程序应当使用标准的SIGCHLD信号,但应了解,为了向后兼容,很多系统定义了与SIGCHLD等同的SIGCLD。如果有使用SIGCLD的软件,需要查阅系统手册,了解它具体的语义。10.7节将讨论这两个信号。
  • SIGCONT此作业控制信号发送给需要继续运行,但当前处于停止状态的进程。如果接收到此信号的进程处于停止状态,则系统默认动作是使该进程继续运行;否则默认动作是忽略此信号。例如,全屏编辑程序在捕捉到此信号后,使用信号处理程序发出重新绘制终端屏幕的通知。关于进一步的情况见10.21节。
  • SIGEMT 指示一个实现定义的硬件故障。EMT这一名字来自PDP-11的仿真器陷入(emulatortrap)指令。并非所有平台都支持此信号。例如,Linux只对SPARC、MIPS和PA_RISC等系统结构支持SIGEMT。
  • SIGFPE 此信号表示一个算术运算异常,如除以0、浮点溢出等。
  • SIGFREEZE 此信号仅由Solaris定义。它用于通知进程在冻结系统状态之前需要采取特定动作,例如当系统进入休眠或挂起状态时可能需要做这种处理。
  • ?: SIGHUP 如果终端接口检测到一个连接断开,则将此信号送给与该终端相关的控制进程(会话首进程)。见图9-13,此信号被送给session结构中s_leader字段所指向的进程。仅当终端的CLOCAL标志没有设置时,在上述条件下才产生此信号。(如果所连接的终端是本地的,则设置该终端的CLOCAL标志。它告诉终端驱动程序忽略所有调制解调器的状态行。第18章将说明如何设置此标志。)

  • SIGILL 此信号表示进程已执行一条非法硬件指令。
  • SIGINFO 这是一种BSD信号,当用户按状态键(一般采用Ctrl+T)时,终端驱动程序产生此信号并发送至前台进程组中的每一个进程(见图 9-9)。此信号通常造成在终端上显示前台进程组中各进程的状态信息。注意,接到此信号的会话首进程可能在后台,作为一个例子,请参见图9-7。这区别于由终端正常产生的几个信号(中断、退出和挂起),这些信号总是传递给前台进程组。如果会话首进程终止,也产生此信号。在这种情况,此信号送给前台进程组中的每一个进程。通常用此信号通知守护进程(见第13章)再次读取它们的配置文件。选用SIGHUP的理由是,守护进程不会有控制终端,通常决不会接收到这种信号。4.3BSD的abort函数产生此信号。现在该函数产生SIGABRT信号。虽然Alpha平台将SIGINFO定义为与SIGPWR具有相同值,但是Linux并不支持SIGINFO信号。这更多是因为需要对OSF/1开发的软件提供某种程度的兼容。
  • SIGINT当用户按中断键(一般采用 Delete 或 Ctrl+C)时,终端驱动程序产生此信号并发送至前台进程组中的每一个进程(见图9-9)。当一个进程在运行时失控,特别是它正在屏幕上产生大量不需要的输出时,常用此信号终止它。
  • SIGIO 此信号指示一个异步I/O事件。在14.5.2节中将对此进行讨论。在图10-1中,对SIGIO的系统默认动作是终止或忽略。遗憾的是,这依赖于系统。在System V中,SIGIOSIGPOLL相同,其默认动作是终止此进程。在BSD中,其默认动作是忽略此信号。Linux 3.2.0和Solaris 10将SIGIO定义为与SIGPOLL具有相同值,所以默认行为是终止该进程。在FreeBSD 8.0和MacOS X 10.6.8中,默认行为是忽略该信号。
  • SIGIOT 这指示一个实现定义的硬件故障。IOT这个名字来自于PDP-11,它是PDP-11计算机“输入/输出TRAP”(input/output TRAP)指令的缩写。System V的早期版本,由abort函数产生此信号。该函数现在产生SIGABRT信号。FreeBSD 8.0、Linux 3.2.0、Mac OS X 10.6.8和Solaris10将SIGIOT定义为与SIGABRT具相同值。
  • SIGJVM1 Solaris上为Java虚拟机预留的一个信号。
  • SIGJVM2 Solaris上为Java虚拟机预留的另一个信号。
  • SIGKILL 这是两个不能被捕捉或忽略信号中的一个。它向系统管理员提供了一种可以杀死任一进程的可靠方法。
  • SIGLOST 运行在Solaris NFSv4客户端系统中的进程,恢复阶段不能重新获得锁,此时将由这个信号通知该进程。
  • SIGLWP 此信号由Solaris线程库内部使用,并不做一般使用。在FreeBSD中,SIGLWPSIGTHR的别名。
  • SIGPIPE 如果在管道的读进程已终止时写管道,则产生此信号。15.2 节将说明管道。当类型为 SOCK_STREAM 的套接字已不再连接时,进程写该套接字也产生此信号。我们将在第16章说明套接字。
  • SIGPOLL 这个信号在SUSv4中已被标记为弃用,将来的标准可能会将此信号移除。当在一个可轮询设备上发生一个特定事件时产生此信号。14.4.2节将说明poll函数和此信号,它起源于SVR3,与BSD的SIGIOSIGURG信号接近。在Linux和Solaris中,SIGPOLL定义为与SIGIO具有相同值。
  • SIGPROF 这个信号在SUSv4中已被标记为弃用,将来的标准可能会将此信号移除。当setitimer(2)函数设置的梗概统计间隔定时器(profiling interval timer)已经超时时产生此信号。
  • SIGPWR 这是一种依赖于系统的信号。它主要用于具有不间断电源(UPS)的系统。如果电源失效,则UPS起作用,而且通常软件会接到通知。在这种情况下,系统依靠蓄电池电源继续运行,所以无须做任何处理。但是如果蓄电池也将不能支持工作,则软件通常会再次接到通知,此时,系统必项使其各部分都停止运行。这时应当发送 SIGPWR 信号。在大多数系统中,接到蓄电池电压过低信息的进程将信号SIGPWR发送给init进程,然后由init处理停机操作。Solaris 10和有些Linux版本在inittab文件中有两个记录项用于此种目的:powerfail以及powerwait(或powerokwait)。在图10-1中,我们将SIGPWR的默认动作标记为“终止或忽略”。遗憾的是,这种默认动作依赖于系统。Linux对此的默认动作是终止相关进程,而Solaris的默认动作是忽略该信号。
  • SIGQUIT 当用户在终端上按退出键(一般采用Ctrl+\)时,中断驱动程序产生此信号,并发送给前台进程组中的所有进程(见图9-9)。此信号不仅终止前台进程组(如SIGINT所做的那样),同时产生一个core文件。
  • SIGSEGV 指示进程进行了一次无效的内存引用(通常说明程序有错,比如访问了一个未经初始化的指针)。名字SEGV代表“段违例”(segmentation violation)。
  • SIGSTKFLT 此信号仅由Linux定义。它出现在Linux的早期版本,企图用于数学协处理器的栈故障。该信号并非由内核产生,但仍保留以向后兼容。
  • SIGSTOP 这是一个作业控制信号,它停止一个进程。它类似于交互停止信号(SIGTSTP),但是SIGSTOP不能被捕捉或忽略。
  • SIGSYS 该信号指示一个无效的系统调用。由于某种未知原因,进程执行了一条机器指令,内核认为这是一条系统调用,但该指令指示系统调用类型的参数却是无效的。这种情况是可能发生的,例如,若用户编写了一道使用新系统调用的程序,然后运行该程序的二进制可执行代码,而所用的操作系统却是不支持该系统调用的较早版本,于是就出现上述情况。
  • SIGTERM 这是由kill(1)命令发送的系统默认终止信号。由于该信号是由应用程序捕获的,使用SIGTERM也让程序有机会在退出之前做好清理工作,从而优雅地终止(相对于SIGKILL而言。SIGKILL不能被捕捉或者忽略)。
  • SIGTHAW 此信号仅由Solaris定义。在被挂起的系统恢复时,该信号用于通知相关进程,它们需要采取特定的动作。
  • SIGTHR FreeBSD线程库预留的信号,它的值定义或与SIGLWP相同。
  • SIGTRAP 指示一个实现定义的硬件故障。此信号名来自于PDP-11的TRAP指令。当执行断点指令时,实现常用此信号将控制转移至调试程序。
  • SIGTSTP 交互停止信号,当用户在终端上按挂起键(一般采用 Ctrl+Z)时,终端驱动程序产生此信号。该信号发送至前台进程组中的所有进程(参见图9-9)。遗憾的是,停止具有不同的含义。当讨论作业控制和信号时,我们谈及停止和继续作业。但是,终端驱动程序一直使用术语“停止”表示用Ctrl+S字符终止终端输出,为了继续启动该终端输出,则用Ctrl+Q字符。为此,终端驱动程序称产生交互停止信号的字符为挂起字符,而非停止字符。
  • SIGTTIN当一个后台进程组进程试图读其控制终端时,终端驱动程序产生此信号(见9.8节中对此问题的讨论)。在下列例外情形下不产生此信号:(a)读进程忽略或阻塞此信号;(b)读进程所属的进程组是孤儿进程组,此时读操作返回出错,errno设置为EIO。
  • SIGTTOU 当一个后台进程组进程试图写其控制终端时,终端驱动程序产生此信号(见9.8节对此问题的讨论)。与上面所述的SIGTTIN信号不同,一个进程可以选择允许后台进程写控制终端。第18章将讨论如何更改此选项。如果不允许后台进程写,则与SIGTTIN相似,也有两种特殊情况:(a)写进程忽略或阻塞此信号;(b)写进程所属进程组是孤儿进程组。在第2种情况下不产生此信号,写操作返回出错,errno设置为EIO。不论是否允许后台进程写,一些除写以外的下列终端操作也能产生SIGTTOU信号,如tcsetattr、tcsendbreak、tcdrain、tcflush、tcflow以及tcsetpgrp。第18章将说明这些终端操作。
  • SIGURG 此信号通知进程已经发生一个紧急情况。在网络连接上接到带外的数据时,可选择地产生此信号。
  • SIGUSR1 这是一个用户定义的信号,可用于应用程序。
  • SIGUSR2 这是另一个用户定义的信号,与SIGUSR1相似,可用于应用程序。
  • SIGVTALRM 当一个由setitimer(2)函数设置的虚拟间隔时间已经超时时,产生此信号。
  • SIGWAITING 此信号由Solaris线程库内部使用,不做他用。
  • SIGWINCH 内核维持与每个终端或伪终端相关联窗口的大小。进程可以用ioctl函数(见18.12 节)得到或设置窗口的大小。如果进程用 ioctl 的设置窗口大小命令更改了窗口大小,则内核将SIGWINCH信号发送至前台进程组。
  • SIGXCPU Single UNIX Specification的XSI扩展支持资源限制的概念(见7.11节)。如果进程超过了其软CPU时间限制,则产生此信号。在图10-1中,对于SIGXCPU的默认动作说明为“终止或终止+core”。该默认动作依赖于操作系统。Linux 3.2.0和Solaris 10支持的默认动作是终止并创建core文件;FreeBSD 8.0和Mac OS X 10.6.8支持的默认动作是终止且不产生core文件。Single UNIX Specification要求该默认动作是,异常终止该进程,是否创建core文件则留给实现决定。

  • SIGXFSZ 如果进程超过了其软文件长度限制(见7.11节),则产生此信号。如同SIGXCPU一样,针对SIGXFSZ的默认动作依赖于操作系统。Linux 3.2.0和Solaris 10对此信号的默认动作是终止并创建core文件。FreeBSD 8.0和Mac OS X 10.6.8支持的默认动作是终止且不产生core文件。Single UNIX Specification要求该默认动作是异常终止该进程,是否创建core文件则留给实现决定。

  • SIGXRES 此信号仅由Solaris定义。可选择地使用此信号以通知进程超过了预配置的资源值。Solaris资源限制机制是一种通用设施,用于控制在独立应用集之间共享资源的使用。

results matching ""

    No results matching ""