重新启动系统调用安全吗?

重新启动系统调用安全吗?

我正在阅读一本教科书,其中描述了如何在中断时处理系统调用:

系统调用可以被中断。 read、wait 和accept 等可能会长时间阻塞进程的系统调用称为慢速系统调用。在某些旧版本的 Unix 上,当处理程序捕获信号时被中断的慢速系统调用在信号处理程序返回时不会恢复,而是立即返回给用户,并带有错误条件并将 errno 设置为 EINTR。在这些系统上,程序员必须包含手动重新启动中断的系统调用的代码。

但是重新启动系统调用总是安全的吗?假设系统调用维护一个内部数据结构,需要在系统调用完成之前重置该结构。因此,我们启动系统调用,它是长时间运行且阻塞的,当信号中断它时,系统调用只是重新启动,因此第一个系统调用没有机会重置数据结构。

由于前一次调用中的数据结构没有被重置,因此在第二次系统调用发生后,数据结构不一致,这可能会污染操作。

那么重启系统调用安全吗?

答案1

在 Linux 上,是的,重新启动返回的系统调用总是安全的EINTR:返回值意味着系统调用在取得任何有用的进展之前被中断,应该重新启动。系统调用的实现考虑到了这一点。

对于因系统调用中断而导致系统状态发生变化的情况,处理方式有所不同;例如,一个read在中断之前检索到一些数据的调用将返回该数据,指示成功,并且write在中断之前传输了一些数据的调用将返回其写入的数据量,也表明成功。 (顺便说一句,这是必须检查这些函数的返回值而不是假设成功的调用已完成所有请求的工作的原因之一。)

SA_RESTART通过设置适当信号的标志,许多系统调用可以自动重新启动。 GNU C 库提供了一个宏可以帮助编写重启代码,TEMP_FAILURE_RETRYunistd.h(如果_GNU_SOURCE已定义则定义)。

EINTR请注意,在 Linux 上,即使没有信号处理程序,系统调用也可以返回。

的“信号处理程序中断系统调用和库函数”部分man 7 signal包含所有详细信息,包括各种场景中受影响的系统调用的列表。

相关内容