【发布时间】:2019-12-13 08:05:32
【问题描述】:
我编写了一个非常小的测试程序来检查errno 的值,当read() 被处理信号中断时。
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
void handler(int sig){
printf("signal: %d\n", sig);
}
int main(){
signal(SIGINT, handler);
char arr[10];
read(0, arr, 10);
perror("emsg");
return 0;
}
根据我所知道的一切以及read(2) 上的手册页,
EINTR The call was interrupted by a signal before any data was read;
see signal(7).
read 应该返回-1 并将errno 设置为EINTR。但是,程序的输出表明它在从信号处理程序返回后再次阻塞 read。
这对我来说完全没有意义,我无法弄清楚出了什么问题。
这是我得到的输出:
$ ./a.out
^Csignal: 2
^Csignal: 2
^Csignal: 2
^Csignal: 2
hello
emsg: Success
我的问题与this one 不同。后者没有谈论系统调用被中断时会发生什么。该讨论的关键是应该使用哪个。
另外,同一线程上的this answer 表示signal() 在下面调用sigaction(),那么为什么两者在系统调用情况下的行为不同?
【问题讨论】:
-
使用
signal设置的信号在不同的类 Unix 系统之间可能有不同的行为。因此,您应该始终使用sigaction来指定所需的行为。 -
在一个稍微相关的说明中,
errno的值几乎适用于所有系统调用未指定,除非之前的函数确实失败了。你总是应该在检查errno(perror做的)之前检查失败。 -
您也不能从信号处理程序中安全地调用
printf()。 Footnote 188 of the C11 standard 甚至声明“因此,信号处理程序通常不能调用标准库函数。” POSIX allows you to safely call async-signal-safe functions。 Linux 上的异步信号安全函数列表可以在thesignal-safetyman page 上找到。请注意,printf()不在这两个列表中。 -
@AndrewHenle 正如我所说,这只是一个示例程序,旨在演示
perror()的使用。 -
好的,根据this answer,
signal在调用sigaction()之前将sa_flags设置为SA_RESTART。从而重启read()。投票以重复结束。
标签: c signals system-calls errno