如果在安装信号处理程序时使用SA_RESTART
标志,内核可以透明地重启一些系统调用,根据人signal(7):
如果对以下某个接口的阻止呼叫被中断 通过信号处理程序,然后调用将自动重启 信号之后 如果使用了SA_RESTART标志,则处理程序返回;否则呼叫将失败并显示错误EINTR:
然后它提到了一些可以(并且不能)重新启动的系统调用,但是在任何一个地方都没有提到close()
,我怎么知道close()
或任何其他函数是否可以重启或不 ?是POSIX
指定它还是特定于Linux的行为?我在哪里可以找到更多信息?
答案 0 :(得分:10)
根据POSIX.1-2008,SA_RESTART
标志适用于所有可中断函数(所有记录为EINTR
失败的函数):
SA_RESTART
此标志影响可中断功能的行为;也就是说,指定为errno设置为[EINTR]的失败。如果设置,并且该信号中断了指定为可中断的功能,则该功能应重新启动,除非另有说明,否则不应使用[EINTR]失败。如果重新启动使用超时的可中断功能,则重新启动后超时的持续时间将设置为未指定的值,该值不会超过原始超时值。如果未设置该标志,则该信号中断的可中断功能将失败,并将errno设置为[EINTR]。
也就是说,未重新启动的函数列表是特定于Linux的(可能算作错误)。
答案 1 :(得分:10)
close
是一个相当特殊的案例。它不仅不能在Linux上重启;当close
在Linux上返回EINTR
时,它实际上已经成功,并且在单线程进程中对close
的另一次调用将失败并导致EBADF
并导致极其危险的文件-descriptor在多线程进程中比赛。
截至发布的POSIX 2008,允许此行为:
如果close()被要捕获的信号中断,它将返回-1,并且errno设置为[EINTR]并且未指定fildes的状态。
此问题是由Austin Group(作为Issue #529)提出的,并且决定修改规范,以便使用EINTR
返回意味着文件描述符仍处于打开状态;这与当前的Linux行为相反。如果在处理信号时文件描述符已经关闭,则close
函数现在需要使用EINPROGRESS
而不是EINTR
返回。这可以在Linux上的用户空间中修复,并且有一个开放的glibc bug report, #14627,但在撰写本文时它没有收到任何响应。
此问题对POSIX线程取消也有严重影响,其副作用是根据EINTR
返回时的副作用指定的。奥斯汀组跟踪器Issue #614上存在相关问题。