12

SA_RESTART根据 man signal(7) ,如果在安装信号处理程序时使用了标志,则内核可以透明地重新启动一些系统调用:

如果对以下接口之一的阻塞调用被信号处理程序中断,则如果使用了 SA_RESTART 标志,则在信号处理程序返回后将自动重新启动调用;否则调用将失败并出现错误 EINTR:

然后它提到了一些可以(也不能)重新启动的系统调用,但close()在任何一个地方都没有提到,我怎么知道close()或任何其他功能是否可重新启动?确实POSIX指定了它还是特定于 Linux 的行为?我在哪里可以找到更多信息?

4

2 回答 2

14

close是一个比较特殊的情况。它不仅不能在 Linux 上重新启动;当在 Linux 上close返回时EINTR,它实际上已经成功,并且在单线程进程中再次调用close将失败,并EBADF在多线程进程中导致极其危险的文件描述符竞争。

从发布的 POSIX 2008 开始,允许这种行为:

如果 close() 被要捕获的信号中断,它应返回 -1 并将 errno 设置为 [EINTR] 并且 fildes 的状态未指定。

这个问题是由 Austin Group 提出的(作为Issue #529),并已解决修改规范,以便返回 withEINTR表示文件描述符仍然打开;这与当前的 Linux 行为相反。如果在处理信号时文件描述符已经关闭,则该close函数现在需要返回EINPROGRESS而不是EINTR. 这可以在 Linux 的用户空间中修复,并且有一个开放的glibc 错误报告,#14627,但截至撰写本文时,它还没有收到任何回复。

这个问题对 POSIX 线程取消也有严重影响,其副作用是根据返回时的副作用来指定的EINTR。Austin Group 跟踪器上有一个相关问题,问题 #614

于 2013-01-21T02:52:45.547 回答
10

根据POSIX.1-2008,该SA_RESTART标志适用于所有可中断函数(所有记录失败的函数EINTR):

SA_RESTART

该标志影响可中断函数的行为;也就是说,那些指定为失败且 errno 设置为 [EINTR] 的。如果设置,并且指定为可中断的功能被此信号中断,则该功能应重新启动,并且除非另有说明,否则不应因 [EINTR] 而失败。如果重新启动使用超时的可中断函数,则重新启动后的超时持续时间将设置为不超过原始超时值的未指定值。如果未设置该标志,则被此信号中断的可中断功能将失败,并将 errno 设置为 [EINTR]。

也就是说,未重新启动的函数列表是特定于 Linux 的(并且可能算作一个错误)。

于 2012-11-13T08:09:42.743 回答