假设我们有一些非常耗时的系统调用,当前正在当前用户空间进程的上下文中以内核模式执行,在执行此类系统调用期间,系统调用SIGKILL
被发送到用户进程。在这种情况下会发生什么 - 进程会立即被终止还是会等到系统调用结束?如果进程立即被终止,则同样适用于用户空间进程在执行中断处理程序时被终止的情况(因为中断处理程序可以在任意用户空间进程的上下文中执行),因为这听起来很奇怪- 非常重要的中断处理程序工作可能会被中止。
答案1
一些系统调用可以被中断(参见eg siginterrupt(3)
)。否则,仅当调用返回用户态时才会传递信号。
答案2
一个非常耗时的系统调用的例子是pause()
。它永远不会完成,除非进程收到信号。
read()
可以是可中断的(更好的术语是“可发出信号”),例如从串行线路读取时,或者不可中断,例如从块设备读取时。
为什么?原始的 UNIX 逻辑如下:我们不知道串行线上是否有任何输入可用。因此,必须有一种方法即使没有输入任何内容也可以结束系统调用。另一方面,从块设备读取总是会完成,但当磁盘出现故障时可能会出现错误。
UNIX 已经发展了很多。如今,不可中断read()
是可能的,但永远不会完成。示例:当 NFS 服务器关闭且挂载为 时,从 NFS 挂载的文件系统读取hard
。
答案3
真正的中断处理程序位于内核中,并且与用户进程没有真正关联。信号处理程序是用户进程最接近中断处理程序的东西。有些信号在信号处理程序期间被阻止,但 SIGKILL 不是其中之一,因此它会立即退出,就像任何其他用户代码一样。
答案4
仅当执行返回到用户模式(即退出内核模式)并且您的进程计划运行时才能传递信号(通常是恢复进程上下文的特权汇编指令,并且可能会或可能不会设置用户模式,具体取决于无论您的进程是否在系统调用中) - 这可能是当系统调用返回时,或者当中断处理程序返回时。
为了回答您的具体问题,它将等到系统调用结束(可能会或可能不会被中断),并且如果中断处理程序返回(完成所有工作后)到您的进程(即它返回到内核模式)不是用户模式),直到您的进程随后从系统调用返回(即返回到用户模式)后,信号才会被传递。
如果系统调用被中断(返回 EINTR)并且是“可重新启动的”,那么在信号处理程序运行后,支持系统调用接口的用户代码可能会选择自动重新进入系统调用,而不返回到您的用户代码。
另请检查这出去 ...
最后,这里的含义是,如果进程从未从系统调用返回(导致“不可杀死”进程),则信号可能永远不会传递到进程,包括 SIGKILL。