捕获信号时系统调用中断

时间:2011-07-11 05:28:00

标签: linux-kernel

通过阅读'read()'和'write()'调用的手册页,看来这些调用会被信号中断,无论它们是否必须阻塞。

特别假设

  • 进程为某些信号建立处理程序。
  • 打开设备(比如终端....),设置'O_NONBLOCK'(即以阻塞模式运行)
  • 然后进程执行'read()'系统调用以从设备读取,结果在内核空间中执行内核控制路径。
  • 当进程在内核空间中执行'read()'时,先前安装了处理程序的信号被传递到该进程并调用其信号处理程序。

阅读手册页和SUSv3'系统界面卷(XSH)'中的相应章节,我发现:

我。如果read()在读取任何数据之前被信号中断(即由于没有数据可用而必须阻塞),则返回-1并将'errno'设置为[EINTR]。

II。如果read()在成功读取某些数据后被信号中断(即可以立即开始服务请求),则返回读取的字节数

问题A):

我是否正确地假设在任何一种情况下(阻止/无阻塞)信号的传递和处理对'read()'不完全透明?

案例i。似乎可以理解,因为阻塞'read()'通常会将进程置于'TASK_INTERRUPTIBLE'状态,这样当传递信号时,内核会将进程置于'TASK_RUNNING'状态。

然而,当'read()'不需要阻塞(情况ii。)并且正在处理内核空间中的请求时,我会认为信号的到达及其处理将是透明的到达并正确处理HW中断。特别是我假设在传递信号时,该过程将暂时置于USER-MODE中以执行其信号处理程序,最终它将返回完成处理被打断的'read()'(在内核空间中) )'read()'运行完成,之后进程返回到调用'read()'(在用户空间)之后的点,结果读取所有可用字节

但是ii。似乎暗示'read()'被中断,因为数据立即可用但它返回返回'一些'数据(而不是全部)。

这让我想到了我的第二个(也是最后一个)问题

问题B):

如果我在A)下的假设是正确的,为什么'read()'会被中断,即使它不需要阻塞因为有数据可以立即满足请求?   换句话说,为什么在执行信号处理程序后'read()'没有恢复,最终导致返回所有可用数据(毕竟是可用的)?

2 个答案:

答案 0 :(得分:1)

当一个信号被发送到一个进程时,所有内核都会在进程的任务结构中设置一个标志来指示该信号是未决的,如果它处于可中断的睡眠状态,则将其唤醒(TASK_INTERRUPTIBLE )。

这意味着从阻塞系统调用内核代码的角度来看,它会看到自己从休眠状态唤醒,就像设备已发出更多数据准备就绪一样。系统调用代码负责检查等待信号并返回用户空间(以便可以处理信号)。

(注意,另一个含义是,如果在进程在用户空间时引发异步信号,必须由在另一个CPU上运行的进程引发,则通常在下一个计时器滴答或系统调用之前不会处理该信号)

答案 1 :(得分:0)

设备驱动程序可能需要在处理读取之前获取互斥锁 - 如果互斥锁上的等待被信号中断,则驱动程序可能会在阻塞和非阻塞模式下返回EINTR,因为它还不知道是否有可用的数据。它显然无法返回任何数据,也不应该返回EAGAIN,这会导致调用者错误地暗示没有可用的数据,例如 - 调用者可能会睡一段时间。