Skip to content

Commit 8ae493b

Browse files
panjf2000gopherbot
authored andcommitted
[release-branch.go1.21] internal/poll: add SPLICE_F_NONBLOCK flag for splice to avoid inconsistency with O_NONBLOCK
Fixes #63801 Updates #59041 Updates #63795 Details: #59041 (comment) Change-Id: Id3fc1df6d86b7c4cc383d09f9465fa8f4cc2a559 Reviewed-on: https://go-review.googlesource.com/c/go/+/536015 Reviewed-by: Bryan Mills <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> (cherry picked from commit 40cdf69) Reviewed-on: https://go-review.googlesource.com/c/go/+/538117 Auto-Submit: Heschi Kreinick <[email protected]> Reviewed-by: Mauri de Souza Meneguzzo <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]>
1 parent b9f245b commit 8ae493b

File tree

1 file changed

+19
-2
lines changed

1 file changed

+19
-2
lines changed

src/internal/poll/splice_linux.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ import (
1313
)
1414

1515
const (
16+
// spliceNonblock doesn't make the splice itself necessarily nonblocking
17+
// (because the actual file descriptors that are spliced from/to may block
18+
// unless they have the O_NONBLOCK flag set), but it makes the splice pipe
19+
// operations nonblocking.
20+
spliceNonblock = 0x2
21+
1622
// maxSpliceSize is the maximum amount of data Splice asks
1723
// the kernel to move in a single call to splice(2).
1824
// We use 1MB as Splice writes data through a pipe, and 1MB is the default maximum pipe buffer size,
@@ -89,7 +95,11 @@ func spliceDrain(pipefd int, sock *FD, max int) (int, error) {
8995
return 0, err
9096
}
9197
for {
92-
n, err := splice(pipefd, sock.Sysfd, max, 0)
98+
// In theory calling splice(2) with SPLICE_F_NONBLOCK could end up an infinite loop here,
99+
// because it could return EAGAIN ceaselessly when the write end of the pipe is full,
100+
// but this shouldn't be a concern here, since the pipe buffer must be sufficient for
101+
// this data transmission on the basis of the workflow in Splice.
102+
n, err := splice(pipefd, sock.Sysfd, max, spliceNonblock)
93103
if err == syscall.EINTR {
94104
continue
95105
}
@@ -127,7 +137,14 @@ func splicePump(sock *FD, pipefd int, inPipe int) (int, error) {
127137
}
128138
written := 0
129139
for inPipe > 0 {
130-
n, err := splice(sock.Sysfd, pipefd, inPipe, 0)
140+
// In theory calling splice(2) with SPLICE_F_NONBLOCK could end up an infinite loop here,
141+
// because it could return EAGAIN ceaselessly when the read end of the pipe is empty,
142+
// but this shouldn't be a concern here, since the pipe buffer must contain inPipe size of
143+
// data on the basis of the workflow in Splice.
144+
n, err := splice(sock.Sysfd, pipefd, inPipe, spliceNonblock)
145+
if err == syscall.EINTR {
146+
continue
147+
}
131148
// Here, the condition n == 0 && err == nil should never be
132149
// observed, since Splice controls the write side of the pipe.
133150
if n > 0 {

0 commit comments

Comments
 (0)