Skip to content

Commit

Permalink
Add handleEINTR() function and use it for read/write/writev syscalls
Browse files Browse the repository at this point in the history
EINTR is commonly encountered when running under a debugger, so this
change makes it possible to do so without hitting spurious
EINTR errors.
  • Loading branch information
akalin authored and hanwen committed Apr 22, 2015
1 parent 6fd2fb1 commit 3ba80d9
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 13 deletions.
26 changes: 25 additions & 1 deletion fuse/server.go
Expand Up @@ -198,6 +198,25 @@ func (ms *Server) DebugData() string {
// What is a good number? Maybe the number of CPUs?
const _MAX_READERS = 2

// handleEINTR retries the given function until it doesn't return syscall.EINTR.
// This is similar to the HANDLE_EINTR() macro from Chromium ( see
// https://code.google.com/p/chromium/codesearch#chromium/src/base/posix/eintr_wrapper.h
// ) and the TEMP_FAILURE_RETRY() from glibc (see
// https://www.gnu.org/software/libc/manual/html_node/Interrupted-Primitives.html
// ).
//
// Don't use handleEINTR() with syscall.Close(); see
// https://code.google.com/p/chromium/issues/detail?id=269623 .
func handleEINTR(fn func() error) (err error) {
for {
err = fn()
if err != syscall.EINTR {
break
}
}
return
}

// Returns a new request, or error. In case exitIdle is given, returns
// nil, OK if we have too many readers already.
func (ms *Server) readRequest(exitIdle bool) (req *request, code Status) {
Expand All @@ -212,7 +231,12 @@ func (ms *Server) readRequest(exitIdle bool) (req *request, code Status) {
ms.reqReaders++
ms.reqMu.Unlock()

n, err := syscall.Read(ms.mountFd, dest)
var n int
err := handleEINTR(func() error {
var err error
n, err = syscall.Read(ms.mountFd, dest)
return err
})
if err != nil {
code = ToStatus(err)
ms.reqPool.Put(req)
Expand Down
5 changes: 4 additions & 1 deletion fuse/server_darwin.go
Expand Up @@ -6,7 +6,10 @@ import (

func (ms *Server) systemWrite(req *request, header []byte) Status {
if req.flatDataSize() == 0 {
_, err := syscall.Write(ms.mountFd, header)
err := handleEINTR(func() error {
_, err := syscall.Write(ms.mountFd, header)
return err
})
return ToStatus(err)
}

Expand Down
5 changes: 4 additions & 1 deletion fuse/server_linux.go
Expand Up @@ -7,7 +7,10 @@ import (

func (ms *Server) systemWrite(req *request, header []byte) Status {
if req.flatDataSize() == 0 {
_, err := syscall.Write(ms.mountFd, header)
err := handleEINTR(func() error {
_, err := syscall.Write(ms.mountFd, header)
return err
})
return ToStatus(err)
}

Expand Down
18 changes: 13 additions & 5 deletions fuse/syscall_darwin.go
Expand Up @@ -9,11 +9,15 @@ import (

// TODO - move these into Go's syscall package.

func sys_writev(fd int, iovecs *syscall.Iovec, cnt int) (n int, errno int) {
func sys_writev(fd int, iovecs *syscall.Iovec, cnt int) (n int, err error) {
n1, _, e1 := syscall.Syscall(
syscall.SYS_WRITEV,
uintptr(fd), uintptr(unsafe.Pointer(iovecs)), uintptr(cnt))
return int(n1), int(e1)
n = int(n1)
if e1 != 0 {
err = syscall.Errno(e1)
}
return
}

func writev(fd int, packet [][]byte) (n int, err error) {
Expand All @@ -30,9 +34,13 @@ func writev(fd int, packet [][]byte) (n int, err error) {
iovecs = append(iovecs, vec)
}

n, errno := sys_writev(fd, &iovecs[0], len(iovecs))
if errno != 0 {
err = os.NewSyscallError("writev", syscall.Errno(errno))
sysErr := handleEINTR(func() error {
var err error
n, err = sys_writev(fd, &iovecs[0], len(iovecs))
return err
})
if sysErr != nil {
err = os.NewSyscallError("writev", sysErr)
}
return n, err
}
Expand Down
18 changes: 13 additions & 5 deletions fuse/syscall_linux.go
Expand Up @@ -8,11 +8,15 @@ import (

// TODO - move these into Go's syscall package.

func sys_writev(fd int, iovecs *syscall.Iovec, cnt int) (n int, errno int) {
func sys_writev(fd int, iovecs *syscall.Iovec, cnt int) (n int, err error) {
n1, _, e1 := syscall.Syscall(
syscall.SYS_WRITEV,
uintptr(fd), uintptr(unsafe.Pointer(iovecs)), uintptr(cnt))
return int(n1), int(e1)
n = int(n1)
if e1 != 0 {
err = syscall.Errno(e1)
}
return n, err
}

func writev(fd int, packet [][]byte) (n int, err error) {
Expand All @@ -29,9 +33,13 @@ func writev(fd int, packet [][]byte) (n int, err error) {
iovecs = append(iovecs, vec)
}

n, errno := sys_writev(fd, &iovecs[0], len(iovecs))
if errno != 0 {
err = os.NewSyscallError("writev", syscall.Errno(errno))
sysErr := handleEINTR(func() error {
var err error
n, err = sys_writev(fd, &iovecs[0], len(iovecs))
return err
})
if sysErr != nil {
err = os.NewSyscallError("writev", sysErr)
}
return n, err
}

0 comments on commit 3ba80d9

Please sign in to comment.