什么是系统调用中断?

Ric*_*ick 7 signals system-calls interrupt

我正在阅读APUE中断系统调用一章让我感到困惑。

我想根据书中写下我的理解,请指正。

  1. 早期 UNIX 系统的一个特点是,如果进程在“慢”系统调用中被阻塞时捕获到信号,则系统调用将被中断。系统调用返回错误并 errno设置为EINTR。这是在假设发生信号并且进程捕获它之后完成的,很有可能发生了一些应该唤醒被阻塞的系统调用的事情。

    所以说早期的UNIX 系统有一个特性:如果我的程序使用系统调用,它会被中断/停止,如果程序在任何时候捕捉到信号。(默认处理程序也算作捕获吗?)

    例如,如果我有一个read系统调用,它读取 10GB 数据,当它正在读取时,我发送任何一个信号(例如kill -SIGUSR1 pid),然后read将失败并返回。


  1. 为了防止应用程序不得不处理中断的系统调用,4.2BSD 引入了某些中断系统调用的自动重启。被自动重新启动的系统调用ioctlreadreadvwritewritevwait,和waitpid。正如我们所提到的,这些功能中的前五个功能只有在它们在慢速设备上运行时才会被信号中断;wait并且waitpid 在捕获到信号时总是被中断。由于这会导致一些应用程序出现问题,如果操作被中断,则不希望操作重新启动,4.3BSD 允许进程在每个信号的基础上禁用此功能。

所以在引入自动重启之前,我不得不自己处理中断的系统调用。我需要编写如下代码:

中断系统调用的问题在于我们现在必须显式地处理错误返回。典型的代码序列(假设读取操作并假设我们想要重新启动读取,即使它被中断)将是:

again:
    if ((n = read(fd, buf, BUFFSIZE)) < 0) {
        if (errno == EINTR)
        goto again; /* just an interrupted system call */
        /* handle other errors */
}
Run Code Online (Sandbox Code Playgroud)

但是现在我不用写这种代码了,因为有自动重启机制。


所以如果我的理解都是正确的,我现在应该关心中断的系统调用什么/为什么..?似乎系统/操作系统会自动处理它。

mtk*_*mtk 9

信号处理程序对系统调用的中断仅发生在各种阻塞系统调用的情况下,并且在系统调用被程序员明确建立的信号处理程序中断时发生。

此外,在阻塞系统调用被信号处理程序中断的情况下,自动重新启动系统调用是一个可选功能。您可以通过SA_RESTART在建立信号处理程序时指定标志来选择自动重新启动系统调用。如(例如)Linux signal(7)手册页所述:

   If  a  signal  handler  is  invoked while a system call or library
   function call is blocked, then either:

   * the call is automatically restarted  after  the  signal  handler
     returns; or

   * the call fails with the error EINTR.

   Which  of  these two behaviors occurs depends on the interface and
   whether or not  the  signal  handler  was  established  using  the
   SA_RESTART  flag (see sigaction(2)). 
Run Code Online (Sandbox Code Playgroud)

正如上面引用的最后一句话所暗示的那样,即使您选择使用此功能,它也不适用于所有系统调用,并且它适用的系统调用集因 UNIX 实现而异。Linuxsignal(7)手册页指出了许多在使用该SA_RESTART标志时会自动重新启动的系统调用,而且还继续指出了各种从未重新启动的系统调用,即使您在建立处理程序时指定了该标志,包括:

   * "Input" socket interfaces, when a timeout (SO_RCVTIMEO) has been
     set  on  the  socket  using  setsockopt(2):  accept(2), recv(2),
     recvfrom(2), recvmmsg(2) (also with  a  non-NULL  timeout  argu?
     ment), and recvmsg(2).

   * "Output"  socket  interfaces,  when  a timeout (SO_RCVTIMEO) has
     been set on the socket using setsockopt(2): connect(2), send(2),
     sendto(2), and sendmsg(2).

   * File   descriptor   multiplexing   interfaces:    epoll_wait(2),
     epoll_pwait(2), poll(2), ppoll(2), select(2), and pselect(2).

   * System  V  IPC  interfaces:  msgrcv(2), msgsnd(2), semop(2), and
     semtimedop(2).
Run Code Online (Sandbox Code Playgroud)

对于这些系统调用,使用 APUE 中描述的形式的循环手动重新启动是必不可少的,例如:

while ((ret = some_syscall(...)) == -1 && errno == EINTR)
    continue;
if (ret == -1)
    /* Handle error */ ;
Run Code Online (Sandbox Code Playgroud)