c语言 - 如何知道 Linux 系统调用是否可重新启动?



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

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

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

close

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

从已发布的 POSIX 2008 开始,允许以下行为:

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

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

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

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

SA_RESTART

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

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

最新更新