Commit 3ba80d98 authored by Frederick Akalin's avatar Frederick Akalin Committed by Han-Wen Nienhuys

Add handleEINTR() function and use it for read/write/writev syscalls

EINTR is commonly encountered when running under a debugger, so this
change makes it possible to do so without hitting spurious
EINTR errors.
parent 6fd2fb13
...@@ -198,6 +198,25 @@ func (ms *Server) DebugData() string { ...@@ -198,6 +198,25 @@ func (ms *Server) DebugData() string {
// What is a good number? Maybe the number of CPUs? // What is a good number? Maybe the number of CPUs?
const _MAX_READERS = 2 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 // Returns a new request, or error. In case exitIdle is given, returns
// nil, OK if we have too many readers already. // nil, OK if we have too many readers already.
func (ms *Server) readRequest(exitIdle bool) (req *request, code Status) { func (ms *Server) readRequest(exitIdle bool) (req *request, code Status) {
...@@ -212,7 +231,12 @@ func (ms *Server) readRequest(exitIdle bool) (req *request, code Status) { ...@@ -212,7 +231,12 @@ func (ms *Server) readRequest(exitIdle bool) (req *request, code Status) {
ms.reqReaders++ ms.reqReaders++
ms.reqMu.Unlock() 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 { if err != nil {
code = ToStatus(err) code = ToStatus(err)
ms.reqPool.Put(req) ms.reqPool.Put(req)
......
...@@ -6,7 +6,10 @@ import ( ...@@ -6,7 +6,10 @@ import (
func (ms *Server) systemWrite(req *request, header []byte) Status { func (ms *Server) systemWrite(req *request, header []byte) Status {
if req.flatDataSize() == 0 { if req.flatDataSize() == 0 {
err := handleEINTR(func() error {
_, err := syscall.Write(ms.mountFd, header) _, err := syscall.Write(ms.mountFd, header)
return err
})
return ToStatus(err) return ToStatus(err)
} }
......
...@@ -7,7 +7,10 @@ import ( ...@@ -7,7 +7,10 @@ import (
func (ms *Server) systemWrite(req *request, header []byte) Status { func (ms *Server) systemWrite(req *request, header []byte) Status {
if req.flatDataSize() == 0 { if req.flatDataSize() == 0 {
err := handleEINTR(func() error {
_, err := syscall.Write(ms.mountFd, header) _, err := syscall.Write(ms.mountFd, header)
return err
})
return ToStatus(err) return ToStatus(err)
} }
......
...@@ -9,11 +9,15 @@ import ( ...@@ -9,11 +9,15 @@ import (
// TODO - move these into Go's syscall package. // 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( n1, _, e1 := syscall.Syscall(
syscall.SYS_WRITEV, syscall.SYS_WRITEV,
uintptr(fd), uintptr(unsafe.Pointer(iovecs)), uintptr(cnt)) 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) { func writev(fd int, packet [][]byte) (n int, err error) {
...@@ -30,9 +34,13 @@ func writev(fd int, packet [][]byte) (n int, err error) { ...@@ -30,9 +34,13 @@ func writev(fd int, packet [][]byte) (n int, err error) {
iovecs = append(iovecs, vec) iovecs = append(iovecs, vec)
} }
n, errno := sys_writev(fd, &iovecs[0], len(iovecs)) sysErr := handleEINTR(func() error {
if errno != 0 { var err error
err = os.NewSyscallError("writev", syscall.Errno(errno)) n, err = sys_writev(fd, &iovecs[0], len(iovecs))
return err
})
if sysErr != nil {
err = os.NewSyscallError("writev", sysErr)
} }
return n, err return n, err
} }
......
...@@ -8,11 +8,15 @@ import ( ...@@ -8,11 +8,15 @@ import (
// TODO - move these into Go's syscall package. // 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( n1, _, e1 := syscall.Syscall(
syscall.SYS_WRITEV, syscall.SYS_WRITEV,
uintptr(fd), uintptr(unsafe.Pointer(iovecs)), uintptr(cnt)) 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) { func writev(fd int, packet [][]byte) (n int, err error) {
...@@ -29,9 +33,13 @@ func writev(fd int, packet [][]byte) (n int, err error) { ...@@ -29,9 +33,13 @@ func writev(fd int, packet [][]byte) (n int, err error) {
iovecs = append(iovecs, vec) iovecs = append(iovecs, vec)
} }
n, errno := sys_writev(fd, &iovecs[0], len(iovecs)) sysErr := handleEINTR(func() error {
if errno != 0 { var err error
err = os.NewSyscallError("writev", syscall.Errno(errno)) n, err = sys_writev(fd, &iovecs[0], len(iovecs))
return err
})
if sysErr != nil {
err = os.NewSyscallError("writev", sysErr)
} }
return n, err return n, err
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment