【问题标题】:Interruption of system calls when a signal is caught捕获信号时中断系统调用
【发布时间】:2011-07-14 13:05:21
【问题描述】:

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

特别是假设

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

阅读手册页和 SUSv3 'System Interfaces volume (XSH)' 中的相应部分会发现:

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

二。如果 read() 在成功读取一些数据后被信号中断(即可以立即开始为请求提供服务),它会返回读取的字节数

问题 A):

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

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

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

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

这就引出了我的第二个(也是最后一个)问题

问题 B):

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

【问题讨论】:

    标签: linux-kernel


    【解决方案1】:

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

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

    (请注意,这的另一个含义是,如果在进程处于用户空间时发出异步信号,必然是由运行在另一个 CPU 上的进程发出的,该信号通常不会被处理,直到下一个计时器滴答声或系统调用) .

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-10
        • 2012-11-01
        • 1970-01-01
        • 2014-11-06
        相关资源
        最近更新 更多