信号的概念

信号的概念

首先,每个信号都有一个名字。名字都以SIG开头。这些名字都由常量正整数定义在<signal.h>头文件中。(实际上一些实现都有自己独立的头文件,但是这些头文件也包含<signal.h>)

没有任何一个信号使用常量0。0是用于kill函数的一个特别案例。POSIX.1叫这个值为空信号(null signal)。

许多条件都能产生信号:

  • 当用户按某些终端键时,终端产生信号。如ctrl+C一般来说会产生中断信号(SIGINT)。这可以停止一个无法控制的程序。
  • 硬件异常产生信号:如除数为0、无效内存索引,这样类似的情况。这些条件一般是被硬件发现的,然后通知给内核。之后内核会产生一个适当的信号,发送给当前产生异常条件的程序。例如:一个进程执行了无效的内存索引,会产生SIGSEGV信号。
  • kill函数允许一个进程发送任何信号到另一个进程或进程组中。正常情况下有个限制:我们必须是接收信号的进程所有者,或者我们必须是超级用户。
  • kill命令允许我们发送信号到另一个进程。这个程序刚好有kill函数的接口。这个命令常用于制止一个无法停止的后台进程。
  • 当某件事发生,这件事应该通知给某进程时,软件条件也能产生信号。这不是硬件产生条件(如除数为0这样的条件),而是软件条件。例如:SIGURG(当超出带宽的数据到来的时候产生),SIGPIPE(当读取PIPE的程序已经终止,进程仍然写PIPE时产生。),SIGALRM(当进程设置的始终到期时产生)

信号是异步事件的典型例子。信号可以发生在进程运行的任意时间里。进程不能简单的测试某一变量值来判断信号是否产生了。而是进程必须告诉内核“如果某一信号发生了,那么就这么干。”

我们可以让内核做下面三件事之一。我们称之为“信号处置(disposition of the signal)”或“信号关联动作”。

  1. 忽略信号。这用于多数信号,但是两种信号不能忽略:SIGKILL和SIGSTOP。原因是这两种信号不能被忽略,这是给内核或超级用户提供一种可靠的结束进程的方法。如果忽略了由硬件产生的异常,那么进程的行为是未定义的。
  2. 捕获信号。这么做是告诉内核,无论可时产生了信号,就调用我们的某一程序进程处理。在我们的函数中,我们可以做任何我们想处理的条件。如果我们写了一个命令中断,当用户使用键盘产生一个中断信号时,我们可能想返回主函数,终止用户已经执行的任何命令。如果SIGCHLD信号被捕获,它意味着子进程已经终止,所以信号捕获函数可以调用waitpid去获得子进程的PID和终止状态。做为另一个例子,如果进程已经创建了临时文件,我们可能想写一个捕获SIGTERM(终止信号是kill命令默认发送的信号)信号的函数,去清除临时文件。注意:SIGKILL和SIGSTOP这两个信号不能被捕获。
  3. 使用默认动作。每个信号都有一个默认动作。注意:对于多数信号来说默认动作是结束进程。

下面表格显示了信号的默认动作:

Figure 10.1. UNIX System signals

Name

Description

ISO C

SUS

FreeBSD 5.2.1

Linux 2.4.22

Mac OS X 10.3

Solaris 9

Default action

SIGABRT

abnormal termination (abort)

•

•

•

•

•

•

terminate+core

SIGALRM

timer expired (alarm)

•

•

•

•

•

terminate

SIGBUS

hardware fault

•

•

•

•

•

terminate+core

SIGCANCEL

threads library internal use

•

ignore

SIGCHLD

change in status of child

•

•

•

•

•

ignore

SIGCONT

continue stopped process

•

•

•

•

•

continue/ignore

SIGEMT

hardware fault

•

•

•

•

terminate+core

SIGFPE

arithmetic exception

•

•

•

•

•

•

terminate+core

SIGFREEZE

checkpoint freeze

•

ignore

SIGHUP

hangup

•

•

•

•

•

terminate

SIGILL

illegal instruction

•

•

•

•

•

•

terminate+core

SIGINFO

status request from keyboard

•

•

ignore

SIGINT

terminal interrupt character

•

•

•

•

•

•

terminate

SIGIO

asynchronous I/O

•

•

•

•

terminate/ignore

SIGIOT

hardware fault

•

•

•

•

terminate+core

SIGKILL

termination

•

•

•

•

•

terminate

SIGLWP

threads library internal use

•

ignore

SIGPIPE

write to pipe with no readers

•

•

•

•

•

terminate

SIGPOLL

pollable event (poll)

XSI

•

•

terminate

SIGPROF

profiling time alarm (setitimer)

XSI

•

•

•

•

terminate

SIGPWR

power fail/restart

•

•

terminate/ignore

SIGQUIT

terminal quit character

•

•

•

•

•

terminate+core

SIGSEGV

invalid memory reference

•

•

•

•

•

•

terminate+core

SIGSTKFLT

coprocessor stack fault

•

terminate

SIGSTOP

stop

•

•

•

•

•

stop process

SIGSYS

invalid system call

XSI

•

•

•

•

terminate+core

SIGTERM

termination

•

•

•

•

•

•

terminate

SIGTHAW

checkpoint thaw

•

ignore

SIGTRAP

hardware fault

XSI

•

•

•

•

terminate+core

SIGTSTP

terminal stop character

•

•

•

•

•

stop process

SIGTTIN

background read from control tty

•

•

•

•

•

stop process

SIGTTOU

background write to control tty

•

•

•

•

•

stop process

SIGURG

urgent condition (sockets)

•

•

•

•

•

ignore

SIGUSR1

user-defined signal

•

•

•

•

•

terminate

SIGUSR2

user-defined signal

•

•

•

•

•

terminate

SIGVTALRM

virtual time alarm (setitimer)

XSI

•

•

•

•

terminate

SIGWAITING

threads library internal use

•

ignore

SIGWINCH

terminal window size change

•

•

•

•

ignore

SIGXCPU

CPU limit exceeded (setrlimit)

XSI

•

•

•

•

terminate+core/ignore

SIGXFSZ

file size limit exceeded (setrlimit)

XSI

•

•

•

•

terminate+core/ignore

SIGXRES

resource control exceeded

•

ignore

SUS列上的•代表它是作为POSIX.1的一部分定义的。XSI代表它是以XSI扩展为基础的。

默认动作为“terminate+core”,它意味着进程的内存镜像已经离开该进程工作目录的core文件。(因为文件被命名为core,它显示了这个功能已经做为UNIX 系统的一部分多长时间了。)这个文件能用于UNIX系统的调式工作,去检查进程结束时的状态。

PS:core文件是发行版本的功能。虽然不是POSIX.1的功能,但是它已经是Single UNIX Specification 的XSI扩展中移植实现指定的功能。

以下几种情况core文件不会产生:

  1. 进程使用了set-user-ID并且当前用户不是程序文件的所有者。
  2. 进程使用了set-group-ID并且当前用户不是程序文件的组所有者。
  3. 用户没有写当前工作目录的权限。
  4. core file已经存在,并且用户没有权限写这个文件。
  5. 文件太大(查看RLIMIT_CORE的设置)

假设core文件不存在,它的权限通常是用户读、写。

具体每个信号的描述详见APUE第10.2节

Comments are closed.