Fix EINTR handling for close
This commit is contained in:
17
style.md
17
style.md
@@ -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`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user