有时,我会对进程可以接收的所有信号感到有些困惑。据我了解,进程为每个信号都有一个默认的处理程序(信号处理),但是它可以通过调用提供自己的处理程序sigaction()
。
所以这是我的问题:是什么原因导致每个信号被发送?我意识到您可以通过-s
参数to 手动将信号发送到正在运行的进程kill
,但是在什么自然条件下发送这些信号?例如,何时SIGINT
发送?
另外,可以处理哪些信号是否有任何限制?甚至SIGSEGV
可以处理信号并将控制权返回给应用程序吗?
有时,我会对进程可以接收的所有信号感到有些困惑。据我了解,进程为每个信号都有一个默认的处理程序(信号处理),但是它可以通过调用提供自己的处理程序sigaction()
。
所以这是我的问题:是什么原因导致每个信号被发送?我意识到您可以通过-s
参数to 手动将信号发送到正在运行的进程kill
,但是在什么自然条件下发送这些信号?例如,何时SIGINT
发送?
另外,可以处理哪些信号是否有任何限制?甚至SIGSEGV
可以处理信号并将控制权返回给应用程序吗?
Answers:
除了进程调用外kill(2)
,在各种情况下,某些信号是由内核(或有时由进程本身)发送的:
SIGALRM
通知该进程设置的计时器已过期。定时器可以设置用alarm
,setitimer
等等。SIGCHLD
通知进程其一个孩子已经死亡。SIGPIPE
当读取端已关闭时,如果进程尝试向管道中写入数据,则会生成此错误(想法是如果您运行foo | bar
并bar
退出,foo
将被杀死SIGPIPE
)。SIGPOLL
(也称为SIGIO
)通知进程已发生可轮询的事件。POSIX指定通过进行注册的可轮询事件I_SETSIG
ioctl
。许多系统允许通过O_ASYNC
fcntl
标志设置的任何文件描述符上的可轮询事件。相关信号是SIGURG
,用于通知设备(通过I_SETSIG
ioctl
或套接字注册)上的紧急数据。SIGPWR
当UPS发出即将发生电源故障的信号时,该消息将发送到所有进程。这些列表并不详尽。标准信号在中定义signal.h
。
应用程序可以捕获和处理(或忽略)大多数信号。不能捕获的仅有两个便携式信号是SIGKILL
(只是死)和STOP
(停止执行)。
SIGSEGV
(分段错误)及其表亲SIGBUS
(总线错误)可以被捕获,但这是一个坏主意,除非您真的知道自己在做什么。捕获它们的常见应用程序是打印堆栈跟踪或其他调试信息。一个更高级的应用程序是实现某种进程内内存管理,或在虚拟机引擎中捕获错误的指令。
最后,让我提及一些不是信号的东西。当您在从终端读取输入的程序的行首按Ctrl+ D时,这将告诉程序输入文件已到达末尾。这不是信号:它是通过输入/输出API传输的。像Ctrl+ C和朋友一样,可以使用来配置键stty
。
SIGFPE
在整数除零时,有时在有符号整数溢出时,也会发出信号,这有点不直观。
首先要回答您的第二个问题:SIGSTOP
并且SIGKILL
不能被应用程序捕获,但是其他所有信号都可以,甚至SIGSEGV
。此属性对于调试很有用-例如,在正确的库支持下,您可以侦听SIGSEGV
并生成堆栈回溯以显示该段错误发生的位置。
可以man 7 signal
从Linux命令行键入有关每个信号作用的官方字词(无论如何,对于Linux)。 http://linux.die.net/man/7/signal具有相同的信息,但是表格很难阅读。
但是,如果没有信号的经验,很难从简短的描述中知道它们在实践中的作用,所以这是我的解释:
SIGINT
击中时发生CTRL+C
。SIGQUIT
由触发CTRL+\
,并转储核心。SIGTSTP
按下时暂停程序CTRL+Z
。与不同SIGSTOP
,它是可捕获的,它使程序vi
有机会在挂起自身之前将终端重置为安全状态。SIGHUP
(“挂断”)是在程序运行时关闭xterm(或以其他方式断开终端)时发生的情况。SIGTTIN
SIGTTOU
如果程序在后台运行时尝试从终端读取或写入终端,请暂停该程序。为了SIGTTOU
实现这一点,我认为程序需要写入/dev/tty
,而不仅仅是默认的stdout。这意味着您的程序试图做错事。
SIGILL
表示非法或未知的处理器指令。例如,如果您尝试直接访问处理器I / O端口,则可能会发生这种情况。SIGFPE
表示存在硬件数学错误;该程序最有可能试图除以零。SIGSEGV
表示您的程序试图访问未映射的内存区域。SIGBUS
表示程序以其他方式错误地访问了内存;我不会在此摘要中详细介绍。SIGPIPE
如果您在管道的阅读器关闭管道末端后尝试写入管道,则会发生这种情况。请参阅man 7 pipe
。SIGCHLD
当您创建的子进程退出或被暂停(由SIGSTOP
或类似原因)时发生。SIGABRT
通常是由程序调用abort()
函数引起的,默认情况下会导致核心转储。一种“紧急按钮”。SIGALRM
是由alarm()
系统调用引起的,这将导致内核SIGALRM
在指定的秒数后将a 传递给程序。请参阅man 2 alarm
和man 2 sleep
。SIGUSR1
并且SIGUSR2
被程序喜欢使用。它们对于在进程之间发信号很有用。这些信号通常是从命令提示符处通过kill
命令发送的,fg
或者bg
在的情况下发送SIGCONT
。
SIGKILL
和SIGSTOP
是不可阻挡的信号。第一个总是总是立即终止该过程;第二个暂停该过程。SIGCONT
恢复暂停的过程。SIGTERM
是的可捕获版本SIGKILL
。shutdown
使用命令时发送哪个信号?
SIGTERM
先发送,然后发送延迟,然后发送 SIGKILL
。原则上,对于硬性立即关闭,内核根本不需要发送信号。它可能只是停止运行该过程。