nat*_*ose 40
下面的解释是不完全一样,和这个作品不同的系统(甚至在不同的硬件相同的操作系统的某些部分)之间的区别的几个方面,但我认为这是一般好 足够让你满足你的好奇心足以使用它们.大多数人开始在编程中使用信号,甚至没有这种理解水平,但在我习惯使用它们之前,我想了解它们.
OS内核有一个称为进程控制块的数据结构,用于运行的每个进程,其中包含有关该进程的数据.这可以通过进程ID(PID)查找,并包括信号动作和未决信号的表.
当信号发送到进程时,OS内核将查找该进程的进程控制块,并检查信号操作表以找到正在发送的特定信号的操作.如果信号动作值是SIG_IGN
那么内核忘记了新信号.如果信号动作值是,SIG_DFL
则内核在另一个表中查找该信号的默认信号处理动作并执行该动作.如果值是其他任何值,则假定该过程中的函数地址是信号被发送到的应该被调用的函数地址.为价值观SIG_IGN
和SIG_DFL
是转换为函数指针的数字,其值不是进程地址空间中的有效地址(例如0和1,它们都在第0页,从不映射到进程).
如果进程注册了一个信号处理函数(信号动作值既不是SIG_IGN也不是SIG_DFL),则在该信号表中挂起信号表中的一个条目,并且该进程被标记为准备好运行(它可能一直在等待某些东西,比如可用于呼叫read
,等待信号或其他一些东西的数据.
现在,下一次运行该进程时,OS内核将首先向堆栈添加一些数据,并更改该进程的指令指针,使其看起来几乎就像进程本身刚刚调用了信号处理程序一样.这不是完全正确的,实际上与实际发生的事情有很大不同,我会稍微谈谈它.
信号处理函数可以执行它所做的任何事情(它是代表它调用的进程的一部分,因此它是在知道该程序应该对该信号执行什么的情况下编写的).当信号处理程序返回时,进程的常规代码再次开始执行.(再次,不准确,但下一步更多)
好的,上面的内容应该让您非常清楚如何将信号传递给流程.我觉得这个很 不错 的想法,才能掌握充分的想法,其中包括一些更复杂的东西需要的版本.
OS内核通常需要知道信号处理程序何时返回.这是因为信号处理程序采用参数(可能需要堆栈空间),您可以阻止在执行信号处理程序期间两次传递相同的信号,和/或在传递信号后重新启动系统调用.为了实现这一点,比堆栈和指令指针更改更多.
有什么要发生的是,内核需要做的过程中告诉它,它已经完成执行信号处理函数.这可以通过将一部分RAM映射到进程的地址空间来完成,该地址空间包含进行此系统调用的代码,并使信号处理函数的返回地址(此函数开始运行时堆栈的最高值)为地址这段代码.我认为这就是它在Linux中的表现(至少是新版本).实现这一目标的另一种方法(我不知道这是否已完成,但它可能是)将使信号处理函数的返回地址为无效地址(如NULL),这将导致大多数系统中断,这将再次给予OS内核控制权.发生这种情况并不重要,
Linux内核确实将页面映射到此过程,但实际的系统调用注册信号处理程序(sigaction 调用)采用参数sa_restore参数,该参数是一个应该用作信号返回地址的地址处理程序,内核只是确保它放在那里.这个地址的代码发出了我 完成的系统调用(sigreturn
),内核知道信号处理程序已经完成.
我主要假设你知道信号是如何产生的.由于发生了某些事情,操作系统可以代表进程生成它们,例如计时器到期,子进程死亡,访问它不应该访问的内存,或发出不应该访问的指令(要么不存在的指令)或者是特权的人,或许多其他事物.定时器外壳在功能上与其他外壳略有不同,因为它可能在过程未运行时发生,因此更像是随之发送的信号.kill
系统调用.对于代表当前进程发送的非定时器相关信号,这些信号是在发生中断时生成的,因为当前进程出错了.此中断提供内核控制(就像系统调用一样),内核生成要传递给当前进程的信号.
认为该信号设施作为中断,由OS(在硬件代替)来实现的.
当你的程序欢快遍历其执行植根于主(中位点),可发生这些中断,导致程序被分派到一个向量(处理器),运行代码那里,然后返回到它的时候被中断的位置.
这些中断(信号)可以源自各种源,例如硬件错误,例如访问错误或未对齐的地址,子进程的死亡,使用该kill
命令的用户生成的信号,或来自使用kill
系统调用的其他进程.消耗信号的方式是指定它们的处理程序,这些处理程序在信号发生时由OS分派.请注意,其中一些信号无法处理,导致该过程死亡.
但那些可以处理的东西可能非常有用.您可以将它们用于进程间通信,即一个进程将信号发送到另一个处理它的进程,并在处理程序中执行一些有用的操作.如果您向他们发送正确的信号,许多守护进程会执行有用的操作,例如重新读取配置文件.
以上所有语句中未解决的一些问题是多核,在接收信号时在内核空间中运行,在接收信号时在内核空间中休眠,系统调用重启和信号处理器延迟.
以下是需要考虑的几个问题:
回答:
siginterrupt(2)
系统调用的信号.如果你想要的系统调用重新启动一定的信号,当您注册使用的信号,您可以决定sigaction(2)
与SA_RESTART
标志.如果发出系统调用并被信号切断并且没有自动重启,您将获得EINTR
(中断的)返回值,并且您必须处理该值.您还可以查看restart_syscall(2)
系统调用以获取更多详细信息.关于为什么所有这些都如此复杂的一些注意事项:
kill(2)
系统调用的另一进程的信号等).那么信号处理的延迟是多少?