c - Unix信号如何工作?

标签 c unix signals

在unix中,信号是如何工作的?我通过了W.R.史蒂文斯,但无法理解。请帮帮我。

最佳答案

下面的解释并不准确,不同的系统(甚至可能是同一个操作系统在不同的硬件上的某些部分)在几个方面的工作方式也有所不同,但我认为这通常足以满足您使用它们的好奇心。大多数人开始在编程中使用信号时甚至没有这种程度的理解,但在我习惯使用它们之前,我想理解它们。
信号传输
操作系统内核有一个称为进程控制块的数据结构,用于运行的每个进程,其中包含有关该进程的数据。这可以通过进程id(pid)查找,并包含一个信号操作和挂起信号的表。
当一个信号被发送到一个进程时,操作系统内核将查找该进程的进程控制块,并检查信号操作表,以定位发送的特定信号的操作。如果信号动作值SIG_IGN则内核会忘记新信号。如果signal action值SIG_DFL则内核在另一个表中查找该信号的默认信号处理操作,并执行该操作。如果值是其他值,则假定该值是发送信号的进程中的函数地址,应调用该函数地址。SIG_IGNSIG_DFL的值是转换为函数指针的数字,这些指针的值不是进程地址空间中的有效地址(例如0和1,它们都在0页中,但从未映射到进程中)。
如果进程注册了一个信号处理函数(信号操作值既不是sig ign也不是sig dfl),则会在挂起信号表中为该信号创建一个条目,并将该进程标记为准备运行(它可能一直在等待某些东西,如数据变为可用于调用read,等待一个或多个信号其他事情)。
现在,下一次运行进程时,操作系统内核将首先向堆栈中添加一些数据,并更改该进程的指令指针,使其看起来几乎像进程本身刚刚调用了信号处理程序。这并不是完全正确的,实际上与实际发生的情况有足够的偏差,我将在一小部分中详细讨论。
信号处理函数可以做它所做的任何事情(它是代表它被调用的进程的一部分,因此它是用该程序应该如何处理该信号的知识编写的)。当信号处理程序返回时,进程的常规代码将再次开始执行。(同样,不准确,但下一步会更详细)
好吧,上面的内容应该让您对如何将信号传递到进程有了很好的了解。我认为在你掌握完整的想法之前,需要这个非常好的想法版本,其中包括一些更复杂的东西。
操作系统内核通常需要知道信号处理程序何时返回。这是因为信号处理程序接受一个参数(可能需要堆栈空间),您可以在执行信号处理程序期间阻止同一信号被传递两次,和/或在传递信号后重新启动系统调用。要实现这一点,不仅仅是堆栈和指令指针的更改。
必须发生的是,内核需要让进程告诉它它已经完成执行信号处理函数。这可以通过将ram的一部分映射到进程的地址空间来实现,该地址空间包含进行此系统调用的代码,并将信号处理函数的返回地址(此函数开始运行时堆栈上的顶部值)作为此代码的地址。我认为这就是Linux(至少是较新版本)的工作方式。实现这一点的另一种方法是(我不知道这是否实现,但它可能实现)将使信号处理函数的返回地址为无效地址(如空),这将导致大多数系统中断,从而再次提供操作系统内核控制。这种情况如何发生并不重要,但内核必须再次获得控制才能修复堆栈并知道信号处理程序已经完成。
当我研究另一个问题时
Linux内核确实将一个页面映射到了这个进程中,但是注册信号处理程序的实际系统调用(sigaction调用的)使用了一个参数sa_restore parameter,该参数是一个应该用作信号处理程序返回地址的地址,内核只是确保它放在那里。这个地址的代码发出i'm done系统调用(sigreturn),内核知道信号处理程序已经完成。
信号产生
我主要假设你知道信号是如何产生的。OS可以代表一个进程,因为某些事情发生,比如一个定时器到期,一个孩子进程死亡,访问内存,它不应该访问,或发出一个指令,它不应该(要么是一个指令不存在或一个特权),或许多其他事情。计时器情况在功能上与其他情况略有不同,因为它可能在进程未运行时发生,因此更像是通过kill系统调用发送的信号。对于代表当前进程发送的与计时器无关的信号,这些信号是在当前进程出错而发生中断时生成的。这个中断提供内核控制(就像系统调用一样),内核生成要传递给当前进程的信号。

关于c - Unix信号如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4208004/

相关文章:

c - 为什么 *(a+b) 在 C 而不是 a[b] 中工作?

c - 使用 Lua C API 选择带有选择器字符串的嵌套值

c - 如何使用指向另一个字段的字段初始化结构?

c++ - 使用 boost::signals2 处理许多信号/槽的连接/断开

c - 在 c 中硬编码大小的最佳方法

c - RSA_private_decrypt 错误代码 : error0407106b: lib(4):funct:(113):reason(107)

linux - 如何使用 SSH 从服务器下载文件?

java - 当我输入 "java -version"时,它从哪里提取该信息?

c++ - 传递给 C 库的函数指针的 C 链接

c - sem_wait 和信号处理程序