Skip to content

Commit 958f3a0

Browse files
panjf2000prattmic
authored andcommitted
[release-branch.go1.23] internal/poll: handle the special case of sendfile(2) sending the full chunk
CL 622235 would fix #70000 while resulting in one extra sendfile(2) system call when sendfile(2) returns (>0, EAGAIN). That's also why I left sendfile_bsd.go behind, and didn't make it line up with other two implementations: sendfile_linux.go and sendfile_solaris.go. Unlike sendfile(2)'s on Linux and Solaris that always return (0, EAGAIN), sendfile(2)'s on *BSD and macOS may return (>0, EAGAIN) when using a socket marked for non-blocking I/O. In that case, the current code will try to re-call sendfile(2) immediately, which will most likely get us a (0, EAGAIN). After that, it goes to `dstFD.pd.waitWrite(dstFD.isFile)` below, which should have been done in the first place. Thus, the real problem that leads to #70000 is that the old code doesn't handle the special case of sendfile(2) sending the exact number of bytes the caller requested. Fixes #70000 Fixes #70020 Change-Id: I6073d6b9feb58b3d7e114ec21e4e80d9727bca66 Reviewed-on: https://go-review.googlesource.com/c/go/+/622255 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Damien Neil <[email protected]> Run-TryBot: Andy Pan <[email protected]> Reviewed-on: https://go-review.googlesource.com/c/go/+/622697
1 parent 6ba3a8a commit 958f3a0

File tree

1 file changed

+16
-1
lines changed

1 file changed

+16
-1
lines changed

src/internal/poll/sendfile_bsd.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,28 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (written int64, err error,
3232
if int64(n) > remain {
3333
n = int(remain)
3434
}
35+
m := n
3536
pos1 := pos
3637
n, err = syscall.Sendfile(dst, src, &pos1, n)
3738
if n > 0 {
3839
pos += int64(n)
3940
written += int64(n)
4041
remain -= int64(n)
41-
continue
42+
// (n, nil) indicates that sendfile(2) has transferred
43+
// the exact number of bytes we requested, or some unretryable
44+
// error have occurred with partial bytes sent. Either way, we
45+
// don't need to go through the following logic to check EINTR
46+
// or fell into dstFD.pd.waitWrite, just continue to send the
47+
// next chunk or break the loop.
48+
if n == m {
49+
continue
50+
} else if err != syscall.EAGAIN &&
51+
err != syscall.EINTR &&
52+
err != syscall.EBUSY {
53+
// Particularly, EPIPE. Errors like that would normally lead
54+
// the subsequent sendfile(2) call to (-1, EBADF).
55+
break
56+
}
4257
} else if err != syscall.EAGAIN && err != syscall.EINTR {
4358
// This includes syscall.ENOSYS (no kernel
4459
// support) and syscall.EINVAL (fd types which

0 commit comments

Comments
 (0)