]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[release-branch.go1.21] internal/poll: add SPLICE_F_NONBLOCK flag for splice to avoid...
authorAndy Pan <panjf2000@gmail.com>
Tue, 17 Oct 2023 14:38:17 +0000 (22:38 +0800)
committerGopher Robot <gobot@golang.org>
Wed, 8 Nov 2023 18:02:42 +0000 (18:02 +0000)
Fixes #63801
Updates #59041
Updates #63795

Details: https://github.com/golang/go/issues/59041#issuecomment-1766610087

Change-Id: Id3fc1df6d86b7c4cc383d09f9465fa8f4cc2a559
Reviewed-on: https://go-review.googlesource.com/c/go/+/536015
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
(cherry picked from commit 40cdf69fc9279ab28f84a6e0f965de8382c578fe)
Reviewed-on: https://go-review.googlesource.com/c/go/+/538117
Auto-Submit: Heschi Kreinick <heschi@google.com>
Reviewed-by: Mauri de Souza Meneguzzo <mauri870@gmail.com>
Reviewed-by: Heschi Kreinick <heschi@google.com>
src/internal/poll/splice_linux.go

index 9505c5dcfc1eb10d06a59484eabc87621f51097b..72cca34fe4ae5ec88c81d4413459d49294e4691a 100644 (file)
@@ -13,6 +13,12 @@ import (
 )
 
 const (
+       // spliceNonblock doesn't make the splice itself necessarily nonblocking
+       // (because the actual file descriptors that are spliced from/to may block
+       // unless they have the O_NONBLOCK flag set), but it makes the splice pipe
+       // operations nonblocking.
+       spliceNonblock = 0x2
+
        // maxSpliceSize is the maximum amount of data Splice asks
        // the kernel to move in a single call to splice(2).
        // 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) {
                return 0, err
        }
        for {
-               n, err := splice(pipefd, sock.Sysfd, max, 0)
+               // In theory calling splice(2) with SPLICE_F_NONBLOCK could end up an infinite loop here,
+               // because it could return EAGAIN ceaselessly when the write end of the pipe is full,
+               // but this shouldn't be a concern here, since the pipe buffer must be sufficient for
+               // this data transmission on the basis of the workflow in Splice.
+               n, err := splice(pipefd, sock.Sysfd, max, spliceNonblock)
                if err == syscall.EINTR {
                        continue
                }
@@ -127,7 +137,14 @@ func splicePump(sock *FD, pipefd int, inPipe int) (int, error) {
        }
        written := 0
        for inPipe > 0 {
-               n, err := splice(sock.Sysfd, pipefd, inPipe, 0)
+               // In theory calling splice(2) with SPLICE_F_NONBLOCK could end up an infinite loop here,
+               // because it could return EAGAIN ceaselessly when the read end of the pipe is empty,
+               // but this shouldn't be a concern here, since the pipe buffer must contain inPipe size of
+               // data on the basis of the workflow in Splice.
+               n, err := splice(sock.Sysfd, pipefd, inPipe, spliceNonblock)
+               if err == syscall.EINTR {
+                       continue
+               }
                // Here, the condition n == 0 && err == nil should never be
                // observed, since Splice controls the write side of the pipe.
                if n > 0 {