Commit 3792db51 authored by Ian Lance Taylor's avatar Ian Lance Taylor

net: refactor poller into new internal/poll package

This will make it possible to use the poller with the os package.

This is a lot of code movement but the behavior is intended to be
unchanged.

Update #6817.
Update #7903.
Update #15021.
Update #18507.

Change-Id: I1413685928017c32df5654ded73a2643820977ae
Reviewed-on: https://go-review.googlesource.com/36799
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarDavid Crawshaw <crawshaw@golang.org>
Reviewed-by: 's avatarRuss Cox <rsc@golang.org>
parent b548eee3
This diff is collapsed.
......@@ -2180,7 +2180,7 @@ func (gcToolchain) gc(b *Builder, p *load.Package, archive, obj string, asmhdr b
extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.FFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
if p.Standard {
switch p.ImportPath {
case "bytes", "net", "os", "runtime/pprof", "sync", "time":
case "bytes", "internal/poll", "net", "os", "runtime/pprof", "sync", "time":
extFiles++
}
}
......
......@@ -150,7 +150,8 @@ var pkgDeps = map[string][]string{
"syscall",
},
"os": {"L1", "os", "syscall", "time", "internal/syscall/windows"},
"internal/poll": {"L0", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8"},
"os": {"L1", "os", "syscall", "time", "internal/poll", "internal/syscall/windows"},
"path/filepath": {"L2", "os", "syscall"},
"io/ioutil": {"L2", "os", "path/filepath", "time"},
"os/exec": {"L2", "os", "context", "path/filepath", "syscall"},
......@@ -300,7 +301,7 @@ var pkgDeps = map[string][]string{
"net": {
"L0", "CGO",
"context", "math/rand", "os", "sort", "syscall", "time",
"internal/nettrace",
"internal/nettrace", "internal/poll",
"internal/syscall/windows", "internal/singleflight", "internal/race",
"golang_org/x/net/lif", "golang_org/x/net/route",
},
......
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Export guts for testing.
// Since testing imports os and os imports internal/poll,
// the internal/poll tests can not be in package poll.
package poll
var Consume = consume
type FDMutex struct {
fdMutex
}
func (mu *FDMutex) Incref() bool {
return mu.incref()
}
func (mu *FDMutex) IncrefAndClose() bool {
return mu.increfAndClose()
}
func (mu *FDMutex) Decref() bool {
return mu.decref()
}
func (mu *FDMutex) RWLock(read bool) bool {
return mu.rwlock(read)
}
func (mu *FDMutex) RWUnlock(read bool) bool {
return mu.rwunlock(read)
}
func (fd *FD) EOFError(n int, err error) error {
return fd.eofError(n, err)
}
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package poll supports non-blocking I/O on file descriptors with polling.
// This supports I/O operations that block only a goroutine, not a thread.
// This is used by the net and os packages.
// It uses a poller built into the runtime, with support from the
// runtime scheduler.
package poll
import (
"errors"
)
// ErrClosing is returned when a descriptor is used after it has been closed.
var ErrClosing = errors.New("use of closed file or network connection")
// ErrTimeout is returned for an expired deadline.
var ErrTimeout error = &TimeoutError{}
// TimeoutError is returned for an expired deadline.
type TimeoutError struct{}
// Implement the net.Error interface.
func (e *TimeoutError) Error() string { return "i/o timeout" }
func (e *TimeoutError) Timeout() bool { return true }
func (e *TimeoutError) Temporary() bool { return true }
// consume removes data from a slice of byte slices, for writev.
func consume(v *[][]byte, n int64) {
for len(*v) > 0 {
ln0 := int64(len((*v)[0]))
if ln0 > n {
(*v)[0] = (*v)[0][n:]
return
}
n -= ln0
*v = (*v)[1:]
}
}
// TestHookDidWritev is a hook for testing writev.
var TestHookDidWritev = func(wrote int) {}
......@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
package poll
import (
"os"
"runtime"
"sync"
"syscall"
......@@ -49,7 +48,7 @@ func newAsyncIO(fn func([]byte) (int, error), b []byte) *asyncIO {
// Go runtime.
runtime.LockOSThread()
runtime_ignoreHangup()
aio.pid = os.Getpid()
aio.pid = syscall.Getpid()
aio.mu.Unlock()
n, err := fn(b)
......@@ -64,8 +63,6 @@ func newAsyncIO(fn func([]byte) (int, error), b []byte) *asyncIO {
return aio
}
var hangupNote os.Signal = syscall.Note("hangup")
// Cancel interrupts the I/O operation, causing
// the Wait function to return.
func (aio *asyncIO) Cancel() {
......@@ -74,11 +71,12 @@ func (aio *asyncIO) Cancel() {
if aio.pid == -1 {
return
}
proc, err := os.FindProcess(aio.pid)
if err != nil {
f, e := syscall.Open("/proc/"+itoa(aio.pid)+"/note", syscall.O_WRONLY)
if e != nil {
return
}
proc.Signal(hangupNote)
syscall.Write(f, []byte("hangup"))
syscall.Close(f)
}
// Wait for the I/O operation to complete.
......
......@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
package poll
import "sync/atomic"
// fdMutex is a specialized synchronization primitive that manages
// lifetime of an fd and serializes access to Read, Write and Close
// methods on netFD.
// methods on FD.
type fdMutex struct {
state uint64
rsema uint32
......@@ -16,7 +16,7 @@ type fdMutex struct {
}
// fdMutex.state is organized as follows:
// 1 bit - whether netFD is closed, if set all subsequent lock operations will fail.
// 1 bit - whether FD is closed, if set all subsequent lock operations will fail.
// 1 bit - lock for read operations.
// 1 bit - lock for write operations.
// 20 bits - total number of references (read+write+misc).
......@@ -196,9 +196,9 @@ func runtime_Semrelease(sema *uint32)
// incref adds a reference to fd.
// It returns an error when fd cannot be used.
func (fd *netFD) incref() error {
func (fd *FD) incref() error {
if !fd.fdmu.incref() {
return errClosing
return ErrClosing
}
return nil
}
......@@ -206,17 +206,18 @@ func (fd *netFD) incref() error {
// decref removes a reference from fd.
// It also closes fd when the state of fd is set to closed and there
// is no remaining reference.
func (fd *netFD) decref() {
func (fd *FD) decref() error {
if fd.fdmu.decref() {
fd.destroy()
return fd.destroy()
}
return nil
}
// readLock adds a reference to fd and locks fd for reading.
// It returns an error when fd cannot be used for reading.
func (fd *netFD) readLock() error {
func (fd *FD) readLock() error {
if !fd.fdmu.rwlock(true) {
return errClosing
return ErrClosing
}
return nil
}
......@@ -224,7 +225,7 @@ func (fd *netFD) readLock() error {
// readUnlock removes a reference from fd and unlocks fd for reading.
// It also closes fd when the state of fd is set to closed and there
// is no remaining reference.
func (fd *netFD) readUnlock() {
func (fd *FD) readUnlock() {
if fd.fdmu.rwunlock(true) {
fd.destroy()
}
......@@ -232,9 +233,9 @@ func (fd *netFD) readUnlock() {
// writeLock adds a reference to fd and locks fd for writing.
// It returns an error when fd cannot be used for writing.
func (fd *netFD) writeLock() error {
func (fd *FD) writeLock() error {
if !fd.fdmu.rwlock(false) {
return errClosing
return ErrClosing
}
return nil
}
......@@ -242,7 +243,7 @@ func (fd *netFD) writeLock() error {
// writeUnlock removes a reference from fd and unlocks fd for writing.
// It also closes fd when the state of fd is set to closed and there
// is no remaining reference.
func (fd *netFD) writeUnlock() {
func (fd *FD) writeUnlock() {
if fd.fdmu.rwunlock(false) {
fd.destroy()
}
......
......@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
package poll_test
import (
. "internal/poll"
"math/rand"
"runtime"
"testing"
......@@ -12,57 +13,57 @@ import (
)
func TestMutexLock(t *testing.T) {
var mu fdMutex
var mu FDMutex
if !mu.incref() {
if !mu.Incref() {
t.Fatal("broken")
}
if mu.decref() {
if mu.Decref() {
t.Fatal("broken")
}
if !mu.rwlock(true) {
if !mu.RWLock(true) {
t.Fatal("broken")
}
if mu.rwunlock(true) {
if mu.RWUnlock(true) {
t.Fatal("broken")
}
if !mu.rwlock(false) {
if !mu.RWLock(false) {
t.Fatal("broken")
}
if mu.rwunlock(false) {
if mu.RWUnlock(false) {
t.Fatal("broken")
}
}
func TestMutexClose(t *testing.T) {
var mu fdMutex
if !mu.increfAndClose() {
var mu FDMutex
if !mu.IncrefAndClose() {
t.Fatal("broken")
}
if mu.incref() {
if mu.Incref() {
t.Fatal("broken")
}
if mu.rwlock(true) {
if mu.RWLock(true) {
t.Fatal("broken")
}
if mu.rwlock(false) {
if mu.RWLock(false) {
t.Fatal("broken")
}
if mu.increfAndClose() {
if mu.IncrefAndClose() {
t.Fatal("broken")
}
}
func TestMutexCloseUnblock(t *testing.T) {
c := make(chan bool)
var mu fdMutex
mu.rwlock(true)
var mu FDMutex
mu.RWLock(true)
for i := 0; i < 4; i++ {
go func() {
if mu.rwlock(true) {
if mu.RWLock(true) {
t.Error("broken")
return
}
......@@ -76,7 +77,7 @@ func TestMutexCloseUnblock(t *testing.T) {
t.Fatal("broken")
default:
}
mu.increfAndClose() // Must unblock the readers.
mu.IncrefAndClose() // Must unblock the readers.
for i := 0; i < 4; i++ {
select {
case <-c:
......@@ -84,10 +85,10 @@ func TestMutexCloseUnblock(t *testing.T) {
t.Fatal("broken")
}
}
if mu.decref() {
if mu.Decref() {
t.Fatal("broken")
}
if !mu.rwunlock(true) {
if !mu.RWUnlock(true) {
t.Fatal("broken")
}
}
......@@ -102,22 +103,22 @@ func TestMutexPanic(t *testing.T) {
f()
}
var mu fdMutex
ensurePanics(func() { mu.decref() })
ensurePanics(func() { mu.rwunlock(true) })
ensurePanics(func() { mu.rwunlock(false) })
var mu FDMutex
ensurePanics(func() { mu.Decref() })
ensurePanics(func() { mu.RWUnlock(true) })
ensurePanics(func() { mu.RWUnlock(false) })
ensurePanics(func() { mu.incref(); mu.decref(); mu.decref() })
ensurePanics(func() { mu.rwlock(true); mu.rwunlock(true); mu.rwunlock(true) })
ensurePanics(func() { mu.rwlock(false); mu.rwunlock(false); mu.rwunlock(false) })
ensurePanics(func() { mu.Incref(); mu.Decref(); mu.Decref() })
ensurePanics(func() { mu.RWLock(true); mu.RWUnlock(true); mu.RWUnlock(true) })
ensurePanics(func() { mu.RWLock(false); mu.RWUnlock(false); mu.RWUnlock(false) })
// ensure that it's still not broken
mu.incref()
mu.decref()
mu.rwlock(true)
mu.rwunlock(true)
mu.rwlock(false)
mu.rwunlock(false)
mu.Incref()
mu.Decref()
mu.RWLock(true)
mu.RWUnlock(true)
mu.RWLock(false)
mu.RWUnlock(false)
}
func TestMutexStress(t *testing.T) {
......@@ -129,7 +130,7 @@ func TestMutexStress(t *testing.T) {
}
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
done := make(chan bool)
var mu fdMutex
var mu FDMutex
var readState [2]uint64
var writeState [2]uint64
for p := 0; p < P; p++ {
......@@ -138,16 +139,16 @@ func TestMutexStress(t *testing.T) {
for i := 0; i < N; i++ {
switch r.Intn(3) {
case 0:
if !mu.incref() {
if !mu.Incref() {
t.Error("broken")
return
}
if mu.decref() {
if mu.Decref() {
t.Error("broken")
return
}
case 1:
if !mu.rwlock(true) {
if !mu.RWLock(true) {
t.Error("broken")
return
}
......@@ -158,12 +159,12 @@ func TestMutexStress(t *testing.T) {
}
readState[0]++
readState[1]++
if mu.rwunlock(true) {
if mu.RWUnlock(true) {
t.Error("broken")
return
}
case 2:
if !mu.rwlock(false) {
if !mu.RWLock(false) {
t.Error("broken")
return
}
......@@ -174,7 +175,7 @@ func TestMutexStress(t *testing.T) {
}
writeState[0]++
writeState[1]++
if mu.rwunlock(false) {
if mu.RWUnlock(false) {
t.Error("broken")
return
}
......@@ -186,10 +187,10 @@ func TestMutexStress(t *testing.T) {
for p := 0; p < P; p++ {
<-done
}
if !mu.increfAndClose() {
if !mu.IncrefAndClose() {
t.Fatal("broken")
}
if !mu.decref() {
if !mu.Decref() {
t.Fatal("broken")
}
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package poll
import (
"io"
"sync/atomic"
"time"
)
type atomicBool int32
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
type FD struct {
// Lock sysfd and serialize access to Read and Write methods.
fdmu fdMutex
Destroy func()
// deadlines
raio *asyncIO
waio *asyncIO
rtimer *time.Timer
wtimer *time.Timer
rtimedout atomicBool // set true when read deadline has been reached
wtimedout atomicBool // set true when write deadline has been reached
}
// We need this to close out a file descriptor when it is unlocked,
// but the real implementation has to live in the net package because
// it uses os.File's.
func (fd *FD) destroy() error {
if fd.Destroy != nil {
fd.Destroy()
}
return nil
}
// Close handles the locking for closing an FD. The real operation
// is in the net package.
func (fd *FD) Close() error {
if !fd.fdmu.increfAndClose() {
return ErrClosing
}
return nil
}
func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (n int, err error) {
if fd.rtimedout.isSet() {
return 0, ErrTimeout
}
if err := fd.readLock(); err != nil {
return 0, err
}
defer fd.readUnlock()
if len(b) == 0 {
return 0, nil
}
fd.raio = newAsyncIO(fn, b)
n, err = fd.raio.Wait()
fd.raio = nil
if isHangup(err) {
err = io.EOF
}
if isInterrupted(err) {
err = ErrTimeout
}
return
}
func (fd *FD) Write(fn func([]byte) (int, error), b []byte) (n int, err error) {
if fd.wtimedout.isSet() {
return 0, ErrTimeout
}
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
fd.waio = newAsyncIO(fn, b)
n, err = fd.waio.Wait()
fd.waio = nil
if isInterrupted(err) {
err = ErrTimeout
}
return
}
func (fd *FD) SetDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'r'+'w')
}
func (fd *FD) SetReadDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'r')
}
func (fd *FD) SetWriteDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'w')
}
func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
d := t.Sub(time.Now())
if mode == 'r' || mode == 'r'+'w' {
fd.rtimedout.setFalse()
}
if mode == 'w' || mode == 'r'+'w' {
fd.wtimedout.setFalse()
}
if t.IsZero() || d < 0 {
// Stop timer
if mode == 'r' || mode == 'r'+'w' {
if fd.rtimer != nil {
fd.rtimer.Stop()
}
fd.rtimer = nil
}
if mode == 'w' || mode == 'r'+'w' {
if fd.wtimer != nil {
fd.wtimer.Stop()
}
fd.wtimer = nil
}
} else {
// Interrupt I/O operation once timer has expired
if mode == 'r' || mode == 'r'+'w' {
fd.rtimer = time.AfterFunc(d, func() {
fd.rtimedout.setTrue()
if fd.raio != nil {
fd.raio.Cancel()
}
})
}
if mode == 'w' || mode == 'r'+'w' {
fd.wtimer = time.AfterFunc(d, func() {
fd.wtimedout.setTrue()
if fd.waio != nil {
fd.waio.Cancel()
}
})
}
}
if !t.IsZero() && d < 0 {
// Interrupt current I/O operation
if mode == 'r' || mode == 'r'+'w' {
fd.rtimedout.setTrue()
if fd.raio != nil {
fd.raio.Cancel()
}
}
if mode == 'w' || mode == 'r'+'w' {
fd.wtimedout.setTrue()
if fd.waio != nil {
fd.waio.Cancel()
}
}
}
return nil
}
// On Plan 9 only, expose the locking for the net code.
func (fd *FD) ReadLock() error {
return fd.readLock()
}
func (fd *FD) ReadUnlock() {
fd.readUnlock()
}
func isHangup(err error) bool {
return err != nil && stringsHasSuffix(err.Error(), "Hangup")
}
func isInterrupted(err error) bool {
return err != nil && stringsHasSuffix(err.Error(), "interrupted")
}
......@@ -2,34 +2,32 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
package poll
import (
"runtime"
"syscall"
"time"
)
type pollDesc struct {
fd *netFD
fd *FD
closing bool
}
func (pd *pollDesc) init(fd *netFD) error { pd.fd = fd; return nil }
func (pd *pollDesc) init(fd *FD) error { pd.fd = fd; return nil }
func (pd *pollDesc) close() {}
func (pd *pollDesc) evict() {
pd.closing = true
if pd.fd != nil {
syscall.StopIO(pd.fd.sysfd)
runtime.KeepAlive(pd.fd)
syscall.StopIO(pd.fd.Sysfd)
}
}
func (pd *pollDesc) prepare(mode int) error {
if pd.closing {
return errClosing
return ErrClosing
}
return nil
}
......@@ -40,9 +38,9 @@ func (pd *pollDesc) prepareWrite() error { return pd.prepare('w') }
func (pd *pollDesc) wait(mode int) error {
if pd.closing {
return errClosing
return ErrClosing
}
return errTimeout
return ErrTimeout
}
func (pd *pollDesc) waitRead() error { return pd.wait('r') }
......@@ -55,19 +53,19 @@ func (pd *pollDesc) waitCanceledRead() {}
func (pd *pollDesc) waitCanceledWrite() {}
func (fd *netFD) setDeadline(t time.Time) error {
func (fd *FD) SetDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'r'+'w')
}
func (fd *netFD) setReadDeadline(t time.Time) error {
func (fd *FD) SetReadDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'r')
}
func (fd *netFD) setWriteDeadline(t time.Time) error {
func (fd *FD) SetWriteDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'w')
}
func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
d := t.UnixNano()
if t.IsZero() {
d = 0
......@@ -77,12 +75,12 @@ func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
}
switch mode {
case 'r':
syscall.SetReadDeadline(fd.sysfd, d)
syscall.SetReadDeadline(fd.Sysfd, d)
case 'w':
syscall.SetWriteDeadline(fd.sysfd, d)
syscall.SetWriteDeadline(fd.Sysfd, d)
case 'r' + 'w':
syscall.SetReadDeadline(fd.sysfd, d)
syscall.SetWriteDeadline(fd.sysfd, d)
syscall.SetReadDeadline(fd.Sysfd, d)
syscall.SetWriteDeadline(fd.Sysfd, d)
}
fd.decref()
return nil
......
......@@ -4,10 +4,10 @@
// +build darwin dragonfly freebsd linux netbsd openbsd windows solaris
package net
package poll
import (
"runtime"
"errors"
"sync"
"syscall"
"time"
......@@ -31,11 +31,14 @@ type pollDesc struct {
var serverInit sync.Once
func (pd *pollDesc) init(fd *netFD) error {
func (pd *pollDesc) init(fd *FD) error {
serverInit.Do(runtime_pollServerInit)
ctx, errno := runtime_pollOpen(uintptr(fd.sysfd))
runtime.KeepAlive(fd)
ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd))
if errno != 0 {
if ctx != 0 {
runtime_pollUnblock(ctx)
runtime_pollClose(ctx)
}
return syscall.Errno(errno)
}
pd.runtimeCtx = ctx
......@@ -59,6 +62,9 @@ func (pd *pollDesc) evict() {
}
func (pd *pollDesc) prepare(mode int) error {
if pd.runtimeCtx == 0 {
return nil
}
res := runtime_pollReset(pd.runtimeCtx, mode)
return convertErr(res)
}
......@@ -72,6 +78,9 @@ func (pd *pollDesc) prepareWrite() error {
}
func (pd *pollDesc) wait(mode int) error {
if pd.runtimeCtx == 0 {
return errors.New("waiting for unsupported file type")
}
res := runtime_pollWait(pd.runtimeCtx, mode)
return convertErr(res)
}
......@@ -85,6 +94,9 @@ func (pd *pollDesc) waitWrite() error {
}
func (pd *pollDesc) waitCanceled(mode int) {
if pd.runtimeCtx == 0 {
return
}
runtime_pollWaitCanceled(pd.runtimeCtx, mode)
}
......@@ -101,27 +113,27 @@ func convertErr(res int) error {
case 0:
return nil
case 1:
return errClosing
return ErrClosing
case 2:
return errTimeout
return ErrTimeout
}
println("unreachable: ", res)
panic("unreachable")
}
func (fd *netFD) setDeadline(t time.Time) error {
func (fd *FD) SetDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'r'+'w')
}
func (fd *netFD) setReadDeadline(t time.Time) error {
func (fd *FD) SetReadDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'r')
}
func (fd *netFD) setWriteDeadline(t time.Time) error {
func (fd *FD) SetWriteDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'w')
}
func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
diff := int64(time.Until(t))
d := runtimeNano() + diff
if d <= 0 && diff > 0 {
......@@ -135,6 +147,9 @@ func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
if err := fd.incref(); err != nil {
return err
}
if fd.pd.runtimeCtx == 0 {
return errors.New("file type does not support deadlines")
}
runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode)
fd.decref()
return nil
......
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package poll
import (
"io"
"syscall"
)
// eofError returns io.EOF when fd is available for reading end of
// file.
func (fd *FD) eofError(n int, err error) error {
if n == 0 && err == nil && fd.ZeroReadIsEOF {
return io.EOF
}
return err
}
// Fchmod wraps syscall.Fchmod.
func (fd *FD) Fchmod(mode uint32) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.Fchmod(fd.Sysfd, mode)
}
// Fchown wraps syscall.Fchown.
func (fd *FD) Fchown(uid, gid int) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.Fchown(fd.Sysfd, uid, gid)
}
// Ftruncate wraps syscall.Ftruncate.
func (fd *FD) Ftruncate(size int64) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.Ftruncate(fd.Sysfd, size)
}
// Fsync wraps syscall.Fsync.
func (fd *FD) Fsync() error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.Fsync(fd.Sysfd)
}
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package poll_test
import (
. "internal/poll"
"io"
"testing"
)
var eofErrorTests = []struct {
n int
err error
fd *FD
expected error
}{
{100, nil, &FD{ZeroReadIsEOF: true}, nil},
{100, io.EOF, &FD{ZeroReadIsEOF: true}, io.EOF},
{100, ErrClosing, &FD{ZeroReadIsEOF: true}, ErrClosing},
{0, nil, &FD{ZeroReadIsEOF: true}, io.EOF},
{0, io.EOF, &FD{ZeroReadIsEOF: true}, io.EOF},
{0, ErrClosing, &FD{ZeroReadIsEOF: true}, ErrClosing},
{100, nil, &FD{ZeroReadIsEOF: false}, nil},
{100, io.EOF, &FD{ZeroReadIsEOF: false}, io.EOF},
{100, ErrClosing, &FD{ZeroReadIsEOF: false}, ErrClosing},
{0, nil, &FD{ZeroReadIsEOF: false}, nil},
{0, io.EOF, &FD{ZeroReadIsEOF: false}, io.EOF},
{0, ErrClosing, &FD{ZeroReadIsEOF: false}, ErrClosing},
}
func TestEOFError(t *testing.T) {
for _, tt := range eofErrorTests {
actual := tt.fd.EOFError(tt.n, tt.err)
if actual != tt.expected {
t.Errorf("eofError(%v, %v, %v): expected %v, actual %v", tt.n, tt.err, tt.fd.ZeroReadIsEOF, tt.expected, actual)
}
}
}
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package poll
import (
"io"
"syscall"
)
// FD is a file descriptor. The net and os packages use this type as a
// field of a larger type representing a network connection or OS file.
type FD struct {
// Lock sysfd and serialize access to Read and Write methods.
fdmu fdMutex
// System file descriptor. Immutable until Close.
Sysfd int
// I/O poller.
pd pollDesc
// Writev cache.
iovecs *[]syscall.Iovec
// Whether this is a streaming descriptor, as opposed to a
// packet-based descriptor like a UDP socket. Immutable.
IsStream bool
// Whether a zero byte read indicates EOF. This is false for a
// message based socket connection.
ZeroReadIsEOF bool
}
// Init initializes the FD. The Sysfd field should already be set.
// This can be called multiple times on a single FD.
func (fd *FD) Init() error {
return fd.pd.init(fd)
}
// Destroy closes the file descriptor. This is called when there are
// no remaining references.
func (fd *FD) destroy() error {
// Poller may want to unregister fd in readiness notification mechanism,
// so this must be executed before CloseFunc.
fd.pd.close()
err := CloseFunc(fd.Sysfd)
fd.Sysfd = -1
return err
}
// Close closes the FD. The underlying file descriptor is closed by the
// destroy method when there are no remaining references.
func (fd *FD) Close() error {
if !fd.fdmu.increfAndClose() {
return ErrClosing
}
// Unblock any I/O. Once it all unblocks and returns,
// so that it cannot be referring to fd.sysfd anymore,
// the final decref will close fd.sysfd. This should happen
// fairly quickly, since all the I/O is non-blocking, and any
// attempts to block in the pollDesc will return ErrClosing.
fd.pd.evict()
// The call to decref will call destroy if there are no other
// references.
return fd.decref()
}
// Shutdown wraps the shutdown call.
func (fd *FD) Shutdown(how int) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.Shutdown(fd.Sysfd, how)
}
// Darwin and FreeBSD can't read or write 2GB+ files at a time,
// even on 64-bit systems.
// The same is true of socket implementations on many systems.
// See golang.org/issue/7812 and golang.org/issue/16266.
// Use 1GB instead of, say, 2GB-1, to keep subsequent reads aligned.
const maxRW = 1 << 30
// Read implements io.Reader.
func (fd *FD) Read(p []byte) (n int, err error) {
if err := fd.readLock(); err != nil {
return 0, err
}
defer fd.readUnlock()
if len(p) == 0 {
// If the caller wanted a zero byte read, return immediately
// without trying (but after acquiring the readLock).
// Otherwise syscall.Read returns 0, nil which looks like
// io.EOF.
// TODO(bradfitz): make it wait for readability? (Issue 15735)
return 0, nil
}
if err := fd.pd.prepareRead(); err != nil {
return 0, err
}
if fd.IsStream && len(p) > maxRW {
p = p[:maxRW]
}
for {
n, err = syscall.Read(fd.Sysfd, p)
if err != nil {
n = 0
if err == syscall.EAGAIN {
if err = fd.pd.waitRead(); err == nil {
continue
}
}
}
err = fd.eofError(n, err)
break
}
return
}
// Pread wraps the pread system call.
func (fd *FD) Pread(p []byte, off int64) (n int, err error) {
if err := fd.readLock(); err != nil {
return 0, err
}
defer fd.readUnlock()
if err := fd.pd.prepareRead(); err != nil {
return 0, err
}
if fd.IsStream && len(p) > maxRW {
p = p[:maxRW]
}
for {
n, err = syscall.Pread(fd.Sysfd, p, off)
if err != nil {
n = 0
if err == syscall.EAGAIN {
if err = fd.pd.waitRead(); err == nil {
continue
}
}
}
err = fd.eofError(n, err)
break
}
return
}
// RecvFrom wraps the recvfrom network call.
func (fd *FD) RecvFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
if err := fd.readLock(); err != nil {
return 0, nil, err
}
defer fd.readUnlock()
if err := fd.pd.prepareRead(); err != nil {
return 0, nil, err
}
for {
n, sa, err = syscall.Recvfrom(fd.Sysfd, p, 0)
if err != nil {
n = 0
if err == syscall.EAGAIN {
if err = fd.pd.waitRead(); err == nil {
continue
}
}
}
err = fd.eofError(n, err)
break
}
return
}
// ReadMsg wraps the recvmsg network call.
func (fd *FD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
if err := fd.readLock(); err != nil {
return 0, 0, 0, nil, err
}
defer fd.readUnlock()
if err := fd.pd.prepareRead(); err != nil {
return 0, 0, 0, nil, err
}
for {
n, oobn, flags, sa, err = syscall.Recvmsg(fd.Sysfd, p, oob, 0)
if err != nil {
// TODO(dfc) should n and oobn be set to 0
if err == syscall.EAGAIN {
if err = fd.pd.waitRead(); err == nil {
continue
}
}
}
err = fd.eofError(n, err)
break
}
return
}
// Write implements io.Writer.
func (fd *FD) Write(p []byte) (nn int, err error) {
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
if err := fd.pd.prepareWrite(); err != nil {
return 0, err
}
for {
var n int
max := len(p)
if fd.IsStream && max-nn > maxRW {
max = nn + maxRW
}
n, err = syscall.Write(fd.Sysfd, p[nn:max])
if n > 0 {
nn += n
}
if nn == len(p) {
break
}
if err == syscall.EAGAIN {
if err = fd.pd.waitWrite(); err == nil {
continue
}
}
if err != nil {
break
}
if n == 0 {
err = io.ErrUnexpectedEOF
break
}
}
return
}
// Pwrite wraps the pwrite system call.
func (fd *FD) Pwrite(p []byte, off int64) (nn int, err error) {
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
if err := fd.pd.prepareWrite(); err != nil {
return 0, err
}
for {
var n int
max := len(p)
if fd.IsStream && max-nn > maxRW {
max = nn + maxRW
}
n, err = syscall.Pwrite(fd.Sysfd, p[nn:max], off+int64(nn))
if n > 0 {
nn += n
}
if nn == len(p) {
break
}
if err == syscall.EAGAIN {
if err = fd.pd.waitWrite(); err == nil {
continue
}
}
if err != nil {
break
}
if n == 0 {
err = io.ErrUnexpectedEOF
break
}
}
return
}
// WriteTo wraps the sendto network call.
func (fd *FD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
if err := fd.pd.prepareWrite(); err != nil {
return 0, err
}
for {
err = syscall.Sendto(fd.Sysfd, p, 0, sa)
if err == syscall.EAGAIN {
if err = fd.pd.waitWrite(); err == nil {
continue
}
}
break
}
if err == nil {
n = len(p)
}
return
}
// WriteMsg wraps the sendmsg network call.
func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
if err := fd.writeLock(); err != nil {
return 0, 0, err
}
defer fd.writeUnlock()
if err := fd.pd.prepareWrite(); err != nil {
return 0, 0, err
}
for {
n, err = syscall.SendmsgN(fd.Sysfd, p, oob, sa, 0)
if err == syscall.EAGAIN {
if err = fd.pd.waitWrite(); err == nil {
continue
}
}
break
}
if err == nil {
oobn = len(oob)
}
return
}
// WaitWrite waits until data can be written to fd.
func (fd *FD) WaitWrite() error {
return fd.pd.waitWrite()
}
// Accept wraps the accept network call.
func (fd *FD) Accept() (newfd int, rsa syscall.Sockaddr, errcall string, err error) {
if err = fd.readLock(); err != nil {
return -1, nil, "", err
}
defer fd.readUnlock()
var s int
if err = fd.pd.prepareRead(); err != nil {
return -1, nil, "", err
}
for {
s, rsa, errcall, err = accept(fd.Sysfd)
if err == nil {
return s, rsa, "", err
}
switch err {
case syscall.EAGAIN:
if err = fd.pd.waitRead(); err == nil {
continue
}
case syscall.ECONNABORTED:
// This means that a socket on the listen
// queue was closed before we Accept()ed it;
// it's a silly error, so try again.
continue
}
return -1, nil, errcall, err
}
}
// Seek wraps syscall.Seek.
func (fd *FD) Seek(offset int64, whence int) (ret int64, err error) {
if err := fd.incref(); err != nil {
return 0, err
}
defer fd.decref()
return syscall.Seek(fd.Sysfd, offset, whence)
}
// ReadDirent wraps syscall.ReadDirent.
// We treat this like an ordinary system call rather than a call
// that tries to fill the buffer.
func (fd *FD) ReadDirent(buf []byte) (n int, err error) {
if err := fd.incref(); err != nil {
return 0, err
}
defer fd.decref()
return syscall.ReadDirent(fd.Sysfd, buf)
}
// Fchdir wraps syscall.Fchdir.
func (fd *FD) Fchdir() error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.Fchdir(fd.Sysfd)
}
// Fstat wraps syscall.Fstat
func (fd *FD) Fstat(s *syscall.Stat_t) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.Fstat(fd.Sysfd, s)
}
This diff is collapsed.
......@@ -4,11 +4,9 @@
// +build freebsd linux
package net
package poll
import "syscall"
var (
// Placeholders for socket system calls.
accept4Func func(int, int) (int, syscall.Sockaddr, error) = syscall.Accept4
)
// Accept4Func is used to hook the accept4 call.
var Accept4Func func(int, int) (int, syscall.Sockaddr, error) = syscall.Accept4
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package poll
import (
"syscall"
)
// CloseFunc is used to hook the close call.
var CloseFunc func(int) error = syscall.Close
// AcceptFunc is used to hook the accept call.
var AcceptFunc func(int) (int, syscall.Sockaddr, error) = syscall.Accept
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package poll
import (
"syscall"
)
// CloseFunc is used to hook the close call.
var CloseFunc func(syscall.Handle) error = syscall.Closesocket
// AcceptFunc is used to hook the accept call.
var AcceptFunc func(syscall.Handle, syscall.Handle, *byte, uint32, uint32, uint32, *uint32, *syscall.Overlapped) error = syscall.AcceptEx
// ConnectExFunc is used to hook the ConnectEx call.
var ConnectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build dragonfly freebsd
package poll
import "syscall"
// maxSendfileSize is the largest chunk size we ask the kernel to copy
// at a time.
const maxSendfileSize int = 4 << 20
// SendFile wraps the sendfile system call.
func SendFile(dstFD *FD, src int, pos, remain int64) (written int64, err error) {
if err := dstFD.writeLock(); err != nil {
return 0, err
}
defer dstFD.writeUnlock()
dst := int(dstFD.Sysfd)
for remain > 0 {
n := maxSendfileSize
if int64(n) > remain {
n = int(remain)
}
pos1 := pos
n, err1 := syscall.Sendfile(dst, src, &pos1, n)
if n > 0 {
pos += int64(n)
written += int64(n)
remain -= int64(n)
}
if n == 0 && err1 == nil {
break
}
if err1 == syscall.EAGAIN {
if err1 = dstFD.pd.waitWrite(); err1 == nil {
continue
}
}
if err1 != nil {
// This includes syscall.ENOSYS (no kernel
// support) and syscall.EINVAL (fd types which
// don't implement sendfile)
err = err1
break
}
}
return written, err
}
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package poll
import "syscall"
// maxSendfileSize is the largest chunk size we ask the kernel to copy
// at a time.
const maxSendfileSize int = 4 << 20
// SendFile wraps the sendfile system call.
func SendFile(dstFD *FD, src int, remain int64) (written int64, err error) {
if err := dstFD.writeLock(); err != nil {
return 0, err
}
defer dstFD.writeUnlock()
dst := int(dstFD.Sysfd)
for remain > 0 {
n := maxSendfileSize
if int64(n) > remain {
n = int(remain)
}
n, err1 := syscall.Sendfile(dst, src, nil, n)
if n > 0 {
written += int64(n)
remain -= int64(n)
}
if n == 0 && err1 == nil {
break
}
if err1 == syscall.EAGAIN {
if err1 = dstFD.pd.waitWrite(); err1 == nil {
continue
}
}
if err1 != nil {
// This includes syscall.ENOSYS (no kernel
// support) and syscall.EINVAL (fd types which
// don't implement sendfile)
err = err1
break
}
}
return written, err
}
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package poll
import "syscall"
// Not strictly needed, but very helpful for debugging, see issue #10221.
//go:cgo_import_dynamic _ _ "libsendfile.so"
//go:cgo_import_dynamic _ _ "libsocket.so"
// maxSendfileSize is the largest chunk size we ask the kernel to copy
// at a time.
const maxSendfileSize int = 4 << 20
// SendFile wraps the sendfile system call.
func SendFile(dstFD *FD, src int, pos, remain int64) (written int64, err error) {
if err := dstFD.writeLock(); err != nil {
return 0, err
}
defer dstFD.writeUnlock()
dst := int(dstFD.Sysfd)
for remain > 0 {
n := maxSendfileSize
if int64(n) > remain {
n = int(remain)
}
pos1 := pos
n, err1 := syscall.Sendfile(dst, src, &pos1, n)
if err1 == syscall.EAGAIN || err1 == syscall.EINTR {
// partial write may have occurred
if n = int(pos1 - pos); n == 0 {
// nothing more to write
err1 = nil
}
}
if n > 0 {
pos += int64(n)
written += int64(n)
remain -= int64(n)
}
if n == 0 && err1 == nil {
break
}
if err1 == syscall.EAGAIN {
if err1 = dstFD.pd.waitWrite(); err1 == nil {
continue
}
}
if err1 == syscall.EINTR {
continue
}
if err1 != nil {
// This includes syscall.ENOSYS (no kernel
// support) and syscall.EINVAL (fd types which
// don't implement sendfile)
err = err1
break
}
}
return written, err
}
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package poll
import "syscall"
// SendFile wraps the TransmitFile call.
func SendFile(fd *FD, src syscall.Handle, n int64) (int64, error) {
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
o := &fd.wop
o.qty = uint32(n)
o.handle = src
done, err := wsrv.ExecIO(o, "TransmitFile", func(o *operation) error {
return syscall.TransmitFile(o.fd.Sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
})
return int64(done), err
}
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file implements sysSocket and accept for platforms that
// provide a fast path for setting SetNonblock and CloseOnExec.
// +build freebsd linux
package poll
import (
"syscall"
)
// Wrapper around the accept system call that marks the returned file
// descriptor as nonblocking and close-on-exec.
func accept(s int) (int, syscall.Sockaddr, string, error) {
ns, sa, err := Accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
// On Linux the accept4 system call was introduced in 2.6.28
// kernel and on FreeBSD it was introduced in 10 kernel. If we
// get an ENOSYS error on both Linux and FreeBSD, or EINVAL
// error on Linux, fall back to using accept.
switch err {
case nil:
return ns, sa, "", nil
default: // errors other than the ones listed
return -1, sa, "accept4", err
case syscall.ENOSYS: // syscall missing
case syscall.EINVAL: // some Linux use this instead of ENOSYS
case syscall.EACCES: // some Linux use this instead of ENOSYS
case syscall.EFAULT: // some Linux use this instead of ENOSYS
}
// See ../syscall/exec_unix.go for description of ForkLock.
// It is probably okay to hold the lock across syscall.Accept
// because we have put fd.sysfd into non-blocking mode.
// However, a call to the File method will put it back into
// blocking mode. We can't take that risk, so no use of ForkLock here.
ns, sa, err = AcceptFunc(s)
if err == nil {
syscall.CloseOnExec(ns)
}
if err != nil {
return -1, nil, "accept", err
}
if err = syscall.SetNonblock(ns, true); err != nil {
CloseFunc(ns)
return -1, nil, "setnonblock", err
}
return ns, sa, "", nil
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package poll
import (
"syscall"
)
// SetsockoptInt wraps the setsockopt network call with an int argument.
func (fd *FD) SetsockoptInt(level, name, arg int) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.SetsockoptInt(fd.Sysfd, level, name, arg)
}
// SetsockoptInet4Addr wraps the setsockopt network call with an IPv4 address.
func (fd *FD) SetsockoptInet4Addr(level, name int, arg [4]byte) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.SetsockoptInet4Addr(fd.Sysfd, level, name, arg)
}
// SetsockoptLinger wraps the setsockopt network call with a Linger argument.
func (fd *FD) SetsockoptLinger(level, name int, l *syscall.Linger) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.SetsockoptLinger(fd.Sysfd, level, name, l)
}
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package poll
import (
"syscall"
)
// SetsockoptIPMreqn wraps the setsockopt network call with a IPMreqn argument.
func (fd *FD) SetsockoptIPMreqn(level, name int, mreq *syscall.IPMreqn) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.SetsockoptIPMreqn(fd.Sysfd, level, name, mreq)
}
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package poll
import "syscall"
// SetsockoptByte wraps the setsockopt network call with a byte argument.
func (fd *FD) SetsockoptByte(level, name int, arg byte) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.SetsockoptByte(fd.Sysfd, level, name, arg)
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package poll
import (
"syscall"
)
// Setsockopt wraps the Windows setsockopt network call.
func (fd *FD) Setsockopt(level, optname int32, optval *byte, optlen int32) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.Setsockopt(fd.Sysfd, level, optname, optval, optlen)
}
// WSAIoctl wraps the Windows WSAIoctl call.
func (fd *FD) WSAIoctl(iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *syscall.Overlapped, completionRoutine uintptr) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.WSAIoctl(fd.Sysfd, iocc, inbuf, cbif, outbuf, cbob, cbbr, overlapped, completionRoutine)
}
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd windows
package poll
import "syscall"
// SetsockoptIPMreq wraps the setsockopt network call with a IPMreq argument.
func (fd *FD) SetsockoptIPMreq(level, name int, mreq *syscall.IPMreq) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.SetsockoptIPMreq(fd.Sysfd, level, name, mreq)
}
// SetsockoptIPv6Mreq wraps the setsockopt network call with a IPv6Mreq argument.
func (fd *FD) SetsockoptIPv6Mreq(level, name int, mreq *syscall.IPv6Mreq) error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.SetsockoptIPv6Mreq(fd.Sysfd, level, name, mreq)
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Simple conversions to avoid depending on strconv.
package poll
// Convert integer to decimal string
func itoa(val int) string {
if val < 0 {
return "-" + uitoa(uint(-val))
}
return uitoa(uint(val))
}
// Convert unsigned integer to decimal string
func uitoa(val uint) string {
if val == 0 { // avoid string allocation
return "0"
}
var buf [20]byte // big enough for 64bit value base 10
i := len(buf) - 1
for val >= 10 {
q := val / 10
buf[i] = byte('0' + val - q*10)
i--
val = q
}
// val < 10
buf[i] = byte('0' + val)
return string(buf[i:])
}
// stringsHasSuffix is strings.HasSuffix. It reports whether s ends in
// suffix.
func stringsHasSuffix(s, suffix string) bool {
return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
}
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file implements sysSocket and accept for platforms that do not
// provide a fast path for setting SetNonblock and CloseOnExec.
// +build darwin dragonfly nacl netbsd openbsd solaris
package poll
import (
"syscall"
)
// Wrapper around the accept system call that marks the returned file
// descriptor as nonblocking and close-on-exec.
func accept(s int) (int, syscall.Sockaddr, string, error) {
// See ../syscall/exec_unix.go for description of ForkLock.
// It is probably okay to hold the lock across syscall.Accept
// because we have put fd.sysfd into non-blocking mode.
// However, a call to the File method will put it back into
// blocking mode. We can't take that risk, so no use of ForkLock here.
ns, sa, err := AcceptFunc(s)
if err == nil {
syscall.CloseOnExec(ns)
}
if err != nil {
return -1, nil, "accept", err
}
if err = syscall.SetNonblock(ns, true); err != nil {
CloseFunc(ns)
return -1, nil, "setnonblock", err
}
return ns, sa, "", nil
}
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd
package poll
import (
"io"
"syscall"
"unsafe"
)
// Writev wraps the writev system call.
func (fd *FD) Writev(v *[][]byte) (n int64, err error) {
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
if err := fd.pd.prepareWrite(); err != nil {
return 0, err
}
var iovecs []syscall.Iovec
if fd.iovecs != nil {
iovecs = *fd.iovecs
}
// TODO: read from sysconf(_SC_IOV_MAX)? The Linux default is
// 1024 and this seems conservative enough for now. Darwin's
// UIO_MAXIOV also seems to be 1024.
maxVec := 1024
for len(*v) > 0 {
iovecs = iovecs[:0]
for _, chunk := range *v {
if len(chunk) == 0 {
continue
}
iovecs = append(iovecs, syscall.Iovec{Base: &chunk[0]})
if fd.IsStream && len(chunk) > 1<<30 {
iovecs[len(iovecs)-1].SetLen(1 << 30)
break // continue chunk on next writev
}
iovecs[len(iovecs)-1].SetLen(len(chunk))
if len(iovecs) == maxVec {
break
}
}
if len(iovecs) == 0 {
break
}
fd.iovecs = &iovecs // cache
wrote, _, e0 := syscall.Syscall(syscall.SYS_WRITEV,
uintptr(fd.Sysfd),
uintptr(unsafe.Pointer(&iovecs[0])),
uintptr(len(iovecs)))
if wrote == ^uintptr(0) {
wrote = 0
}
TestHookDidWritev(int(wrote))
n += int64(wrote)
consume(v, int64(wrote))
if e0 == syscall.EAGAIN {
if err = fd.pd.waitWrite(); err == nil {
continue
}
} else if e0 != 0 {
err = syscall.Errno(e0)
}
if err != nil {
break
}
if n == 0 {
err = io.ErrUnexpectedEOF
break
}
}
return n, err
}
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package poll_test
import (
"internal/poll"
"reflect"
"testing"
)
func TestConsume(t *testing.T) {
tests := []struct {
in [][]byte
consume int64
want [][]byte
}{
{
in: [][]byte{[]byte("foo"), []byte("bar")},
consume: 0,
want: [][]byte{[]byte("foo"), []byte("bar")},
},
{
in: [][]byte{[]byte("foo"), []byte("bar")},
consume: 2,
want: [][]byte{[]byte("o"), []byte("bar")},
},
{
in: [][]byte{[]byte("foo"), []byte("bar")},
consume: 3,
want: [][]byte{[]byte("bar")},
},
{
in: [][]byte{[]byte("foo"), []byte("bar")},
consume: 4,
want: [][]byte{[]byte("ar")},
},
{
in: [][]byte{nil, nil, nil, []byte("bar")},
consume: 1,
want: [][]byte{[]byte("ar")},
},
{
in: [][]byte{nil, nil, nil, []byte("foo")},
consume: 0,
want: [][]byte{[]byte("foo")},
},
{
in: [][]byte{nil, nil, nil},
consume: 0,
want: [][]byte{},
},
}
for i, tt := range tests {
in := tt.in
poll.Consume(&in, tt.consume)
if !reflect.DeepEqual(in, tt.want) {
t.Errorf("%d. after consume(%d) = %+v, want %+v", i, tt.consume, in, tt.want)
}
}
}
......@@ -7,6 +7,7 @@ package net
import (
"context"
"internal/nettrace"
"internal/poll"
"time"
)
......@@ -110,7 +111,7 @@ func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, er
}
timeRemaining := deadline.Sub(now)
if timeRemaining <= 0 {
return time.Time{}, errTimeout
return time.Time{}, poll.ErrTimeout
}
// Tentatively allocate equal time to each remaining address.
timeout := timeRemaining / time.Duration(addrsRemaining)
......
......@@ -7,6 +7,7 @@ package net
import (
"bufio"
"context"
"internal/poll"
"internal/testenv"
"io"
"net/internal/socktest"
......@@ -94,7 +95,7 @@ func TestDialTimeoutFDLeak(t *testing.T) {
default:
sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
time.Sleep(2 * T)
return nil, errTimeout
return nil, poll.ErrTimeout
})
defer sw.Set(socktest.FilterConnect, nil)
}
......@@ -585,8 +586,8 @@ func TestDialerPartialDeadline(t *testing.T) {
{now, noDeadline, 1, noDeadline, nil},
// Step the clock forward and cross the deadline.
{now.Add(-1 * time.Millisecond), now, 1, now, nil},
{now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout},
{now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout},
{now.Add(0 * time.Millisecond), now, 1, noDeadline, poll.ErrTimeout},
{now.Add(1 * time.Millisecond), now, 1, noDeadline, poll.ErrTimeout},
}
for i, tt := range testCases {
deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs)
......
......@@ -9,6 +9,7 @@ package net
import (
"context"
"fmt"
"internal/poll"
"internal/testenv"
"io/ioutil"
"os"
......@@ -767,7 +768,7 @@ func TestRetryTimeout(t *testing.T) {
if s == "192.0.2.1:53" {
deadline0 = deadline
time.Sleep(10 * time.Millisecond)
return nil, errTimeout
return nil, poll.ErrTimeout
}
if deadline == deadline0 {
......
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......@@ -7,15 +7,15 @@
package net
import (
"io"
"os"
"syscall"
)
// eofError returns io.EOF when fd is available for reading end of
// file.
func (fd *netFD) eofError(n int, err error) error {
if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM && fd.sotype != syscall.SOCK_RAW {
return io.EOF
// wrapSyscallError takes an error and a syscall name. If the error is
// a syscall.Errno, it wraps it in a os.SyscallError using the syscall name.
func wrapSyscallError(name string, err error) error {
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError(name, err)
}
return err
}
......@@ -7,6 +7,7 @@ package net
import (
"context"
"fmt"
"internal/poll"
"io"
"io/ioutil"
"net/internal/socktest"
......@@ -87,7 +88,7 @@ second:
return nil
}
switch err := nestedErr.(type) {
case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *poll.TimeoutError, UnknownNetworkError:
return nil
case *os.SyscallError:
nestedErr = err.Err
......@@ -97,7 +98,7 @@ second:
goto third
}
switch nestedErr {
case errCanceled, errClosing, errMissingAddress, errNoSuitableAddress,
case errCanceled, poll.ErrClosing, errMissingAddress, errNoSuitableAddress,
context.DeadlineExceeded, context.Canceled:
return nil
}
......@@ -432,7 +433,7 @@ second:
goto third
}
switch nestedErr {
case errClosing, errTimeout:
case poll.ErrClosing, poll.ErrTimeout:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
......@@ -467,14 +468,14 @@ second:
return nil
}
switch err := nestedErr.(type) {
case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *poll.TimeoutError, UnknownNetworkError:
return nil
case *os.SyscallError:
nestedErr = err.Err
goto third
}
switch nestedErr {
case errCanceled, errClosing, errMissingAddress, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
case errCanceled, poll.ErrClosing, errMissingAddress, poll.ErrTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
......@@ -517,7 +518,7 @@ second:
goto third
}
switch nestedErr {
case errClosing:
case poll.ErrClosing:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
......@@ -613,7 +614,7 @@ second:
goto third
}
switch nestedErr {
case errClosing, errTimeout:
case poll.ErrClosing, poll.ErrTimeout:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
......@@ -692,7 +693,7 @@ second:
goto third
}
switch nestedErr {
case errClosing:
case poll.ErrClosing:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
......
......@@ -5,23 +5,15 @@
package net
import (
"internal/poll"
"io"
"os"
"sync/atomic"
"syscall"
"time"
)
type atomicBool int32
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
// Network file descriptor.
type netFD struct {
// locking/lifetime of sysfd + serialize access to Read and Write methods
fdmu fdMutex
pfd poll.FD
// immutable until Close
net string
......@@ -30,14 +22,6 @@ type netFD struct {
listen, ctl, data *os.File
laddr, raddr Addr
isStream bool
// deadlines
raio *asyncIO
waio *asyncIO
rtimer *time.Timer
wtimer *time.Timer
rtimedout atomicBool // set true when read deadline has been reached
wtimedout atomicBool // set true when write deadline has been reached
}
var (
......@@ -49,7 +33,7 @@ func sysInit() {
}
func newFD(net, name string, listen, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
return &netFD{
ret := &netFD{
net: net,
n: name,
dir: netdir + "/" + net + "/" + name,
......@@ -57,7 +41,9 @@ func newFD(net, name string, listen, ctl, data *os.File, laddr, raddr Addr) (*ne
ctl: ctl, data: data,
laddr: laddr,
raddr: raddr,
}, nil
}
ret.pfd.Destroy = ret.destroy
return ret, nil
}
func (fd *netFD) init() error {
......@@ -99,28 +85,10 @@ func (fd *netFD) destroy() {
}
func (fd *netFD) Read(b []byte) (n int, err error) {
if fd.rtimedout.isSet() {
return 0, errTimeout
}
if !fd.ok() || fd.data == nil {
return 0, syscall.EINVAL
}
if err := fd.readLock(); err != nil {
return 0, err
}
defer fd.readUnlock()
if len(b) == 0 {
return 0, nil
}
fd.raio = newAsyncIO(fd.data.Read, b)
n, err = fd.raio.Wait()
fd.raio = nil
if isHangup(err) {
err = io.EOF
}
if isInterrupted(err) {
err = errTimeout
}
n, err = fd.pfd.Read(fd.data.Read, b)
if fd.net == "udp" && err == io.EOF {
n = 0
err = nil
......@@ -129,23 +97,10 @@ func (fd *netFD) Read(b []byte) (n int, err error) {
}
func (fd *netFD) Write(b []byte) (n int, err error) {
if fd.wtimedout.isSet() {
return 0, errTimeout
}
if !fd.ok() || fd.data == nil {
return 0, syscall.EINVAL
}
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
fd.waio = newAsyncIO(fd.data.Write, b)
n, err = fd.waio.Wait()
fd.waio = nil
if isInterrupted(err) {
err = errTimeout
}
return
return fd.pfd.Write(fd.data.Write, b)
}
func (fd *netFD) closeRead() error {
......@@ -163,8 +118,8 @@ func (fd *netFD) closeWrite() error {
}
func (fd *netFD) Close() error {
if !fd.fdmu.increfAndClose() {
return errClosing
if err := fd.pfd.Close(); err != nil {
return err
}
if !fd.ok() {
return syscall.EINVAL
......@@ -216,77 +171,6 @@ func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
return os.NewFile(uintptr(dfd), s), nil
}
func (fd *netFD) setDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'r'+'w')
}
func (fd *netFD) setReadDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'r')
}
func (fd *netFD) setWriteDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'w')
}
func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
d := t.Sub(time.Now())
if mode == 'r' || mode == 'r'+'w' {
fd.rtimedout.setFalse()
}
if mode == 'w' || mode == 'r'+'w' {
fd.wtimedout.setFalse()
}
if t.IsZero() || d < 0 {
// Stop timer
if mode == 'r' || mode == 'r'+'w' {
if fd.rtimer != nil {
fd.rtimer.Stop()
}
fd.rtimer = nil
}
if mode == 'w' || mode == 'r'+'w' {
if fd.wtimer != nil {
fd.wtimer.Stop()
}
fd.wtimer = nil
}
} else {
// Interrupt I/O operation once timer has expired
if mode == 'r' || mode == 'r'+'w' {
fd.rtimer = time.AfterFunc(d, func() {
fd.rtimedout.setTrue()
if fd.raio != nil {
fd.raio.Cancel()
}
})
}
if mode == 'w' || mode == 'r'+'w' {
fd.wtimer = time.AfterFunc(d, func() {
fd.wtimedout.setTrue()
if fd.waio != nil {
fd.waio.Cancel()
}
})
}
}
if !t.IsZero() && d < 0 {
// Interrupt current I/O operation
if mode == 'r' || mode == 'r'+'w' {
fd.rtimedout.setTrue()
if fd.raio != nil {
fd.raio.Cancel()
}
}
if mode == 'w' || mode == 'r'+'w' {
fd.wtimedout.setTrue()
if fd.waio != nil {
fd.waio.Cancel()
}
}
}
return nil
}
func setReadBuffer(fd *netFD, bytes int) error {
return syscall.EPLAN9
}
......@@ -294,11 +178,3 @@ func setReadBuffer(fd *netFD, bytes int) error {
func setWriteBuffer(fd *netFD, bytes int) error {
return syscall.EPLAN9
}
func isHangup(err error) bool {
return err != nil && stringsHasSuffix(err.Error(), "Hangup")
}
func isInterrupted(err error) bool {
return err != nil && stringsHasSuffix(err.Error(), "interrupted")
}
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
import (
"io"
"syscall"
"testing"
)
var eofErrorTests = []struct {
n int
err error
fd *netFD
expected error
}{
{100, nil, &netFD{sotype: syscall.SOCK_STREAM}, nil},
{100, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
{100, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing},
{0, nil, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
{0, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
{0, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing},
{100, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil},
{100, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF},
{100, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing},
{0, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil},
{0, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF},
{0, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing},
{100, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, nil},
{100, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
{100, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing},
{0, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
{0, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
{0, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing},
{100, nil, &netFD{sotype: syscall.SOCK_RAW}, nil},
{100, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF},
{100, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing},
{0, nil, &netFD{sotype: syscall.SOCK_RAW}, nil},
{0, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF},
{0, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing},
}
func TestEOFError(t *testing.T) {
for _, tt := range eofErrorTests {
actual := tt.fd.eofError(tt.n, tt.err)
if actual != tt.expected {
t.Errorf("eofError(%v, %v, %v): expected %v, actual %v", tt.n, tt.err, tt.fd.sotype, tt.expected, actual)
}
}
}
This diff is collapsed.
This diff is collapsed.
......@@ -7,6 +7,7 @@
package net
import (
"internal/poll"
"os"
"syscall"
)
......@@ -17,7 +18,7 @@ func dupSocket(f *os.File) (int, error) {
return -1, err
}
if err := syscall.SetNonblock(s, true); err != nil {
closeFunc(s)
poll.CloseFunc(s)
return -1, os.NewSyscallError("setnonblock", err)
}
return s, nil
......@@ -31,7 +32,7 @@ func newFileFD(f *os.File) (*netFD, error) {
family := syscall.AF_UNSPEC
sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE)
if err != nil {
closeFunc(s)
poll.CloseFunc(s)
return nil, os.NewSyscallError("getsockopt", err)
}
lsa, _ := syscall.Getsockname(s)
......@@ -44,12 +45,12 @@ func newFileFD(f *os.File) (*netFD, error) {
case *syscall.SockaddrUnix:
family = syscall.AF_UNIX
default:
closeFunc(s)
poll.CloseFunc(s)
return nil, syscall.EPROTONOSUPPORT
}
fd, err := newFD(s, family, sotype, "")
if err != nil {
closeFunc(s)
poll.CloseFunc(s)
return nil, err
}
laddr := fd.addrFunc()(lsa)
......
......@@ -13,10 +13,8 @@ var (
testHookCanceledDial = func() {} // for golang.org/issue/16523
// Placeholders for socket system calls.
socketFunc func(int, int, int) (int, error) = syscall.Socket
closeFunc func(int) error = syscall.Close
connectFunc func(int, syscall.Sockaddr) error = syscall.Connect
listenFunc func(int, int) error = syscall.Listen
acceptFunc func(int) (int, syscall.Sockaddr, error) = syscall.Accept
getsockoptIntFunc func(int, int, int) (int, error) = syscall.GetsockoptInt
socketFunc func(int, int, int) (int, error) = syscall.Socket
connectFunc func(int, syscall.Sockaddr) error = syscall.Connect
listenFunc func(int, int) error = syscall.Listen
getsockoptIntFunc func(int, int, int) (int, error) = syscall.GetsockoptInt
)
......@@ -13,10 +13,7 @@ var (
testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349
// Placeholders for socket system calls.
socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket
closeFunc func(syscall.Handle) error = syscall.Closesocket
connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect
connectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx
listenFunc func(syscall.Handle, int) error = syscall.Listen
acceptFunc func(syscall.Handle, syscall.Handle, *byte, uint32, uint32, uint32, *uint32, *syscall.Overlapped) error = syscall.AcceptEx
socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket
connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect
listenFunc func(syscall.Handle, int) error = syscall.Listen
)
......@@ -249,10 +249,10 @@ func (fd *netFD) netFD() (*netFD, error) {
func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
defer func() { fixErr(err) }()
if err := fd.readLock(); err != nil {
if err := fd.pfd.ReadLock(); err != nil {
return nil, err
}
defer fd.readUnlock()
defer fd.pfd.ReadUnlock()
listen, err := os.Open(fd.dir + "/listen")
if err != nil {
return nil, err
......
......@@ -8,6 +8,7 @@ package net
import (
"context"
"internal/poll"
"runtime"
"syscall"
)
......@@ -18,7 +19,7 @@ func probeIPv4Stack() bool {
case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT:
return false
case nil:
closeFunc(s)
poll.CloseFunc(s)
}
return true
}
......@@ -68,7 +69,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
if err != nil {
continue
}
defer closeFunc(s)
defer poll.CloseFunc(s)
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value)
sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6)
if err != nil {
......
......@@ -6,6 +6,8 @@
package net
import "internal/poll"
func init() {
extraTestHookInstallers = append(extraTestHookInstallers, installAccept4TestHook)
extraTestHookUninstallers = append(extraTestHookUninstallers, uninstallAccept4TestHook)
......@@ -13,13 +15,13 @@ func init() {
var (
// Placeholders for saving original socket system calls.
origAccept4 = accept4Func
origAccept4 = poll.Accept4Func
)
func installAccept4TestHook() {
accept4Func = sw.Accept4
poll.Accept4Func = sw.Accept4
}
func uninstallAccept4TestHook() {
accept4Func = origAccept4
poll.Accept4Func = origAccept4
}
......@@ -6,13 +6,15 @@
package net
import "internal/poll"
var (
// Placeholders for saving original socket system calls.
origSocket = socketFunc
origClose = closeFunc
origClose = poll.CloseFunc
origConnect = connectFunc
origListen = listenFunc
origAccept = acceptFunc
origAccept = poll.AcceptFunc
origGetsockoptInt = getsockoptIntFunc
extraTestHookInstallers []func()
......@@ -21,10 +23,10 @@ var (
func installTestHooks() {
socketFunc = sw.Socket
closeFunc = sw.Close
poll.CloseFunc = sw.Close
connectFunc = sw.Connect
listenFunc = sw.Listen
acceptFunc = sw.Accept
poll.AcceptFunc = sw.Accept
getsockoptIntFunc = sw.GetsockoptInt
for _, fn := range extraTestHookInstallers {
......@@ -34,10 +36,10 @@ func installTestHooks() {
func uninstallTestHooks() {
socketFunc = origSocket
closeFunc = origClose
poll.CloseFunc = origClose
connectFunc = origConnect
listenFunc = origListen
acceptFunc = origAccept
poll.AcceptFunc = origAccept
getsockoptIntFunc = origGetsockoptInt
for _, fn := range extraTestHookUninstallers {
......@@ -48,6 +50,6 @@ func uninstallTestHooks() {
// forceCloseSockets must be called only from TestMain.
func forceCloseSockets() {
for s := range sw.Sockets() {
closeFunc(s)
poll.CloseFunc(s)
}
}
......@@ -4,37 +4,39 @@
package net
import "internal/poll"
var (
// Placeholders for saving original socket system calls.
origSocket = socketFunc
origClosesocket = closeFunc
origClosesocket = poll.CloseFunc
origConnect = connectFunc
origConnectEx = connectExFunc
origConnectEx = poll.ConnectExFunc
origListen = listenFunc
origAccept = acceptFunc
origAccept = poll.AcceptFunc
)
func installTestHooks() {
socketFunc = sw.Socket
closeFunc = sw.Closesocket
poll.CloseFunc = sw.Closesocket
connectFunc = sw.Connect
connectExFunc = sw.ConnectEx
poll.ConnectExFunc = sw.ConnectEx
listenFunc = sw.Listen
acceptFunc = sw.AcceptEx
poll.AcceptFunc = sw.AcceptEx
}
func uninstallTestHooks() {
socketFunc = origSocket
closeFunc = origClosesocket
poll.CloseFunc = origClosesocket
connectFunc = origConnect
connectExFunc = origConnectEx
poll.ConnectExFunc = origConnectEx
listenFunc = origListen
acceptFunc = origAccept
poll.AcceptFunc = origAccept
}
// forceCloseSockets must be called only from TestMain.
func forceCloseSockets() {
for s := range sw.Sockets() {
closeFunc(s)
poll.CloseFunc(s)
}
}
......@@ -81,6 +81,7 @@ package net
import (
"context"
"errors"
"internal/poll"
"io"
"os"
"syscall"
......@@ -234,7 +235,7 @@ func (c *conn) SetDeadline(t time.Time) error {
if !c.ok() {
return syscall.EINVAL
}
if err := c.fd.setDeadline(t); err != nil {
if err := c.fd.pfd.SetDeadline(t); err != nil {
return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
}
return nil
......@@ -245,7 +246,7 @@ func (c *conn) SetReadDeadline(t time.Time) error {
if !c.ok() {
return syscall.EINVAL
}
if err := c.fd.setReadDeadline(t); err != nil {
if err := c.fd.pfd.SetReadDeadline(t); err != nil {
return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
}
return nil
......@@ -256,7 +257,7 @@ func (c *conn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
return syscall.EINVAL
}
if err := c.fd.setWriteDeadline(t); err != nil {
if err := c.fd.pfd.SetWriteDeadline(t); err != nil {
return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
}
return nil
......@@ -391,10 +392,8 @@ var (
errMissingAddress = errors.New("missing address")
// For both read and write operations.
errTimeout error = &timeoutError{}
errCanceled = errors.New("operation was canceled")
errClosing = errors.New("use of closed network connection")
ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
errCanceled = errors.New("operation was canceled")
ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
)
// mapErr maps from the context errors to the historical internal net
......@@ -407,7 +406,7 @@ func mapErr(err error) error {
case context.Canceled:
return errCanceled
case context.DeadlineExceeded:
return errTimeout
return poll.ErrTimeout
default:
return err
}
......@@ -502,12 +501,6 @@ func (e *OpError) Temporary() bool {
return ok && t.Temporary()
}
type timeoutError struct{}
func (e *timeoutError) Error() string { return "i/o timeout" }
func (e *timeoutError) Timeout() bool { return true }
func (e *timeoutError) Temporary() bool { return true }
// A ParseError is the error type of literal network address parsers.
type ParseError struct {
// Type is the type of string that was expected, such as
......@@ -632,8 +625,6 @@ type buffersWriter interface {
writeBuffers(*Buffers) (int64, error)
}
var testHookDidWritev = func(wrote int) {}
// Buffers contains zero or more runs of bytes to write.
//
// On certain machines, for certain types of connections, this is
......
......@@ -7,15 +7,11 @@
package net
import (
"internal/poll"
"io"
"os"
"syscall"
)
// maxSendfileSize is the largest chunk size we ask the kernel to copy
// at a time.
const maxSendfileSize int = 4 << 20
// sendFile copies the contents of r to c using the sendfile
// system call to minimize copies.
//
......@@ -62,49 +58,10 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
return 0, err, false
}
if err := c.writeLock(); err != nil {
return 0, err, true
}
defer c.writeUnlock()
written, err = poll.SendFile(&c.pfd, int(f.Fd()), pos, remain)
dst := c.sysfd
src := int(f.Fd())
for remain > 0 {
n := maxSendfileSize
if int64(n) > remain {
n = int(remain)
}
pos1 := pos
n, err1 := syscall.Sendfile(dst, src, &pos1, n)
if n > 0 {
pos += int64(n)
written += int64(n)
remain -= int64(n)
}
if n == 0 && err1 == nil {
break
}
if err1 == syscall.EAGAIN {
if err1 = c.pd.waitWrite(); err1 == nil {
continue
}
}
if err1 == syscall.EINTR {
continue
}
if err1 != nil {
// This includes syscall.ENOSYS (no kernel
// support) and syscall.EINVAL (fd types which
// don't implement sendfile)
err = err1
break
}
}
if lr != nil {
lr.N = remain
}
if err != nil {
err = os.NewSyscallError("sendfile", err)
lr.N = remain - written
}
return written, err, written > 0
return written, wrapSyscallError("sendfile", err), written > 0
}
......@@ -5,15 +5,11 @@
package net
import (
"internal/poll"
"io"
"os"
"syscall"
)
// maxSendfileSize is the largest chunk size we ask the kernel to copy
// at a time.
const maxSendfileSize int = 4 << 20
// sendFile copies the contents of r to c using the sendfile
// system call to minimize copies.
//
......@@ -36,44 +32,10 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
return 0, nil, false
}
if err := c.writeLock(); err != nil {
return 0, err, true
}
defer c.writeUnlock()
written, err = poll.SendFile(&c.pfd, int(f.Fd()), remain)
dst := c.sysfd
src := int(f.Fd())
for remain > 0 {
n := maxSendfileSize
if int64(n) > remain {
n = int(remain)
}
n, err1 := syscall.Sendfile(dst, src, nil, n)
if n > 0 {
written += int64(n)
remain -= int64(n)
}
if n == 0 && err1 == nil {
break
}
if err1 == syscall.EAGAIN {
if err1 = c.pd.waitWrite(); err1 == nil {
continue
}
}
if err1 != nil {
// This includes syscall.ENOSYS (no kernel
// support) and syscall.EINVAL (fd types which
// don't implement sendfile)
err = err1
break
}
}
if lr != nil {
lr.N = remain
}
if err != nil {
err = os.NewSyscallError("sendfile", err)
lr.N = remain - written
}
return written, err, written > 0
return written, wrapSyscallError("sendfile", err), written > 0
}
......@@ -5,19 +5,11 @@
package net
import (
"internal/poll"
"io"
"os"
"syscall"
)
// Not strictly needed, but very helpful for debugging, see issue #10221.
//go:cgo_import_dynamic _ _ "libsendfile.so"
//go:cgo_import_dynamic _ _ "libsocket.so"
// maxSendfileSize is the largest chunk size we ask the kernel to copy
// at a time.
const maxSendfileSize int = 4 << 20
// sendFile copies the contents of r to c using the sendfile
// system call to minimize copies.
//
......@@ -62,56 +54,10 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
return 0, err, false
}
if err := c.writeLock(); err != nil {
return 0, err, true
}
defer c.writeUnlock()
written, err = poll.SendFile(&c.pfd, int(f.Fd()), pos, remain)
dst := c.sysfd
src := int(f.Fd())
for remain > 0 {
n := maxSendfileSize
if int64(n) > remain {
n = int(remain)
}
pos1 := pos
n, err1 := syscall.Sendfile(dst, src, &pos1, n)
if err1 == syscall.EAGAIN || err1 == syscall.EINTR {
// partial write may have occurred
if n = int(pos1 - pos); n == 0 {
// nothing more to write
err1 = nil
}
}
if n > 0 {
pos += int64(n)
written += int64(n)
remain -= int64(n)
}
if n == 0 && err1 == nil {
break
}
if err1 == syscall.EAGAIN {
if err1 = c.pd.waitWrite(); err1 == nil {
continue
}
}
if err1 == syscall.EINTR {
continue
}
if err1 != nil {
// This includes syscall.ENOSYS (no kernel
// support) and syscall.EINVAL (fd types which
// don't implement sendfile)
err = err1
break
}
}
if lr != nil {
lr.N = remain
}
if err != nil {
err = os.NewSyscallError("sendfile", err)
lr.N = remain - written
}
return written, err, written > 0
return written, wrapSyscallError("sendfile", err), written > 0
}
......@@ -5,6 +5,7 @@
package net
import (
"internal/poll"
"io"
"os"
"syscall"
......@@ -34,19 +35,10 @@ func sendFile(fd *netFD, r io.Reader) (written int64, err error, handled bool) {
return 0, nil, false
}
if err := fd.writeLock(); err != nil {
return 0, err, true
}
defer fd.writeUnlock()
done, err := poll.SendFile(&fd.pfd, syscall.Handle(f.Fd()), n)
o := &fd.wop
o.qty = uint32(n)
o.handle = syscall.Handle(f.Fd())
done, err := wsrv.ExecIO(o, "TransmitFile", func(o *operation) error {
return syscall.TransmitFile(o.fd.sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
})
if err != nil {
return 0, os.NewSyscallError("transmitfile", err), false
return 0, wrapSyscallError("transmitfile", err), false
}
if lr != nil {
lr.N -= int64(done)
......
......@@ -10,6 +10,7 @@
package net
import (
"internal/poll"
"os"
"syscall"
)
......@@ -42,46 +43,8 @@ func sysSocket(family, sotype, proto int) (int, error) {
return -1, os.NewSyscallError("socket", err)
}
if err = syscall.SetNonblock(s, true); err != nil {
closeFunc(s)
poll.CloseFunc(s)
return -1, os.NewSyscallError("setnonblock", err)
}
return s, nil
}
// Wrapper around the accept system call that marks the returned file
// descriptor as nonblocking and close-on-exec.
func accept(s int) (int, syscall.Sockaddr, error) {
ns, sa, err := accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
// On Linux the accept4 system call was introduced in 2.6.28
// kernel and on FreeBSD it was introduced in 10 kernel. If we
// get an ENOSYS error on both Linux and FreeBSD, or EINVAL
// error on Linux, fall back to using accept.
switch err {
case nil:
return ns, sa, nil
default: // errors other than the ones listed
return -1, sa, os.NewSyscallError("accept4", err)
case syscall.ENOSYS: // syscall missing
case syscall.EINVAL: // some Linux use this instead of ENOSYS
case syscall.EACCES: // some Linux use this instead of ENOSYS
case syscall.EFAULT: // some Linux use this instead of ENOSYS
}
// See ../syscall/exec_unix.go for description of ForkLock.
// It is probably okay to hold the lock across syscall.Accept
// because we have put fd.sysfd into non-blocking mode.
// However, a call to the File method will put it back into
// blocking mode. We can't take that risk, so no use of ForkLock here.
ns, sa, err = acceptFunc(s)
if err == nil {
syscall.CloseOnExec(ns)
}
if err != nil {
return -1, nil, os.NewSyscallError("accept", err)
}
if err = syscall.SetNonblock(ns, true); err != nil {
closeFunc(ns)
return -1, nil, os.NewSyscallError("setnonblock", err)
}
return ns, sa, nil
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -255,7 +255,7 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
if !l.ok() {
return syscall.EINVAL
}
if err := l.fd.setDeadline(t); err != nil {
if err := l.fd.pfd.SetDeadline(t); err != nil {
return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
}
return nil
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -264,7 +264,7 @@ func (l *UnixListener) SetDeadline(t time.Time) error {
if !l.ok() {
return syscall.EINVAL
}
if err := l.fd.setDeadline(t); err != nil {
if err := l.fd.pfd.SetDeadline(t); err != nil {
return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
}
return nil
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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