是什么导致发送各种信号?


28

有时,我会对进程可以接收的所有信号感到有些困惑。据我了解,进程为每个信号都有一个默认的处理程序(信号处理),但是它可以通过调用提供自己的处理程序sigaction()

所以这是我的问题:是什么原因导致每个信号被发送?我意识到您可以通过-s参数to 手动将信号发送到正在运行的进程kill,但是在什么自然条件下发送这些信号?例如,何时SIGINT发送?

另外,可以处理哪些信号是否有任何限制?甚至SIGSEGV可以处理信号并将控制权返回给应用程序吗?


对此的正确答案将是史诗般的,并且基本上可以复制Wikipedia文章中有关此问题的信息,因此,我仅在此处指出。
肖恩·高夫

@Shawn:Wikipedia文章有一个信号列表,但是没有清楚地说明谁发送了什么信号。
吉尔(Gilles)“所以,别再邪恶了”,

Answers:


41

除了进程调用外kill(2),在各种情况下,某些信号是由内核(或有时由进程本身)发送的:

  • 终端驱动程序发送与各种事件对应的信号:
    • 按键通知: SIGINT(请返回到主循环)的Ctrl+ CSIGQUIT(请立即退出)的Ctrl+ \SIGTSTP(请暂停)上Ctrl+ Z。可以使用stty命令更改键。
    • SIGTTINSIGTTOU在后台进程尝试对其控制终端进行读写时发送。
    • SIGWINCH 发送以通知终端窗口的大小已更改。
    • SIGHUP被发送到信号终端已经消失(因为历史上你的modem了^ h UNG ,现在通常是因为你已经关闭了终端仿真器窗口)。
  • 一些处理器陷阱可以生成信号。详细信息取决于体系结构和系统。以下是典型示例:
    • SIGBUS 用于未对齐的访问存储器;
    • SIGSEGV 用于访问未映射的页面;
    • SIGILL 用于非法指令(错误的操作码);
    • SIGFPE用于带有错误参数的浮点指令(例如sqrt(-1))。
  • 许多信号通知目标进程某些系统事件已经发生:
    • SIGALRM通知该进程设置的计时器已过期。定时器可以设置用alarmsetitimer等等。
    • SIGCHLD 通知进程其一个孩子已经死亡。
    • SIGPIPE当读取端已关闭时,如果进程尝试向管道中写入数据,则会生成此错误(想法是如果您运行foo | barbar退出,foo将被杀死SIGPIPE)。
    • SIGPOLL(也称为SIGIO)通知进程已发生可轮询的事件。POSIX指定通过进行注册的可轮询事件I_SETSIG ioctl。许多系统允许通过O_ASYNC fcntl标志设置的任何文件描述符上的可轮询事件。相关信号是SIGURG,用于通知设备(通过I_SETSIG ioctl套接字注册)上的紧急数据。
    • 在某些系统上,SIGPWRUPS发出即将发生电源故障的信号时,该消息将发送到所有进程。

这些列表并不详尽。标准信号在中定义signal.h

应用程序可以捕获和处理(或忽略)大多数信号。不能捕获的仅有两个便携式信号是SIGKILL(只是死)和STOP(停止执行)。

SIGSEGV分段错误)及其表亲SIGBUS总线错误)可以被捕获,但这是一个坏主意,除非您真的知道自己在做什么。捕获它们的常见应用程序是打印堆栈跟踪或其他调试信息。一个更高级的应用程序是实现某种进程内内存管理,或在虚拟机引擎中捕获错误的指令。

最后,让我提及一些不是信号的东西。当您在从终端读取输入的程序的行首按Ctrl+ D时,这将告诉程序输入文件已到达末尾。这不是信号:它是通过输入/输出API传输的。像Ctrl+ C和朋友一样,可以使用来配置键stty


和SIGHUP,您的调制解调器已挂断。:-)
Keith

1
要注意的另一件事:SIGFPE整数除零时,有时在有符号整数溢出时,也会发出信号,这有点不直观。
短暂的2011年

18

首先要回答您的第二个问题: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(或以其他方式断开终端)时发生的情况。
  • SIGTTINSIGTTOU如果程序在后台运行时尝试从终端读取或写入终端,请暂停该程序。为了SIGTTOU实现这一点,我认为程序需要写入/dev/tty,而不仅仅是默认的stdout。

由CPU异常触发

这意味着您的程序试图做错事。

  • SIGILL表示非法或未知的处理器指令。例如,如果您尝试直接访问处理器I / O端口,则可能会发生这种情况。
  • SIGFPE表示存在硬件数学错误;该程序最有可能试图除以零。
  • SIGSEGV 表示您的程序试图访问未映射的内存区域。
  • SIGBUS表示程序以其他方式错误地访问了内存;我不会在此摘要中详细介绍。

流程互动

  • SIGPIPE如果您在管道的阅读器关闭管道末端后尝试写入管道,则会发生这种情况。请参阅man 7 pipe
  • SIGCHLD当您创建的子进程退出或被暂停(由SIGSTOP或类似原因)时发生。

对于自信令很有用

  • SIGABRT通常是由程序调用abort()函数引起的,默认情况下会导致核心转储。一种“紧急按钮”。
  • SIGALRM是由alarm()系统调用引起的,这将导致内核SIGALRM在指定的秒数后将a 传递给程序。请参阅man 2 alarmman 2 sleep
  • SIGUSR1并且SIGUSR2被程序喜欢使用。它们对于在进程之间发信号很有用。

由管理员发送

这些信号通常是从命令提示符处通过kill命令发送的,fg或者bg在的情况下发送SIGCONT

  • SIGKILLSIGSTOP是不可阻挡的信号。第一个总是总是立即终止该过程;第二个暂停该过程。
  • SIGCONT 恢复暂停的过程。
  • SIGTERM是的可捕获版本SIGKILL

shutdown使用命令时发送哪个信号?
内森·奥斯曼

这取决于关闭脚本。通常,SIGTERM先发送,然后发送延迟,然后发送 SIGKILL。原则上,对于硬性立即关闭,内核根本不需要发送信号。它可能只是停止运行该过程。
詹德(Jander)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.