return err
}
defer fd.decref()
- return syscall.Fsync(fd.Sysfd)
+ return ignoringEINTR(func() error {
+ return syscall.Fsync(fd.Sysfd)
+ })
}
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
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.
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.
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
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
+ }
+ }
+}
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() {
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
}
}
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() {
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.
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.
}
}
-// 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 {
var entptr *syscall.Dirent
for len(names) < size || n == -1 {
if res := readdir_r(d.dir, &dirent, &entptr); res != 0 {
+ if syscall.Errno(res) == syscall.EINTR {
+ continue
+ }
return names, wrapSyscallError("readdir", syscall.Errno(res))
}
if entptr == nil { // EOF
if runtime.GOOS == "windows" && isWindowsNulName(name) {
return &PathError{"mkdir", name, syscall.ENOTDIR}
}
- e := syscall.Mkdir(fixLongPath(name), syscallMode(perm))
+ longName := fixLongPath(name)
+ e := ignoringEINTR(func() error {
+ return syscall.Mkdir(longName, syscallMode(perm))
+ })
if e != nil {
return &PathError{"mkdir", name, e}
func newRawConn(file *File) (*rawConn, error) {
return nil, syscall.EPLAN9
}
+
+func ignoringEINTR(fn func() error) error {
+ return fn()
+}
// See docs in file.go:Chmod.
func chmod(name string, mode FileMode) error {
- if e := syscall.Chmod(fixLongPath(name), syscallMode(mode)); e != nil {
+ longName := fixLongPath(name)
+ e := ignoringEINTR(func() error {
+ return syscall.Chmod(longName, syscallMode(mode))
+ })
+ if e != nil {
return &PathError{"chmod", name, e}
}
return nil
// On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or
// EPLAN9 error, wrapped in *PathError.
func Chown(name string, uid, gid int) error {
- if e := syscall.Chown(name, uid, gid); e != nil {
+ e := ignoringEINTR(func() error {
+ return syscall.Chown(name, uid, gid)
+ })
+ if e != nil {
return &PathError{"chown", name, e}
}
return nil
// On Windows, it always returns the syscall.EWINDOWS error, wrapped
// in *PathError.
func Lchown(name string, uid, gid int) error {
- if e := syscall.Lchown(name, uid, gid); e != nil {
+ e := ignoringEINTR(func() error {
+ return syscall.Lchown(name, uid, gid)
+ })
+ if e != nil {
return &PathError{"lchown", name, e}
}
return nil
}
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
+ }
+ }
+}
return &LinkError{"rename", oldname, newname, syscall.EEXIST}
}
}
- err = syscall.Rename(oldname, newname)
+ err = ignoringEINTR(func() error {
+ return syscall.Rename(oldname, newname)
+ })
if err != nil {
return &LinkError{"rename", oldname, newname, err}
}
switch runtime.GOOS {
case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd":
var st syscall.Stat_t
- err := syscall.Fstat(fdi, &st)
+ err := ignoringEINTR(func() error {
+ return syscall.Fstat(fdi, &st)
+ })
typ := st.Mode & syscall.S_IFMT
// Don't try to use kqueue with regular files on *BSDs.
// On FreeBSD a regular file is always
// If the file is a symbolic link, it changes the size of the link's target.
// If there is an error, it will be of type *PathError.
func Truncate(name string, size int64) error {
- if e := syscall.Truncate(name, size); e != nil {
+ e := ignoringEINTR(func() error {
+ return syscall.Truncate(name, size)
+ })
+ if e != nil {
return &PathError{"truncate", name, e}
}
return nil
// whether name is a file or directory.
// Try both: it is cheaper on average than
// doing a Stat plus the right one.
- e := syscall.Unlink(name)
+ e := ignoringEINTR(func() error {
+ return syscall.Unlink(name)
+ })
if e == nil {
return nil
}
- e1 := syscall.Rmdir(name)
+ e1 := ignoringEINTR(func() error {
+ return syscall.Rmdir(name)
+ })
if e1 == nil {
return nil
}
// Link creates newname as a hard link to the oldname file.
// If there is an error, it will be of type *LinkError.
func Link(oldname, newname string) error {
- e := syscall.Link(oldname, newname)
+ e := ignoringEINTR(func() error {
+ return syscall.Link(oldname, newname)
+ })
if e != nil {
return &LinkError{"link", oldname, newname, e}
}
// Symlink creates newname as a symbolic link to oldname.
// If there is an error, it will be of type *LinkError.
func Symlink(oldname, newname string) error {
- e := syscall.Symlink(oldname, newname)
+ e := ignoringEINTR(func() error {
+ return syscall.Symlink(oldname, newname)
+ })
if e != nil {
return &LinkError{"symlink", oldname, newname, e}
}
func Readlink(name string) (string, error) {
for len := 128; ; len *= 2 {
b := make([]byte, len)
- n, e := fixCount(syscall.Readlink(name, b))
+ var (
+ n int
+ e error
+ )
+ for {
+ n, e = fixCount(syscall.Readlink(name, b))
+ if e != syscall.EINTR {
+ break
+ }
+ }
// buffer too small
if runtime.GOOS == "aix" && e == syscall.ERANGE {
continue
// If the operating system provides a Getwd call, use it.
// Otherwise, we're trying to find our way back to ".".
if syscall.ImplementsGetwd {
- s, e := syscall.Getwd()
+ var (
+ s string
+ e error
+ )
+ for {
+ s, e = syscall.Getwd()
+ if e != syscall.EINTR {
+ break
+ }
+ }
if useSyscallwd(e) {
return s, NewSyscallError("getwd", e)
}
// statNolog stats a file with no test logging.
func statNolog(name string) (FileInfo, error) {
var fs fileStat
- err := syscall.Stat(name, &fs.sys)
+ err := ignoringEINTR(func() error {
+ return syscall.Stat(name, &fs.sys)
+ })
if err != nil {
return nil, &PathError{"stat", name, err}
}
// lstatNolog lstats a file with no test logging.
func lstatNolog(name string) (FileInfo, error) {
var fs fileStat
- err := syscall.Lstat(name, &fs.sys)
+ err := ignoringEINTR(func() error {
+ return syscall.Lstat(name, &fs.sys)
+ })
if err != nil {
return nil, &PathError{"lstat", name, err}
}
{trace.EvGoSysCall, []frame{
{"syscall.read", 0},
{"syscall.Read", 0},
- {"internal/poll.ignoringEINTR", 0},
+ {"internal/poll.ignoringEINTRIO", 0},
{"internal/poll.(*FD).Read", 0},
{"os.(*File).read", 0},
{"os.(*File).Read", 0},