为什么 Unix 程序不能有有意义的程序定义名称的信号(而不是 USR1等) ?

许多 Unix 程序接受像 USR1USR2这样的信号。例如,要动态升级 Nginx 的可执行文件,您可以发送 kill -USR2

我理解 USR1是一个“用户定义”的信号,这意味着创建程序的人可以使用它来表示“关闭”或“转储您的日志”或“打印 foo 一千次”或其他什么。但我不明白为什么他们一定要用这个武断的名字。为什么不是 kill -UPGRADE或者 kill -GRACEFUL_SHUTDOWN?Unix 只允许特定的信号吗?

同时,Nginx 还使用以下信号(参见 文件) :

  • TERM,INT : 快速关机
  • 优雅的关机
  • HUP :
    • 重新配置
    • 使用新配置启动新辅助进程
    • 优雅地关闭旧的工作进程
  • USR1 : 重新打开日志文件
  • USR2 : 即时升级可执行文件
  • WINCH : 优雅地关闭工作进程

HUP? WINCH? 这些名字的原因是什么? 我在哪里可以学到更多关于这方面的知识?

55918 次浏览

操作系统上可用的信号是由操作系统定义的(通常在 POSIX 之后)——它们不是“字符串”,而是具有标准名称的整数常量。USR1USR2是两个没有附加特定含义的信号——用于开发人员想要的任意用途。

在 Linux 机器上,阅读 man 7 signal以获得信号处理和信号的概述。

如果准备好处理操作系统响应事件发出的信号,那么可以重新定义其他信号的含义。例如,你可以使 HUP意味着“重新加载配置”——只要你确定这个过程永远不会挂起(终端丢失) ,或者你准备好处理操作系统而不是用户发送 HUP 信号的情况。

因为信号的 名字是标准化的(由 POSIX)。如果愿意,您可以编写自己的 kill-type 可执行文件来接收 -UPGRADE,并让它传递 USR1信号,但 UNIX 附带的标准 kill将无法识别它。

或者,您可以创建一个别名、函数或 shell 脚本来为您进行翻译,例如使用 bash别名:

alias upgrade='kill -USR1'

signal.h头文件将信号名映射到它们的实际值,这些实际值依赖于实现。

WINCH而言,我认为这有点令人厌恶。这是当应用程序的窗口大小发生变化时(特别是当其控制终端的窗口发生变化时)传递给应用程序的信号。

使用它来优雅地关闭工作线程并不是一个好主意,除非您可以保证进程永远不会在终端中运行。我知道如果我运行一个应用程序,它决定取消所有飞行中的工作,仅仅因为我最大化了窗口,我会非常生气: -)

在符合 POSIX 的平台上,SIGUSR1SIGUSR2是发送到进程的信号,用于指示用户定义的条件。它们的符号常量在头文件 signal.h中定义。使用符号信号名称是因为信号号可以在不同的平台上变化。

SIG是信号名称的常用前缀。 USR是用户定义的缩写。

HUP是“挂断”的简称。如果进程的控制终端达到文件末端,则该信号被发送到进程。在过去,控制终端通常连接到串行端口,可能通过电话线上的调制解调器链路。如果电话连接被挂起,本地调制解调器将降低载波检测线,这将导致内核报告文件结束和发送 SIGHUP信号。

WINCH是“窗口改变”的简称。如果进程的控制终端改变大小,则将其发送到进程。出于显而易见的原因,可以改变大小的终端通常是伪终端,最终由运行在窗口环境(如 xterm)中的虚拟终端表示。

试试 kill -l,自己找答案:

1)  SIGHUP       2)  SIGINT       3)  SIGQUIT      4)  SIGILL       5)  SIGTRAP
6)  SIGABRT      7)  SIGBUS       8)  SIGFPE       9)  SIGKILL      10) SIGUSR1
11) SIGSEGV      12) SIGUSR2      13) SIGPIPE      14) SIGALRM      15) SIGTERM
16) SIGSTKFLT    17) SIGCHLD      18) SIGCONT      19) SIGSTOP      20) SIGTSTP
21) SIGTTIN      22) SIGTTOU      23) SIGURG       24) SIGXCPU      25) SIGXFSZ
26) SIGVTALRM    27) SIGPROF      28) SIGWINCH     29) SIGIO        30) SIGPWR
31) SIGSYS       34) SIGRTMIN     35) SIGRTMIN+1   36) SIGRTMIN+2   37) SIGRTMIN+3
38) SIGRTMIN+4   39) SIGRTMIN+5   40) SIGRTMIN+6   41) SIGRTMIN+7   42) SIGRTMIN+8
43) SIGRTMIN+9   44) SIGRTMIN+10  45) SIGRTMIN+11  46) SIGRTMIN+12  47) SIGRTMIN+13
48) SIGRTMIN+14  49) SIGRTMIN+15  50) SIGRTMAX-14  51) SIGRTMAX-13  52) SIGRTMAX-12
53) SIGRTMAX-11  54) SIGRTMAX-10  55) SIGRTMAX-9   56) SIGRTMAX-8   57) SIGRTMAX-7
58) SIGRTMAX-6   59) SIGRTMAX-5   60) SIGRTMAX-4   61) SIGRTMAX-3   62) SIGRTMAX-2
63) SIGRTMAX-1   64) SIGRTMAX

信号名称起源于比 Posix 更早的时代。

我想谈谈 SIG 的事。在使用 DEC PDP 大型机的时候,所使用的处理器有一个特殊的物联网指令(I/O Trap) ,通常用于 轻轻地使系统崩溃——通常迫使它重新启动(在实时服务器中)。整个内核以及设备驱动程序和特权进程(用汇编语言编写)都使用了这种方法。即使在今天,仍然有一些处理器使用物联网指令。

因此,当内核在非特权域中执行物联网指令时,它会向受影响的进程引发一个 SIGIOT。