Skip to content

Commit

Permalink
net: refactor poller into new internal/poll package
Browse files Browse the repository at this point in the history
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: David Crawshaw <crawshaw@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
  • Loading branch information
ianlancetaylor committed Feb 13, 2017
1 parent b548eee commit 3792db5
Show file tree
Hide file tree
Showing 79 changed files with 2,722 additions and 1,619 deletions.
95 changes: 48 additions & 47 deletions src/cmd/dist/deps.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/cmd/go/internal/work/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -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++
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/go/build/deps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"},
Expand Down Expand Up @@ -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",
},
Expand Down
39 changes: 39 additions & 0 deletions src/internal/poll/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// 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)
}
44 changes: 44 additions & 0 deletions src/internal/poll/fd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// 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) {}
14 changes: 6 additions & 8 deletions src/net/fd_io_plan9.go → src/internal/poll/fd_io_plan9.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand All @@ -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() {
Expand All @@ -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.
Expand Down
27 changes: 14 additions & 13 deletions src/net/fd_mutex.go → src/internal/poll/fd_mutex.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@
// 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
wsema uint32
}

// 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).
Expand Down Expand Up @@ -196,53 +196,54 @@ 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
}

// 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
}

// 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()
}
}

// 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
}

// 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()
}
Expand Down

0 comments on commit 3792db5

Please sign in to comment.