Fix EINTR handling for close

This commit is contained in:
2025-08-23 20:14:24 -04:00
parent 7db0e331e4
commit 18a1b30d9f
6 changed files with 86 additions and 78 deletions

View File

@@ -331,7 +331,7 @@ static_assert(std::is_trivially_destructible_v<T>, "Arena requires trivially des
### System Call Error Handling
When a system call is interrupted by a signal (`EINTR`), it is usually necessary to retry the call. This is especially true for "slow" system calls that can block for a long time, such as `read`, `write`, `accept`, `connect`, `close`, `sem_wait`, and `epoll_wait`.
When a system call is interrupted by a signal (`EINTR`), it is usually necessary to retry the call. This is especially true for "slow" system calls that can block for a long time, such as `read`, `write`, `accept`, `connect`, `sem_wait`, and `epoll_wait`.
**Rule:** Always wrap potentially interruptible system calls in a `do-while` loop that checks for `EINTR`.
@@ -350,6 +350,20 @@ if (fd == -1) {
}
```
**Special case - close():**
The `close()` system call is a special case on Linux. According to `man 2 close`, when `close()` returns `EINTR` on Linux, the file descriptor is still guaranteed to be closed. Therefore, `close()` should **never** be retried.
```cpp
// Correct: Do not retry close() on EINTR
int e = close(fd);
if (e == -1 && errno != EINTR) {
// Handle non-EINTR errors only
perror("close");
std::abort();
}
// Note: fd is guaranteed closed even on EINTR
```
**Non-interruptible calls:**
@@ -361,6 +375,7 @@ Most system calls are not interruptible in practice. For these, it is not necess
* `pipe`
* `setsockopt`
* `epoll_create1`
* `close` (special case: guaranteed closed even on EINTR on Linux)
When in doubt, consult the `man` page for the specific system call to see if it can return `EINTR`.