C 如何知道Linux系统调用是否可重启?
根据man的说法,如果在安装信号处理程序时使用C 如何知道Linux系统调用是否可重启?,c,linux,posix,system-calls,C,Linux,Posix,System Calls,根据man的说法,如果在安装信号处理程序时使用sau RESTART标志,内核可以透明地重新启动一些系统调用: 如果对以下接口之一的阻塞调用被中断 通过信号处理程序,调用将自动重新启动 信号后 如果使用了SA_重新启动标志,则处理程序返回;否则调用将失败,错误为EINTR: 然后它提到了一些可以(也不能)重新启动的系统调用,但在这两个地方都没有提到close(),我怎么知道close()或任何其他函数是否可以重新启动?POSIX是否指定了它,或者它是Linux特有的行为?在哪里可以找到更多信息?
sau RESTART
标志,内核可以透明地重新启动一些系统调用:
如果对以下接口之一的阻塞调用被中断
通过信号处理程序,调用将自动重新启动
信号后
如果使用了SA_重新启动标志,则处理程序返回;否则调用将失败,错误为EINTR:
然后它提到了一些可以(也不能)重新启动的系统调用,但在这两个地方都没有提到close()
,我怎么知道close()
或任何其他函数是否可以重新启动?POSIX
是否指定了它,或者它是Linux特有的行为?在哪里可以找到更多信息?根据,SA_RESTART
标志适用于所有可中断功能(所有使用EINTR
记录为失败的功能):
萨乌重启
此标志影响可中断函数的行为;也就是说,在errno设置为[EINTR]的情况下指定为失败的。如果设置了,且指定为可中断的功能被该信号中断,则该功能应重新启动,且不得因[EINTR]故障,除非另有规定。如果重新启动使用超时的可中断函数,则重新启动后的超时持续时间将设置为不超过原始超时值的未指定值。如果未设置该标志,被该信号中断的可中断功能将失败,errno设置为[EINTR]
也就是说,未重新启动的函数列表是特定于Linux的(可能会被视为bug)。
close
是一种非常特殊的情况。它不仅不能在Linux上重启;在Linux上,当close
返回EINTR
时,它实际上已经成功了,在单线程进程中再次调用close
将因EBADF
而失败,并在多线程进程中导致极其危险的文件描述符争用
从发布的POSIX 2008开始,这种行为是允许的:
如果close()被要捕获的信号中断,它将返回-1,errno设置为[EINTR],fildes的状态未指定
该问题已向奥斯汀集团(as)提出,并已解决,以修改规范,使返回EINTR
表示文件描述符仍然打开;这与当前的Linux行为相反。如果在处理信号时文件描述符已经关闭,close
功能现在需要返回EINPROGRESS
,而不是EINTR
。这可以在Linux上的用户空间中修复,并且有一个开放的解决方案,但是在撰写本文时,它还没有收到任何响应
此问题对POSIX线程取消也有严重影响,其副作用在使用
EINTR
返回时的副作用中指定。Austin Group tracker上有一个相关问题。请注意“除非另有规定”。情况就是这样,因此它是“实现细节”而不是“bug”(这并没有让它变得不那么烦人,尤其是因为在Linux中,文档通常是相当模糊的)。我添加了一个新的答案,其中有一些关于close
特例的更多细节,这非常难看。注意:这种行为不是Linux特有的<不能在linux、Solaris、Darwin(MacOS)和BSD上重试代码>关闭()。HP-UX是唯一要求在EINTR上重试关闭的(?)系统。任何平台改变其行为的可能性都为零。希望他们停止返回EINTR
并开始返回EINPROGRESS
或success;POSIX中的修复程序将允许这两种情况之一。我认为成功可能是最好的,因为不打破现有的应用程序,除了考虑代码之外的任何值。EINT/<代码>一个致命的错误。当关闭()被信号中断时,许多实现不遵守POSIX:Linux关闭()返回0并且不设置ErrNO。FreeBSD close()返回-1并将errno设置为EBADF(这可能与其他错误代码重合)。我不知道有哪个UNIX在中断close()结果时将errno设置为EINTR。@HeikoBloch:这不完全准确;请参阅我的问题,它解决了Linux上出现的反直觉方式EINTR
close
。如果FreeBSD的行为符合您的预期,那么系统调用可能会在fd关闭后重新启动,这可能是多线程应用程序中的一个严重错误(双重关闭竞争)。4年后回顾这一点并将其传递给FreeBSD人员,这里确实存在实际的错误!看见