aboutsummaryrefslogtreecommitdiff
path: root/src/internal
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2020-08-18 16:46:24 -0700
committerIan Lance Taylor <iant@golang.org>2020-08-19 21:49:56 +0000
commit6b420169d798c7ebe733487b56ea5c3fa4aab5ce (patch)
tree9f9e791d75c363b7f25529b1f408d50e8e03274d /src/internal
parent18239be10a0b5caa1b3222b228ff590b1c036382 (diff)
downloadgo-6b420169d798c7ebe733487b56ea5c3fa4aab5ce.tar.gz
go-6b420169d798c7ebe733487b56ea5c3fa4aab5ce.zip
os, internal/poll: loop on EINTR for all file syscalls
When using a FUSE file system, any system call that touches the file system can return EINTR. Fixes #40846 Change-Id: I25d32da22cec08dea81ab297291a85ad72db2df7 Reviewed-on: https://go-review.googlesource.com/c/go/+/249178 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Bryan C. Mills <bcmills@google.com>
Diffstat (limited to 'src/internal')
-rw-r--r--src/internal/poll/fd_fsync_posix.go4
-rw-r--r--src/internal/poll/fd_opendir_darwin.go8
-rw-r--r--src/internal/poll/fd_posix.go28
-rw-r--r--src/internal/poll/fd_unix.go22
4 files changed, 44 insertions, 18 deletions
diff --git a/src/internal/poll/fd_fsync_posix.go b/src/internal/poll/fd_fsync_posix.go
index 69358297f4..dd7956f14d 100644
--- a/src/internal/poll/fd_fsync_posix.go
+++ b/src/internal/poll/fd_fsync_posix.go
@@ -14,5 +14,7 @@ func (fd *FD) Fsync() error {
return err
}
defer fd.decref()
- return syscall.Fsync(fd.Sysfd)
+ return ignoringEINTR(func() error {
+ return syscall.Fsync(fd.Sysfd)
+ })
}
diff --git a/src/internal/poll/fd_opendir_darwin.go b/src/internal/poll/fd_opendir_darwin.go
index c7d3318c72..8eb770c358 100644
--- a/src/internal/poll/fd_opendir_darwin.go
+++ b/src/internal/poll/fd_opendir_darwin.go
@@ -19,7 +19,13 @@ func (fd *FD) OpenDir() (uintptr, string, error) {
if err != nil {
return 0, call, err
}
- dir, err := fdopendir(fd2)
+ var dir uintptr
+ for {
+ dir, err = fdopendir(fd2)
+ if err != syscall.EINTR {
+ break
+ }
+ }
if err != nil {
syscall.Close(fd2)
return 0, "fdopendir", err
diff --git a/src/internal/poll/fd_posix.go b/src/internal/poll/fd_posix.go
index 54747b4c99..e5fb05c9c2 100644
--- a/src/internal/poll/fd_posix.go
+++ b/src/internal/poll/fd_posix.go
@@ -35,7 +35,9 @@ func (fd *FD) Fchmod(mode uint32) error {
return err
}
defer fd.decref()
- return syscall.Fchmod(fd.Sysfd, mode)
+ return ignoringEINTR(func() error {
+ return syscall.Fchmod(fd.Sysfd, mode)
+ })
}
// Fchown wraps syscall.Fchown.
@@ -44,7 +46,9 @@ func (fd *FD) Fchown(uid, gid int) error {
return err
}
defer fd.decref()
- return syscall.Fchown(fd.Sysfd, uid, gid)
+ return ignoringEINTR(func() error {
+ return syscall.Fchown(fd.Sysfd, uid, gid)
+ })
}
// Ftruncate wraps syscall.Ftruncate.
@@ -53,7 +57,9 @@ func (fd *FD) Ftruncate(size int64) error {
return err
}
defer fd.decref()
- return syscall.Ftruncate(fd.Sysfd, size)
+ return ignoringEINTR(func() error {
+ return syscall.Ftruncate(fd.Sysfd, size)
+ })
}
// RawControl invokes the user-defined function f for a non-IO
@@ -66,3 +72,19 @@ func (fd *FD) RawControl(f func(uintptr)) error {
f(uintptr(fd.Sysfd))
return nil
}
+
+// ignoringEINTR makes a function call and repeats it if it returns
+// an EINTR error. This appears to be required even though we install all
+// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
+// Also #20400 and #36644 are issues in which a signal handler is
+// installed without setting SA_RESTART. None of these are the common case,
+// but there are enough of them that it seems that we can't avoid
+// an EINTR loop.
+func ignoringEINTR(fn func() error) error {
+ for {
+ err := fn()
+ if err != syscall.EINTR {
+ return err
+ }
+ }
+}
diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go
index 4872fa9851..1d5101eac3 100644
--- a/src/internal/poll/fd_unix.go
+++ b/src/internal/poll/fd_unix.go
@@ -152,7 +152,7 @@ func (fd *FD) Read(p []byte) (int, error) {
p = p[:maxRW]
}
for {
- n, err := ignoringEINTR(syscall.Read, fd.Sysfd, p)
+ n, err := ignoringEINTRIO(syscall.Read, fd.Sysfd, p)
if err != nil {
n = 0
if err == syscall.EAGAIN && fd.pd.pollable() {
@@ -264,7 +264,7 @@ func (fd *FD) Write(p []byte) (int, error) {
if fd.IsStream && max-nn > maxRW {
max = nn + maxRW
}
- n, err := ignoringEINTR(syscall.Write, fd.Sysfd, p[nn:max])
+ n, err := ignoringEINTRIO(syscall.Write, fd.Sysfd, p[nn:max])
if n > 0 {
nn += n
}
@@ -423,7 +423,7 @@ func (fd *FD) ReadDirent(buf []byte) (int, error) {
}
defer fd.decref()
for {
- n, err := ignoringEINTR(syscall.ReadDirent, fd.Sysfd, buf)
+ n, err := ignoringEINTRIO(syscall.ReadDirent, fd.Sysfd, buf)
if err != nil {
n = 0
if err == syscall.EAGAIN && fd.pd.pollable() {
@@ -452,7 +452,9 @@ func (fd *FD) Fstat(s *syscall.Stat_t) error {
return err
}
defer fd.decref()
- return syscall.Fstat(fd.Sysfd, s)
+ return ignoringEINTR(func() error {
+ return syscall.Fstat(fd.Sysfd, s)
+ })
}
// tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used.
@@ -514,7 +516,7 @@ func (fd *FD) WriteOnce(p []byte) (int, error) {
return 0, err
}
defer fd.writeUnlock()
- return ignoringEINTR(syscall.Write, fd.Sysfd, p)
+ return ignoringEINTRIO(syscall.Write, fd.Sysfd, p)
}
// RawRead invokes the user-defined function f for a read operation.
@@ -555,14 +557,8 @@ func (fd *FD) RawWrite(f func(uintptr) bool) error {
}
}
-// ignoringEINTR makes a function call and repeats it if it returns
-// an EINTR error. This appears to be required even though we install
-// all signal handlers with SA_RESTART: see #22838, #38033, #38836.
-// Also #20400 and #36644 are issues in which a signal handler is
-// installed without setting SA_RESTART. None of these are the common case,
-// but there are enough of them that it seems that we can't avoid
-// an EINTR loop.
-func ignoringEINTR(fn func(fd int, p []byte) (int, error), fd int, p []byte) (int, error) {
+// ignoringEINTRIO is like ignoringEINTR, but just for IO calls.
+func ignoringEINTRIO(fn func(fd int, p []byte) (int, error), fd int, p []byte) (int, error) {
for {
n, err := fn(fd, p)
if err != syscall.EINTR {