【问题标题】:Why does this alarm() syscall does not interrupt read()?为什么这个alarm() 系统调用不会中断read()?
【发布时间】:2021-04-20 20:12:16
【问题描述】:

我发现了一个问题,它要求解释以下程序的行为:

#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void sig_alrm(int n) {
    write(2, "ALARM!\n", 7);
    return;
}

int main() {
    int fd[2], n;
    char message[6], *s;

    s = "HELLO\n";
    signal(SIGALRM, sig_alrm);
    pipe(fd);
    
    if (fork() == 0) {
        close(fd[1]);
        alarm(3);
        while ((n = read(fd[0], message, 6)) > 0);
        alarm(0);
        exit(0);
    }
    
    close(1);
    dup(fd[1]);
    close(fd[0]);
    close(fd[1]);
    
    while (1)
        write(1, s, 6);
}

它基本上是一个带有共享管道的父进程,它通过管道不断地向子进程发送 HELLO\n。孩子在三秒内设置了一个SIGALRM,它将被 sig_alrm 函数捕获,然后继续从管道中无限期地读取。

如果我理解正确,SIGALRM 应该中断read() 系统调用,导致它在到达时出错,这反过来会导致子进程以默认行为的即时警报退出,而父进程结束也是因为SIGPIPE

问题是我试图运行代码,在SIGALRM 到达子进程后,两个进程继续愉快地从管道中读写。

我对信号行为有什么误解吗?

【问题讨论】:

  • 可能它没有在读取中休眠,因为写入速度更快,并且总有一些东西要读取。尝试减慢写入速度。
  • @dratenik 谢谢,但没有运气。我试着每隔一秒或几秒写一次,同样的事情发生了。
  • 我敢打赌你的操作系统的signal() 实现会安装一个可重启的处理程序。请改用sigaction()

标签: c signals system-calls


【解决方案1】:

signal 的行为因平台而异,您应该改用它的后继 sigaction,即 standardized in POSIX-1.1988

在您的平台上并根据您的构建说明,signal() 以“可重新启动”方式安装用户处理程序,这意味着可中断的系统调用将简单地重新启动,而不是因 EINTR 而失败。您的 read 被处理程序中断,但随后恢复。一些平台和/或构建语义不这样做。

sigaction 通过提供一个标志 SA_RESTART 来解决这种歧义,该标志控制中断的系统调用实际上是否重新启动。它也将其他历史上不同的行为标准化。

对于它的价值,当我在旧的 Linux 系统上 gcc 编译您的代码而不指定任何功能宏时,strace 显示 signal 实际上是按照(实时)sigaction 使用 SA_RESTART 调用,这解释了您看到的行为:

$ strace -fe trace=\!write,read ./so65742182
....
munmap(0x7f8ddffaf000, 70990)           = 0
rt_sigaction(SIGALRM, {0x013370, [ALRM], SA_RESTORER|SA_RESTART, ...
#                                                    ^^^^^^^^^^
pipe([3, 4])
....

【讨论】:

  • sigaction 通过提供一个标志 SA_RESTART 来解决这种歧义,该标志控制实际上是否重新启动中断的系统调用。重新启动。通常,只有实现指定的系统调用才会重新启动。在 Linux 上,这些列在 signal.7 man page
  • @AndrewHenle, yup.
  • 我明白了,这就解释了,谢谢!确实 sigaction 更好,应该使用,但我们正在研究两者,以防我们发现遗留代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-05
  • 1970-01-01
  • 2013-03-09
相关资源
最近更新 更多