Linux 内核中的信号机制允许正在运行的应用程序在发生新事件时异步通知系统。 由于其性质,这种信号机制通常被称为软件中断。 就像硬件中断一样,信号会中断应用程序的正常流程,并且无法预测应用程序何时会收到信号。
让我们深入研究 Linux 中的信号机制并了解幕后发生的事情。
Linux 中的基本信号概念
在 Linux 上,进程在三种基本情况下生成信号:
- 当硬件端出现异常情况时。 例如,您可以考虑诸如应用程序试图访问允许的地址空间之外的区域(分段错误)或生成包含除以零操作的机器代码等事件。
- 诸如使用组合键之类的情况 Ctrl + C 或者 Ctrl + Z 用户在控制台上,调整控制台屏幕的大小,或发送终止信号。
- 应用程序中设置的计时器到期,给予应用程序的 CPU 限制很高,数据到达打开的文件描述符等。
信号的概念从 Unix 的早期版本就已经存在。 以前,Unix 版本之间在信号处理方面存在一些差异。 后来,随着信号管理的 POSIX 标准化,Linux 和其他 Unix 衍生产品开始遵循这些标准。 出于这个原因,您可能在某些文档中遇到的 Unix 信号和 POSIX 信号的概念指出了不同之处。
信号编号
信号有各种数值,从一个开始。 例如,信号 1 是 HUP 几乎每个系统中的信号,或者信号 9 是 杀 信号。
但是,当您在应用程序中使用信号时,强烈建议不要使用这些数字。 对于 POSIX 信号, 信号.h 文件应该在应用程序中,开发人员应该使用相关数字的常量定义,例如 SIGHUP, 杀戮等。
如果你检查 /usr/include/signal.h 文件,您可以通过查看值的定义来查看附加操作和其他包含的文件,例如 __USE_POSIX, __USE_XOPEN, __USE_POSIX199309等文件中。 您可以在 Linux 系统中找到可用的信号编号 /usr/include/asm-generic/signal.h 文件,您不需要直接将其包含在应用程序代码中。
信号生成和发送
由于事件而发生信号生成。 然而,将信号发送(传递)到相关应用程序不会与信号的生成同时发生。
对于要发送到应用程序的信号,应用程序必须当前正在运行并且具有 CPU 资源。 因此,当相关应用程序在上下文切换后再次开始工作时,就会向特定应用程序发送信号。
未决信号概念
在信号从产生到传输期间,信号处于待机状态。 您可以从 /proc/PID/状态 文件。
# For a process with PID: 2299
cat /proc/2299/status
# Output
...
SigQ: 2/31630
...
信号屏蔽和阻塞
应用程序通常无法预测信号到达的确切时间。 因此,在任何操作过程中都可能发生一些严重的中断。 这可能会导致大规模应用程序出现重大问题。
为防止出现此类不良情况,有必要使用信号掩码。 因此,可以在关键操作之前阻止一些信号。 在这个阶段,重要的是完成关键部分并删除定义的块。 这个过程是应用程序开发者应该注意的。
当应用程序阻塞一个信号时,产生的其他同类型信号将处于等待状态,直到解除阻塞。 在应用程序中,一旦块被移除,也提供待处理信号的发送。
这样,在正常使用中删除块后,在块时被搁置的相同类型的信号只会发送到应用程序一次。 实时信号的情况有所不同。
Linux 信号类型
默认操作可能因信号类型而异。 如果接收到相应信号的应用程序没有信号处理函数,则执行默认操作。 有时这意味着终止应用程序,有时会忽略信号。
有些信号无法在应用层捕获,这些信号始终执行默认操作(如 KILL 信号)。
除了导致应用程序终止的某些操作之外,还会生成核心转储文件。 通过将相关进程的虚拟内存表写入磁盘而创建的核心转储文件可帮助用户在进程结束前检查状态信息,并在下一阶段使用调试工具。
以下值基于 典型的 MIPS 架构:
信号 | 数字 | 默认操作 | 它可以被抓住吗? |
---|---|---|---|
SIGHUP | 1 | 终止申请 | 是的 |
信号情报 | 2 | 终止申请 | 是的 |
SIGQUIT | 3 | 终止应用程序(核心转储) | 是的 |
海豹 | 4 | 终止应用程序(核心转储) | 是的 |
SIGTRAP | 5 | 终止应用程序(核心转储) | 是的 |
SIGABRT | 6 | 终止应用程序(核心转储) | 是的 |
SIGFPE | 8 | 终止应用程序(核心转储) | 是的 |
杀戮 | 9 | 终止申请 | 不 |
信号总线 | 10 | 终止应用程序(核心转储) | 是的 |
SIGSEGV | 11 | 终止应用程序(核心转储) | 是的 |
SIGSYS | 12 | 终止应用程序(核心转储) | 是的 |
SIGPIPE | 13 | 终止申请 | 是的 |
SIGALRM | 14 | 终止申请 | 是的 |
SIGTERM | 15 | 终止申请 | 是的 |
SIGUSR1 | 16 | 终止申请 | 是的 |
SIGUSR2 | 17 | 终止申请 | 是的 |
SIGCHLD | 18 | 忽视 | 是的 |
SIGTSTP | 20 | 停止 | 是的 |
西格 | 21 | 忽视 | 是的 |
信号轮询 | 22 | 终止申请 | 是的 |
信号停止 | 23 | 停止 | 不 |
SIGCONT | 25 | 如果停止则继续 | 是的 |
SIGTTIN | 26 | 停止 | 是的 |
西头 | 27 | 停止 | 是的 |
SIGVTALRM | 28 | 终止申请 | 是的 |
SIGPROF | 29 | 终止申请 | 是的 |
SIGXCPU | 30 | 终止应用程序(核心转储) | 是的 |
SIGXFSZ | 31 | 终止应用程序(核心转储) | 是的 |
Linux 中信号的生命周期
信号经过三个阶段。 它们主要在生产阶段由内核或任何进程产生,并由一个数字表示。 他们工作轻而快,因为他们没有任何额外的负担。 但是如果你看一下 POSIX 方面,你会发现实时信号可以传输额外的数据。
信号的交付阶段在生产阶段之后。 通常,信号会尽快从内核到达应用程序。 但是,有时应用程序可能会在执行关键操作时阻塞信号。 在这种情况下,信号将保持未决状态,直到交易发生。
与信号一样,进程也是 Linux 生态系统不可或缺的一部分。 如果您打算成为 Linux 系统管理员,那么了解什么是进程以及它们如何工作至关重要。