unix信号如何工作?

use*_*401 17 c unix signals

信号如何在unix中工作?我经历了WR史蒂文斯,但无法理解.请帮我.

nat*_*ose 40

下面的解释是不完全一样,和这个作品不同的系统(甚至在不同的硬件相同的操作系统的某些部分)之间的区别的几个方面,但我认为这是一般 足够让你满足你的好奇心足以使用它们.大多数人开始在编程中使用信号,甚至没有这种理解水平,但在我习惯使用它们之前,我想了解它们.

信号传递

OS内核有一个称为进程控制块的数据结构,用于运行的每个进程,其中包含有关该进程的数据.这可以通过进程ID(PID)查找,并包括信号动作和未决信号的表.

当信号发送到进程时,OS内核将查找该进程的进程控制块,并检查信号操作表以找到正在发送的特定信号的操作.如果信号动作值是SIG_IGN那么内核忘记了新信号.如果信号动作值是,SIG_DFL则内核在另一个表中查找该信号的默认信号处理动作并执行该动作.如果值是其他任何值,则假定该过程中的函数地址是信号被发送到的应该被调用的函数地址.为价值观SIG_IGNSIG_DFL 是转换为函数指针的数字,其值不是进程地址空间中的有效地址(例如0和1,它们都在第0页,从不映射到进程).

如果进程注册了一个信号处理函数(信号动作值既不是SIG_IGN也不是SIG_DFL),则在该信号表中挂起信号表中的一个条目,并且该进程被标记为准备好运行(它可能一直在等待某些东西,比如可用于呼叫read,等待信号或其他一些东西的数据.

现在,下一次运行该进程时,OS内核将首先向堆栈添加一些数据,并更改该进程的指令指针,使其看起来几乎就像进程本身刚刚调用了信号处理程序一样.这不是完全正确的,实际上与实际发生的事情有很大不同,我会稍微谈谈它.

信号处理函数可以执行它所做的任何事情(它是代表它调用的进程的一部分,因此它是在知道该程序应该对该信号执行什么的情况下编写的).当信号处理程序返回时,进程的常规代码再次开始执行.(再次,不准确,但下一步更多)

好的,上面的内容应该让您非常清楚如何将信号传递给流程.我觉得这个 不错 的想法,才能掌握充分的想法,其中包括一些更复杂的东西需要的版本.

OS内核通常需要知道信号处理程序何时返回.这是因为信号处理程序采用参数(可能需要堆栈空间),您可以阻止在执行信号处理程序期间两次传递相同的信号,和/或在传递信号后重新启动系统调用.为了实现这一点,比堆栈和指令指针更改更多.

有什么要发生的是,内核需要做的过程中告诉它,它已经完成执行信号处理函数.这可以通过将一部分RAM映射到进程的地址空间来完成,该地址空间包含进行此系统调用的代码,并使信号处理函数的返回地址(此函数开始运行时堆栈的最高值)为地址这段代码.我认为这就是它在Linux中的表现(至少是新版本).实现这一目标的另一种方法(我不知道这是否已完成,但它可能是)将使信号处理函数的返回地址为无效地址(如NULL),这将导致大多数系统中断,这将再次给予OS内核控制权.发生这种情况并不重要,

在看到我学到的另一个问题的同时

Linux内核确实将页面映射到此过程,但实际的系统调用注册信号处理程序(sigaction 调用)采用参数sa_restore参数,该参数是一个应该用作信号返回地址的地址处理程序,内核只是确保它放在那里.这个地址的代码发出了 完成的系统调用(sigreturn),内核知道信号处理程序已经完成.

信号生成

我主要假设你知道信号是如何产生的.由于发生了某些事情,操作系统可以代表进程生成它们,例如计时器到期,子进程死亡,访问它不应该访问的内存,或发出不应该访问的指令(要么不存在的指令)或者是特权的人,或许多其他事物.定时器外壳在功能上与其他外壳略有不同,因为它可能在过程未运行时发生,因此更像是随之发送的信号.kill系统调用.对于代表当前进程发送的非定时器相关信号,这些信号是在发生中断时生成的,因为当前进程出错了.此中断提供内核控制(就像系统调用一样),内核生成要传递给当前进程的信号.

  • 是.我从使用`strace`,读取代码,最终编写一个从未发送过的信号返回的程序中学到了这一点. (4认同)

Zif*_*ion 8

认为该信号设施作为中断,由OS(在硬件代替)来实现的.

当你的程序欢快遍历其执行植根于主(中位点),可发生这些中断,导致程序被分派到一个向量(处理器),运行代码那里,然后返回到它的时候被中断的位置.

这些中断(信号)可以源自各种源,例如硬件错误,例如访问错误或未对齐的地址,子进程的死亡,使用该kill命令的用户生成的信号,或来自使用kill系统调用的其他进程.消耗信号的方式是指定它们的处理程序,这些处理程序在信号发生时由OS分派.请注意,其中一些信号无法处理,导致该过程死亡.

但那些可以处理的东西可能非常有用.您可以将它们用于进程间通信,即一个进程将信号发送到另一个处理它的进程,并在处理程序中执行一些有用的操作.如果您向他们发送正确的信号,许多守护进程会执行有用的操作,例如重新读取配置文件.


Mar*_*zer 7

以上所有语句中未解决的一些问题是多核,在接收信号时在内核空间中运行,在接收信号时在内核空间中休眠,系统调用重启和信号处理器延迟.

以下是需要考虑的几个问题:

  • 如果内核知道需要将信号传递给在CPU_X上运行的进程X,但内核在CPU_Y(CPU_X!= CPU_Y)上运行时获知它,该怎么办?因此内核需要阻止进程在不同的核心上运行.
  • 如果进程在接收信号时在内核空间中运行怎么办?每次进程进行系统调用时,它都会进入内核空间,并在内核空间中进行数据结构和内存分配.所有这些黑客攻击都发生在内核空间吗?
  • 如果进程在内核空间中休眠等待其他事件怎么办?(读,写,信号,轮询,互斥是一些选择).

回答:

  • 如果进程在另一个CPU上运行,则内核通过跨CPU通信将向另一个CPU发送中断并为其发送消息.另一个CPU将在硬件中保存状态并跳转到另一个CPU上的内核,然后在另一个CPU上执行信号传递.这是尝试不在另一个CPU上执行进程的信号处理程序的一部分,这会破坏缓存局部性.
  • 如果进程在内核空间中运行,则不会中断.相反,记录此过程已收到信号.当进程退出内核空间时(在每次系统调用结束时),内核将设置trampoline来执行信号处理程序.
  • 如果进程在内核空间中运行后,在收到信号后,到达睡眠函数,则该睡眠函数(这对内核中的所有睡眠函数都是通用的)将检查进程是否有待处理的信号.如果是这样,它将不会使进程进入休眠状态,而是取消进入内核时已完成的所有操作,并在设置蹦床以执行信号处理程序然后重新启动系统时将退出到用户空间呼叫.您实际上可以控制要中断系统调用的信号以及不使用siginterrupt(2)系统调用的信号.如果你想要的系统调用重新启动一定的信号,当您注册使用的信号,您可以决定sigaction(2)SA_RESTART标志.如果发出系统调用并被信号切断并且没有自动重启,您将获得EINTR(中断的)返回值,并且您必须处理该值.您还可以查看restart_syscall(2)系统调用以获取更多详细信息.
  • 如果进程已经在内核空间中休眠/等待(实际上所有休眠/等待总是在内核空间中)它从睡眠中被唤醒,内核代码在自身之后清理并且在返回到用户空间之后跳转到信号处理程序,之后系统如果用户需要,则会自动重新启动调用(非常类似于先前对内核空间中正在运行的进程所发生情况的说明).

关于为什么所有这些都如此复杂的一些注意事项:

  • 您不能只停止在内核空间中运行的进程,因为内核开发人员分配内存,为数据结构做些事情等等.如果你只是取消控制,你将破坏内核状态并导致机器挂起.必须以受控方式通知内核代码,它必须停止运行,返回用户空间并允许用户空间处理信号.这是通过内核中所有(几乎所有)休眠函数的返回值完成的.并且内核程序员应该尊重这些返回值,并采取相应的行动.
  • 信号是异步的.这意味着它们应该尽快交付.想象一个只有一个线程的进程,进入睡眠状态一小时,并发出一个信号.睡眠在内核中.所以你除了内核代码唤醒,清理后,返回用户空间并执行信号处理程序,可能在信号处理程序完成后重新启动系统调用.您当然不希望该过程仅在一小时后执行信号处理程序.然后你期望睡眠恢复.用户空间和内核人员都很难做到这一点.
  • 所有信号都像中断处理程序,但用户空间.这是一个很好的比喻,但并不完美.虽然中断处理程序是由硬件生成的,但是一些信号处理程序来自硬件,但大多数只是软件(关于子进程死亡的信号,来自使用kill(2)系统调用的另一进程的信号等).

那么信号处理的延迟是多少?

  • 如果当某个其他进程正在运行时发出信号,则由内核调度程序决定是否让其他进程完成其时间片,然后才传递信号.如果您使用的是普通的Linux/Unix系统,这意味着在获得信号之前可能会延迟一个或多个时间片(这意味着毫秒相当于永恒).
  • 当您收到信号时,如果您的进程是高优先级或其他进程已经获得时间片,您将获得非常快的信号.如果你在用户空间中运行,你将"立即"获得它,如果你在内核空间运行,你将很快到达睡眠函数或从内核返回,在这种情况下,当你返回到用户空间时,你的信号处理程序将被调用.这通常是很短的时间,因为在内核中花费的时间不多.
  • 如果你在内核中睡觉,没有其他东西超过你的优先级或需要运行,处理你的系统调用的内核线程被唤醒,在它进入内核的过程中所做的所有事情之后清理,返回到用户空间并执行您的信号.这不需要太长时间(在这里谈论微秒).
  • 如果您运行的是Linux的实时版本并且您的进程具有最高的实时优先级,那么您将在触发后立即获得信号.谈论50微秒甚至更好(取决于我不能进入的其他因素).