]> Cypherpunks repositories - gostls13.git/commitdiff
net: refactor poller into new internal/poll package
authorIan Lance Taylor <iant@golang.org>
Fri, 10 Feb 2017 22:59:38 +0000 (14:59 -0800)
committerIan Lance Taylor <iant@golang.org>
Mon, 13 Feb 2017 18:36:28 +0000 (18:36 +0000)
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>
79 files changed:
src/cmd/dist/deps.go
src/cmd/go/internal/work/build.go
src/go/build/deps_test.go
src/internal/poll/export_test.go [new file with mode: 0644]
src/internal/poll/fd.go [new file with mode: 0644]
src/internal/poll/fd_io_plan9.go [moved from src/net/fd_io_plan9.go with 91% similarity]
src/internal/poll/fd_mutex.go [moved from src/net/fd_mutex.go with 93% similarity]
src/internal/poll/fd_mutex_test.go [moved from src/net/fd_mutex_test.go with 67% similarity]
src/internal/poll/fd_plan9.go [new file with mode: 0644]
src/internal/poll/fd_poll_nacl.go [moved from src/net/fd_poll_nacl.go with 66% similarity]
src/internal/poll/fd_poll_runtime.go [moved from src/net/fd_poll_runtime.go with 79% similarity]
src/internal/poll/fd_posix.go [new file with mode: 0644]
src/internal/poll/fd_posix_test.go [new file with mode: 0644]
src/internal/poll/fd_unix.go [new file with mode: 0644]
src/internal/poll/fd_windows.go [new file with mode: 0644]
src/internal/poll/hook_cloexec.go [moved from src/net/hook_cloexec.go with 58% similarity]
src/internal/poll/hook_unix.go [new file with mode: 0644]
src/internal/poll/hook_windows.go [new file with mode: 0644]
src/internal/poll/sendfile_bsd.go [new file with mode: 0644]
src/internal/poll/sendfile_linux.go [new file with mode: 0644]
src/internal/poll/sendfile_solaris.go [new file with mode: 0644]
src/internal/poll/sendfile_windows.go [new file with mode: 0644]
src/internal/poll/sock_cloexec.go [new file with mode: 0644]
src/internal/poll/sockopt.go [new file with mode: 0644]
src/internal/poll/sockopt_linux.go [new file with mode: 0644]
src/internal/poll/sockopt_unix.go [new file with mode: 0644]
src/internal/poll/sockopt_windows.go [new file with mode: 0644]
src/internal/poll/sockoptip.go [new file with mode: 0644]
src/internal/poll/str.go [new file with mode: 0644]
src/internal/poll/sys_cloexec.go [new file with mode: 0644]
src/internal/poll/writev.go [new file with mode: 0644]
src/internal/poll/writev_test.go [new file with mode: 0644]
src/net/dial.go
src/net/dial_test.go
src/net/dnsclient_unix_test.go
src/net/error_posix.go [new file with mode: 0644]
src/net/error_test.go
src/net/fd_plan9.go
src/net/fd_posix.go [deleted file]
src/net/fd_posix_test.go [deleted file]
src/net/fd_unix.go
src/net/fd_windows.go
src/net/file_unix.go
src/net/hook_unix.go
src/net/hook_windows.go
src/net/ipsock_plan9.go
src/net/ipsock_posix.go
src/net/main_cloexec_test.go
src/net/main_unix_test.go
src/net/main_windows_test.go
src/net/net.go
src/net/sendfile_bsd.go
src/net/sendfile_linux.go
src/net/sendfile_solaris.go
src/net/sendfile_windows.go
src/net/sock_cloexec.go
src/net/sock_posix.go
src/net/sockopt_posix.go
src/net/sockoptip_bsd.go
src/net/sockoptip_linux.go
src/net/sockoptip_posix.go
src/net/sockoptip_windows.go
src/net/sys_cloexec.go
src/net/tcpsock.go
src/net/tcpsockopt_darwin.go
src/net/tcpsockopt_posix.go
src/net/tcpsockopt_solaris.go
src/net/tcpsockopt_unix.go
src/net/tcpsockopt_windows.go
src/net/timeout_test.go
src/net/unixsock.go
src/net/writev_test.go
src/net/writev_unix.go
src/runtime/net_plan9.go
src/runtime/netpoll.go
src/runtime/netpoll_windows.go
src/runtime/sema.go
src/runtime/time.go
src/runtime/trace/trace_stack_test.go

index c1c8b8fff3a6a541deb2b5c37de50de44dd7e63c..641fe5d8968dde9b246a921e9948ae3ca17634a9 100644 (file)
@@ -5,68 +5,69 @@ package main
 var builddeps = map[string][]string{
        "bufio":                             {"bytes", "errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"},
        "bytes":                             {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"},
-       "cmd/go/internal/base":              {"bufio", "bytes", "cmd/go/internal/cfg", "cmd/go/internal/str", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/bug":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/envcmd", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/web", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/buildid":           {"bufio", "bytes", "cmd/go/internal/cfg", "compress/flate", "compress/zlib", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/cfg":               {"bufio", "bytes", "errors", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/clean":             {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/doc":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/envcmd":            {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/fix":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "compress/flate", "compress/zlib", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/fmtcmd":            {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "compress/flate", "compress/zlib", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/generate":          {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/get":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/web", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding", "encoding/base64", "encoding/binary", "encoding/json", "encoding/xml", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/singleflight", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/help":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/list":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding", "encoding/base64", "encoding/binary", "encoding/json", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/load":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/str", "compress/flate", "compress/zlib", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/run":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/str":               {"bytes", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/test":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/tool":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/version":           {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "cmd/go/internal/vet":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/base":              {"bufio", "bytes", "cmd/go/internal/cfg", "cmd/go/internal/str", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/bug":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/envcmd", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/web", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/buildid":           {"bufio", "bytes", "cmd/go/internal/cfg", "compress/flate", "compress/zlib", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/cfg":               {"bufio", "bytes", "errors", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/clean":             {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/doc":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/envcmd":            {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/fix":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "compress/flate", "compress/zlib", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/fmtcmd":            {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "compress/flate", "compress/zlib", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/generate":          {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/get":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/web", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding", "encoding/base64", "encoding/binary", "encoding/json", "encoding/xml", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/singleflight", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/help":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/list":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding", "encoding/base64", "encoding/binary", "encoding/json", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/load":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/str", "compress/flate", "compress/zlib", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/run":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/str":               {"bytes", "errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/test":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/tool":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/version":           {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/cfg", "cmd/go/internal/str", "context", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/vet":               {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
        "cmd/go/internal/web":               {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
-       "cmd/go/internal/work":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "compress/flate":                    {"bufio", "bytes", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "compress/zlib":                     {"bufio", "bytes", "compress/flate", "errors", "fmt", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go/internal/work":              {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/load", "cmd/go/internal/str", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding/binary", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "compress/flate":                    {"bufio", "bytes", "errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "compress/zlib":                     {"bufio", "bytes", "compress/flate", "errors", "fmt", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
        "container/heap":                    {"errors", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "unicode/utf8"},
-       "context":                           {"errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
+       "context":                           {"errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
        "crypto":                            {"errors", "hash", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
        "crypto/sha1":                       {"crypto", "errors", "hash", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
-       "debug/dwarf":                       {"encoding/binary", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "debug/elf":                         {"bufio", "bytes", "compress/flate", "compress/zlib", "debug/dwarf", "encoding/binary", "errors", "fmt", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "debug/macho":                       {"bytes", "debug/dwarf", "encoding/binary", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "debug/dwarf":                       {"encoding/binary", "errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "debug/elf":                         {"bufio", "bytes", "compress/flate", "compress/zlib", "debug/dwarf", "encoding/binary", "errors", "fmt", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "debug/macho":                       {"bytes", "debug/dwarf", "encoding/binary", "errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
        "encoding":                          {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
        "encoding/base64":                   {"errors", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
        "encoding/binary":                   {"errors", "internal/race", "io", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
-       "encoding/json":                     {"bytes", "encoding", "encoding/base64", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "encoding/xml":                      {"bufio", "bytes", "encoding", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "encoding/json":                     {"bytes", "encoding", "encoding/base64", "errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "encoding/xml":                      {"bufio", "bytes", "encoding", "errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
        "errors":                            {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
-       "flag":                              {"errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
-       "fmt":                               {"errors", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
-       "go/ast":                            {"bytes", "errors", "fmt", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "go/build":                          {"bufio", "bytes", "errors", "fmt", "go/ast", "go/doc", "go/parser", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "go/doc":                            {"bytes", "errors", "fmt", "go/ast", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "go/parser":                         {"bytes", "errors", "fmt", "go/ast", "go/scanner", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "go/scanner":                        {"bytes", "errors", "fmt", "go/token", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "go/token":                          {"errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
+       "flag":                              {"errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
+       "fmt":                               {"errors", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
+       "go/ast":                            {"bytes", "errors", "fmt", "go/scanner", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "go/build":                          {"bufio", "bytes", "errors", "fmt", "go/ast", "go/doc", "go/parser", "go/scanner", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "go/doc":                            {"bytes", "errors", "fmt", "go/ast", "go/scanner", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "go/parser":                         {"bytes", "errors", "fmt", "go/ast", "go/scanner", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "go/scanner":                        {"bytes", "errors", "fmt", "go/token", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "go/token":                          {"errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
        "hash":                              {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
        "hash/adler32":                      {"errors", "hash", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
+       "internal/poll":                     {"errors", "internal/race", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "time", "unicode/utf16"},
        "internal/race":                     {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
        "internal/singleflight":             {"internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
        "internal/syscall/windows":          {"errors", "internal/race", "internal/syscall/windows/sysdll", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "unicode/utf16"},
        "internal/syscall/windows/registry": {"errors", "internal/race", "internal/syscall/windows/sysdll", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "unicode/utf16"},
        "internal/syscall/windows/sysdll":   {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
        "io":                      {"errors", "internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
-       "io/ioutil":               {"bytes", "errors", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "log":                     {"errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
+       "io/ioutil":               {"bytes", "errors", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "log":                     {"errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
        "math":                    {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
-       "net/url":                 {"bytes", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "os":                      {"errors", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
-       "os/exec":                 {"bytes", "context", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "os/signal":               {"errors", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "os", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
+       "net/url":                 {"bytes", "errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "os":                      {"errors", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
+       "os/exec":                 {"bytes", "context", "errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "os/signal":               {"errors", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "os", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
        "path":                    {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
-       "path/filepath":           {"errors", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "path/filepath":           {"errors", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
        "reflect":                 {"errors", "internal/race", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
        "regexp":                  {"bytes", "errors", "internal/race", "io", "math", "reflect", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
        "regexp/syntax":           {"bytes", "errors", "internal/race", "io", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
@@ -79,11 +80,11 @@ var builddeps = map[string][]string{
        "sync":                    {"internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync/atomic"},
        "sync/atomic":             {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
        "syscall":                 {"errors", "internal/race", "internal/syscall/windows/sysdll", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode/utf16"},
-       "text/template":           {"bytes", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "net/url", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
-       "text/template/parse":     {"bytes", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "text/template":           {"bytes", "errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "net/url", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "text/template/parse":     {"bytes", "errors", "fmt", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
        "time":                    {"errors", "internal/race", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "unicode/utf16"},
        "unicode":                 {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
        "unicode/utf16":           {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
        "unicode/utf8":            {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
-       "cmd/go":                  {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/bug", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/clean", "cmd/go/internal/doc", "cmd/go/internal/envcmd", "cmd/go/internal/fix", "cmd/go/internal/fmtcmd", "cmd/go/internal/generate", "cmd/go/internal/get", "cmd/go/internal/help", "cmd/go/internal/list", "cmd/go/internal/load", "cmd/go/internal/run", "cmd/go/internal/str", "cmd/go/internal/test", "cmd/go/internal/tool", "cmd/go/internal/version", "cmd/go/internal/vet", "cmd/go/internal/web", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding", "encoding/base64", "encoding/binary", "encoding/json", "encoding/xml", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/singleflight", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+       "cmd/go":                  {"bufio", "bytes", "cmd/go/internal/base", "cmd/go/internal/bug", "cmd/go/internal/buildid", "cmd/go/internal/cfg", "cmd/go/internal/clean", "cmd/go/internal/doc", "cmd/go/internal/envcmd", "cmd/go/internal/fix", "cmd/go/internal/fmtcmd", "cmd/go/internal/generate", "cmd/go/internal/get", "cmd/go/internal/help", "cmd/go/internal/list", "cmd/go/internal/load", "cmd/go/internal/run", "cmd/go/internal/str", "cmd/go/internal/test", "cmd/go/internal/tool", "cmd/go/internal/version", "cmd/go/internal/vet", "cmd/go/internal/web", "cmd/go/internal/work", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding", "encoding/base64", "encoding/binary", "encoding/json", "encoding/xml", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/poll", "internal/race", "internal/singleflight", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "os/exec", "os/signal", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
 }
index 2ed4d6b6ec28a73e4711b3095cb58179e4daaa52..a395176986d3c8d5633e85c0c6cc0610e774e58d 100644 (file)
@@ -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++
                }
        }
index 1ee23eda69eb7666a2ffe1020762084156092b7b..e6804e7ef506af838a2e23099166c019f34cdac0 100644 (file)
@@ -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",
        },
diff --git a/src/internal/poll/export_test.go b/src/internal/poll/export_test.go
new file mode 100644 (file)
index 0000000..ec658fd
--- /dev/null
@@ -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)
+}
diff --git a/src/internal/poll/fd.go b/src/internal/poll/fd.go
new file mode 100644 (file)
index 0000000..0752876
--- /dev/null
@@ -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) {}
similarity index 91%
rename from src/net/fd_io_plan9.go
rename to src/internal/poll/fd_io_plan9.go
index 76da0c546cfc74f050504077440fe712c014891f..287d11bd8c29f6a0bc46225183a669b06c03275e 100644 (file)
@@ -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.
similarity index 93%
rename from src/net/fd_mutex.go
rename to src/internal/poll/fd_mutex.go
index 4591fd1cac8e9738818f54b492ffbc7d0b0192a1..2b7605337022f449592a1060f82eaa4b4d96d001 100644 (file)
@@ -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()
        }
similarity index 67%
rename from src/net/fd_mutex_test.go
rename to src/internal/poll/fd_mutex_test.go
index 3542c70f9d1073e4f8358d504cf80b740f8d06bc..bab81c6dfee53698b9a5660a7487ebc2c49c41d3 100644 (file)
@@ -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")
        }
 }
diff --git a/src/internal/poll/fd_plan9.go b/src/internal/poll/fd_plan9.go
new file mode 100644 (file)
index 0000000..fa9e566
--- /dev/null
@@ -0,0 +1,180 @@
+// 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")
+}
similarity index 66%
rename from src/net/fd_poll_nacl.go
rename to src/internal/poll/fd_poll_nacl.go
index 83987602a585a2c48cd56cabb34b71a6c7abe8b9..69c728d084365e72048bb8d6babc1d5c6938a895 100644 (file)
@@ -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
similarity index 79%
rename from src/net/fd_poll_runtime.go
rename to src/internal/poll/fd_poll_runtime.go
index 62b69fcbf150541304db4f6c116969ac82ddd3ad..f0d7a227299776c0fa339c601e3ad66c9d7bfc16 100644 (file)
@@ -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
diff --git a/src/internal/poll/fd_posix.go b/src/internal/poll/fd_posix.go
new file mode 100644 (file)
index 0000000..e0e634c
--- /dev/null
@@ -0,0 +1,57 @@
+// 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)
+}
diff --git a/src/internal/poll/fd_posix_test.go b/src/internal/poll/fd_posix_test.go
new file mode 100644 (file)
index 0000000..edc2dcb
--- /dev/null
@@ -0,0 +1,43 @@
+// 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)
+               }
+       }
+}
diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go
new file mode 100644 (file)
index 0000000..d97490a
--- /dev/null
@@ -0,0 +1,398 @@
+// 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)
+}
diff --git a/src/internal/poll/fd_windows.go b/src/internal/poll/fd_windows.go
new file mode 100644 (file)
index 0000000..33df876
--- /dev/null
@@ -0,0 +1,816 @@
+// 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 (
+       "errors"
+       "internal/race"
+       "io"
+       "runtime"
+       "sync"
+       "syscall"
+       "unicode/utf16"
+       "unicode/utf8"
+       "unsafe"
+)
+
+var (
+       initErr error
+       ioSync  uint64
+)
+
+// CancelIo Windows API cancels all outstanding IO for a particular
+// socket on current thread. To overcome that limitation, we run
+// special goroutine, locked to OS single thread, that both starts
+// and cancels IO. It means, there are 2 unavoidable thread switches
+// for every IO.
+// Some newer versions of Windows has new CancelIoEx API, that does
+// not have that limitation and can be used from any thread. This
+// package uses CancelIoEx API, if present, otherwise it fallback
+// to CancelIo.
+
+var (
+       canCancelIO                               bool // determines if CancelIoEx API is present
+       skipSyncNotif                             bool
+       hasLoadSetFileCompletionNotificationModes bool
+)
+
+func init() {
+       var d syscall.WSAData
+       e := syscall.WSAStartup(uint32(0x202), &d)
+       if e != nil {
+               initErr = e
+       }
+       canCancelIO = syscall.LoadCancelIoEx() == nil
+       hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil
+       if hasLoadSetFileCompletionNotificationModes {
+               // It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed:
+               // http://support.microsoft.com/kb/2568167
+               skipSyncNotif = true
+               protos := [2]int32{syscall.IPPROTO_TCP, 0}
+               var buf [32]syscall.WSAProtocolInfo
+               len := uint32(unsafe.Sizeof(buf))
+               n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len)
+               if err != nil {
+                       skipSyncNotif = false
+               } else {
+                       for i := int32(0); i < n; i++ {
+                               if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 {
+                                       skipSyncNotif = false
+                                       break
+                               }
+                       }
+               }
+       }
+}
+
+// operation contains superset of data necessary to perform all async IO.
+type operation struct {
+       // Used by IOCP interface, it must be first field
+       // of the struct, as our code rely on it.
+       o syscall.Overlapped
+
+       // fields used by runtime.netpoll
+       runtimeCtx uintptr
+       mode       int32
+       errno      int32
+       qty        uint32
+
+       // fields used only by net package
+       fd     *FD
+       errc   chan error
+       buf    syscall.WSABuf
+       sa     syscall.Sockaddr
+       rsa    *syscall.RawSockaddrAny
+       rsan   int32
+       handle syscall.Handle
+       flags  uint32
+       bufs   []syscall.WSABuf
+}
+
+func (o *operation) InitBuf(buf []byte) {
+       o.buf.Len = uint32(len(buf))
+       o.buf.Buf = nil
+       if len(buf) != 0 {
+               o.buf.Buf = &buf[0]
+       }
+}
+
+func (o *operation) InitBufs(buf *[][]byte) {
+       if o.bufs == nil {
+               o.bufs = make([]syscall.WSABuf, 0, len(*buf))
+       } else {
+               o.bufs = o.bufs[:0]
+       }
+       for _, b := range *buf {
+               var p *byte
+               if len(b) > 0 {
+                       p = &b[0]
+               }
+               o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: p})
+       }
+}
+
+// ClearBufs clears all pointers to Buffers parameter captured
+// by InitBufs, so it can be released by garbage collector.
+func (o *operation) ClearBufs() {
+       for i := range o.bufs {
+               o.bufs[i].Buf = nil
+       }
+       o.bufs = o.bufs[:0]
+}
+
+// ioSrv executes net IO requests.
+type ioSrv struct {
+       req chan ioSrvReq
+}
+
+type ioSrvReq struct {
+       o      *operation
+       submit func(o *operation) error // if nil, cancel the operation
+}
+
+// ProcessRemoteIO will execute submit IO requests on behalf
+// of other goroutines, all on a single os thread, so it can
+// cancel them later. Results of all operations will be sent
+// back to their requesters via channel supplied in request.
+// It is used only when the CancelIoEx API is unavailable.
+func (s *ioSrv) ProcessRemoteIO() {
+       runtime.LockOSThread()
+       defer runtime.UnlockOSThread()
+       for r := range s.req {
+               if r.submit != nil {
+                       r.o.errc <- r.submit(r.o)
+               } else {
+                       r.o.errc <- syscall.CancelIo(r.o.fd.Sysfd)
+               }
+       }
+}
+
+// ExecIO executes a single IO operation o. It submits and cancels
+// IO in the current thread for systems where Windows CancelIoEx API
+// is available. Alternatively, it passes the request onto
+// runtime netpoll and waits for completion or cancels request.
+func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) error) (int, error) {
+       fd := o.fd
+       // Notify runtime netpoll about starting IO.
+       err := fd.pd.prepare(int(o.mode))
+       if err != nil {
+               return 0, err
+       }
+       // Start IO.
+       if canCancelIO {
+               err = submit(o)
+       } else {
+               // Send request to a special dedicated thread,
+               // so it can stop the IO with CancelIO later.
+               s.req <- ioSrvReq{o, submit}
+               err = <-o.errc
+       }
+       switch err {
+       case nil:
+               // IO completed immediately
+               if o.fd.skipSyncNotif {
+                       // No completion message will follow, so return immediately.
+                       return int(o.qty), nil
+               }
+               // Need to get our completion message anyway.
+       case syscall.ERROR_IO_PENDING:
+               // IO started, and we have to wait for its completion.
+               err = nil
+       default:
+               return 0, err
+       }
+       // Wait for our request to complete.
+       err = fd.pd.wait(int(o.mode))
+       if err == nil {
+               // All is good. Extract our IO results and return.
+               if o.errno != 0 {
+                       err = syscall.Errno(o.errno)
+                       return 0, err
+               }
+               return int(o.qty), nil
+       }
+       // IO is interrupted by "close" or "timeout"
+       netpollErr := err
+       switch netpollErr {
+       case ErrClosing, ErrTimeout:
+               // will deal with those.
+       default:
+               panic("net: unexpected runtime.netpoll error: " + netpollErr.Error())
+       }
+       // Cancel our request.
+       if canCancelIO {
+               err := syscall.CancelIoEx(fd.Sysfd, &o.o)
+               // Assuming ERROR_NOT_FOUND is returned, if IO is completed.
+               if err != nil && err != syscall.ERROR_NOT_FOUND {
+                       // TODO(brainman): maybe do something else, but panic.
+                       panic(err)
+               }
+       } else {
+               s.req <- ioSrvReq{o, nil}
+               <-o.errc
+       }
+       // Wait for cancelation to complete.
+       fd.pd.waitCanceled(int(o.mode))
+       if o.errno != 0 {
+               err = syscall.Errno(o.errno)
+               if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
+                       err = netpollErr
+               }
+               return 0, err
+       }
+       // We issued a cancelation request. But, it seems, IO operation succeeded
+       // before the cancelation request run. We need to treat the IO operation as
+       // succeeded (the bytes are actually sent/recv from network).
+       return int(o.qty), nil
+}
+
+// Start helper goroutines.
+var rsrv, wsrv *ioSrv
+var onceStartServer sync.Once
+
+func startServer() {
+       rsrv = new(ioSrv)
+       wsrv = new(ioSrv)
+       if !canCancelIO {
+               // Only CancelIo API is available. Lets start two special goroutines
+               // locked to an OS thread, that both starts and cancels IO. One will
+               // process read requests, while other will do writes.
+               rsrv.req = make(chan ioSrvReq)
+               go rsrv.ProcessRemoteIO()
+               wsrv.req = make(chan ioSrvReq)
+               go wsrv.ProcessRemoteIO()
+       }
+}
+
+// FD is a file descriptor. The net and os packages embed this type in
+// 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 syscall.Handle
+
+       // Read operation.
+       rop operation
+       // Write operation.
+       wop operation
+
+       // I/O poller.
+       pd pollDesc
+
+       // Used to implement pread/pwrite.
+       l sync.Mutex
+
+       // For console I/O.
+       isConsole      bool
+       lastbits       []byte   // first few bytes of the last incomplete rune in last write
+       readuint16     []uint16 // buffer to hold uint16s obtained with ReadConsole
+       readbyte       []byte   // buffer to hold decoding of readuint16 from utf16 to utf8
+       readbyteOffset int      // readbyte[readOffset:] is yet to be consumed with file.Read
+
+       skipSyncNotif bool
+
+       // Whether this is a streaming descriptor, as opposed to a
+       // packet-based descriptor like a UDP socket.
+       IsStream bool
+
+       // Whether a zero byte read indicates EOF. This is false for a
+       // message based socket connection.
+       ZeroReadIsEOF bool
+
+       // Whether this is a normal file.
+       isFile bool
+
+       // Whether this is a directory.
+       isDir bool
+}
+
+// Init initializes the FD. The Sysfd field should already be set.
+// This can be called multiple times on a single FD.
+// The net argument is a network name from the net package (e.g., "tcp"),
+// or "file" or "console" or "dir".
+func (fd *FD) Init(net string) (string, error) {
+       if initErr != nil {
+               return "", initErr
+       }
+       onceStartServer.Do(startServer)
+
+       switch net {
+       case "file":
+               fd.isFile = true
+       case "console":
+               fd.isConsole = true
+       case "dir":
+               fd.isDir = true
+       case "tcp", "tcp4", "tcp6":
+       case "udp", "udp4", "udp6":
+       case "ip", "ip4", "ip6":
+       case "unix", "unixgram", "unixpacket":
+       default:
+               return "", errors.New("internal error: unknown network type " + net)
+       }
+
+       if err := fd.pd.init(fd); err != nil {
+               return "", err
+       }
+       if hasLoadSetFileCompletionNotificationModes {
+               // We do not use events, so we can skip them always.
+               flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE)
+               // It's not safe to skip completion notifications for UDP:
+               // http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx
+               if skipSyncNotif && (net == "tcp" || net == "file") {
+                       flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
+               }
+               err := syscall.SetFileCompletionNotificationModes(fd.Sysfd, flags)
+               if err == nil && flags&syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS != 0 {
+                       fd.skipSyncNotif = true
+               }
+       }
+       // Disable SIO_UDP_CONNRESET behavior.
+       // http://support.microsoft.com/kb/263823
+       switch net {
+       case "udp", "udp4", "udp6":
+               ret := uint32(0)
+               flag := uint32(0)
+               size := uint32(unsafe.Sizeof(flag))
+               err := syscall.WSAIoctl(fd.Sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
+               if err != nil {
+                       return "wsaioctl", err
+               }
+       }
+       fd.rop.mode = 'r'
+       fd.wop.mode = 'w'
+       fd.rop.fd = fd
+       fd.wop.fd = fd
+       fd.rop.runtimeCtx = fd.pd.runtimeCtx
+       fd.wop.runtimeCtx = fd.pd.runtimeCtx
+       if !canCancelIO {
+               fd.rop.errc = make(chan error)
+               fd.wop.errc = make(chan error)
+       }
+       return "", nil
+}
+
+func (fd *FD) destroy() error {
+       if fd.Sysfd == syscall.InvalidHandle {
+               return syscall.EINVAL
+       }
+       // Poller may want to unregister fd in readiness notification mechanism,
+       // so this must be executed before fd.CloseFunc.
+       fd.pd.close()
+       var err error
+       if fd.isFile || fd.isConsole {
+               err = syscall.CloseHandle(fd.Sysfd)
+       } else if fd.isDir {
+               err = syscall.FindClose(fd.Sysfd)
+       } else {
+               // The net package uses the CloseFunc variable for testing.
+               err = CloseFunc(fd.Sysfd)
+       }
+       fd.Sysfd = syscall.InvalidHandle
+       return err
+}
+
+func (fd *FD) Close() error {
+       if !fd.fdmu.increfAndClose() {
+               return ErrClosing
+       }
+       // unblock pending reader and writer
+       fd.pd.evict()
+       return fd.decref()
+}
+
+func (fd *FD) Shutdown(how int) error {
+       if err := fd.incref(); err != nil {
+               return err
+       }
+       defer fd.decref()
+       return syscall.Shutdown(fd.Sysfd, how)
+}
+
+func (fd *FD) Read(buf []byte) (int, error) {
+       if err := fd.readLock(); err != nil {
+               return 0, err
+       }
+       defer fd.readUnlock()
+
+       var n int
+       var err error
+       if fd.isFile || fd.isDir || fd.isConsole {
+               fd.l.Lock()
+               defer fd.l.Unlock()
+               if fd.isConsole {
+                       n, err = fd.readConsole(buf)
+               } else {
+                       n, err = syscall.Read(fd.Sysfd, buf)
+               }
+               if err != nil {
+                       n = 0
+               }
+       } else {
+               o := &fd.rop
+               o.InitBuf(buf)
+               n, err = rsrv.ExecIO(o, "WSARecv", func(o *operation) error {
+                       return syscall.WSARecv(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil)
+               })
+               if race.Enabled {
+                       race.Acquire(unsafe.Pointer(&ioSync))
+               }
+       }
+       if len(buf) != 0 {
+               err = fd.eofError(n, err)
+       }
+       return n, err
+}
+
+var ReadConsole = syscall.ReadConsole // changed for testing
+
+// readConsole reads utf16 characters from console File,
+// encodes them into utf8 and stores them in buffer b.
+// It returns the number of utf8 bytes read and an error, if any.
+func (fd *FD) readConsole(b []byte) (n int, err error) {
+       if len(b) == 0 {
+               return 0, nil
+       }
+
+       if fd.readuint16 == nil {
+               // Note: syscall.ReadConsole fails for very large buffers.
+               // The limit is somewhere around (but not exactly) 16384.
+               // Stay well below.
+               fd.readuint16 = make([]uint16, 0, 10000)
+               fd.readbyte = make([]byte, 0, 4*cap(fd.readuint16))
+       }
+
+       for fd.readbyteOffset >= len(fd.readbyte) {
+               n := cap(fd.readuint16) - len(fd.readuint16)
+               if n > len(b) {
+                       n = len(b)
+               }
+               var nw uint32
+               err := ReadConsole(fd.Sysfd, &fd.readuint16[:len(fd.readuint16)+1][len(fd.readuint16)], uint32(n), &nw, nil)
+               if err != nil {
+                       return 0, err
+               }
+               uint16s := fd.readuint16[:len(fd.readuint16)+int(nw)]
+               fd.readuint16 = fd.readuint16[:0]
+               buf := fd.readbyte[:0]
+               for i := 0; i < len(uint16s); i++ {
+                       r := rune(uint16s[i])
+                       if utf16.IsSurrogate(r) {
+                               if i+1 == len(uint16s) {
+                                       if nw > 0 {
+                                               // Save half surrogate pair for next time.
+                                               fd.readuint16 = fd.readuint16[:1]
+                                               fd.readuint16[0] = uint16(r)
+                                               break
+                                       }
+                                       r = utf8.RuneError
+                               } else {
+                                       r = utf16.DecodeRune(r, rune(uint16s[i+1]))
+                                       if r != utf8.RuneError {
+                                               i++
+                                       }
+                               }
+                       }
+                       n := utf8.EncodeRune(buf[len(buf):cap(buf)], r)
+                       buf = buf[:len(buf)+n]
+               }
+               fd.readbyte = buf
+               fd.readbyteOffset = 0
+               if nw == 0 {
+                       break
+               }
+       }
+
+       src := fd.readbyte[fd.readbyteOffset:]
+       var i int
+       for i = 0; i < len(src) && i < len(b); i++ {
+               x := src[i]
+               if x == 0x1A { // Ctrl-Z
+                       if i == 0 {
+                               fd.readbyteOffset++
+                       }
+                       break
+               }
+               b[i] = x
+       }
+       fd.readbyteOffset += i
+       return i, nil
+}
+
+func (fd *FD) Pread(b []byte, off int64) (n int, err error) {
+       if err := fd.readLock(); err != nil {
+               return 0, err
+       }
+       defer fd.readUnlock()
+
+       fd.l.Lock()
+       defer fd.l.Unlock()
+       curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
+       if e != nil {
+               return 0, e
+       }
+       defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart)
+       o := syscall.Overlapped{
+               OffsetHigh: uint32(off >> 32),
+               Offset:     uint32(off),
+       }
+       var done uint32
+       e = syscall.ReadFile(fd.Sysfd, b, &done, &o)
+       if e != nil {
+               if e == syscall.ERROR_HANDLE_EOF {
+                       // end of file
+                       return 0, nil
+               }
+               return 0, e
+       }
+       return int(done), nil
+}
+
+func (fd *FD) RecvFrom(buf []byte) (int, syscall.Sockaddr, error) {
+       if len(buf) == 0 {
+               return 0, nil, nil
+       }
+       if err := fd.readLock(); err != nil {
+               return 0, nil, err
+       }
+       defer fd.readUnlock()
+       o := &fd.rop
+       o.InitBuf(buf)
+       n, err := rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error {
+               if o.rsa == nil {
+                       o.rsa = new(syscall.RawSockaddrAny)
+               }
+               o.rsan = int32(unsafe.Sizeof(*o.rsa))
+               return syscall.WSARecvFrom(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil)
+       })
+       err = fd.eofError(n, err)
+       if err != nil {
+               return n, nil, err
+       }
+       sa, _ := o.rsa.Sockaddr()
+       return n, sa, nil
+}
+
+func (fd *FD) Write(buf []byte) (int, error) {
+       if err := fd.writeLock(); err != nil {
+               return 0, err
+       }
+       defer fd.writeUnlock()
+
+       var n int
+       var err error
+       if fd.isFile || fd.isDir || fd.isConsole {
+               fd.l.Lock()
+               defer fd.l.Unlock()
+               if fd.isConsole {
+                       n, err = fd.writeConsole(buf)
+               } else {
+                       n, err = syscall.Write(fd.Sysfd, buf)
+               }
+               if err != nil {
+                       n = 0
+               }
+       } else {
+               if race.Enabled {
+                       race.ReleaseMerge(unsafe.Pointer(&ioSync))
+               }
+               o := &fd.wop
+               o.InitBuf(buf)
+               n, err = wsrv.ExecIO(o, "WSASend", func(o *operation) error {
+                       return syscall.WSASend(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil)
+               })
+       }
+       return n, err
+}
+
+// writeConsole writes len(b) bytes to the console File.
+// It returns the number of bytes written and an error, if any.
+func (fd *FD) writeConsole(b []byte) (n int, err error) {
+       n = len(b)
+       runes := make([]rune, 0, 256)
+       if len(fd.lastbits) > 0 {
+               b = append(fd.lastbits, b...)
+               fd.lastbits = nil
+
+       }
+       for len(b) >= utf8.UTFMax || utf8.FullRune(b) {
+               r, l := utf8.DecodeRune(b)
+               runes = append(runes, r)
+               b = b[l:]
+       }
+       if len(b) > 0 {
+               fd.lastbits = make([]byte, len(b))
+               copy(fd.lastbits, b)
+       }
+       // syscall.WriteConsole seems to fail, if given large buffer.
+       // So limit the buffer to 16000 characters. This number was
+       // discovered by experimenting with syscall.WriteConsole.
+       const maxWrite = 16000
+       for len(runes) > 0 {
+               m := len(runes)
+               if m > maxWrite {
+                       m = maxWrite
+               }
+               chunk := runes[:m]
+               runes = runes[m:]
+               uint16s := utf16.Encode(chunk)
+               for len(uint16s) > 0 {
+                       var written uint32
+                       err = syscall.WriteConsole(fd.Sysfd, &uint16s[0], uint32(len(uint16s)), &written, nil)
+                       if err != nil {
+                               return 0, nil
+                       }
+                       uint16s = uint16s[written:]
+               }
+       }
+       return n, nil
+}
+
+func (fd *FD) Pwrite(b []byte, off int64) (int, error) {
+       if err := fd.writeLock(); err != nil {
+               return 0, err
+       }
+       defer fd.writeUnlock()
+
+       fd.l.Lock()
+       defer fd.l.Unlock()
+       curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
+       if e != nil {
+               return 0, e
+       }
+       defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart)
+       o := syscall.Overlapped{
+               OffsetHigh: uint32(off >> 32),
+               Offset:     uint32(off),
+       }
+       var done uint32
+       e = syscall.WriteFile(fd.Sysfd, b, &done, &o)
+       if e != nil {
+               return 0, e
+       }
+       return int(done), nil
+}
+
+func (fd *FD) Writev(buf *[][]byte) (int64, error) {
+       if len(*buf) == 0 {
+               return 0, nil
+       }
+       if err := fd.writeLock(); err != nil {
+               return 0, err
+       }
+       defer fd.writeUnlock()
+       if race.Enabled {
+               race.ReleaseMerge(unsafe.Pointer(&ioSync))
+       }
+       o := &fd.wop
+       o.InitBufs(buf)
+       n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error {
+               return syscall.WSASend(o.fd.Sysfd, &o.bufs[0], uint32(len(*buf)), &o.qty, 0, &o.o, nil)
+       })
+       o.ClearBufs()
+       TestHookDidWritev(n)
+       consume(buf, int64(n))
+       return int64(n), err
+}
+
+func (fd *FD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
+       if len(buf) == 0 {
+               return 0, nil
+       }
+       if err := fd.writeLock(); err != nil {
+               return 0, err
+       }
+       defer fd.writeUnlock()
+       o := &fd.wop
+       o.InitBuf(buf)
+       o.sa = sa
+       n, err := wsrv.ExecIO(o, "WSASendto", func(o *operation) error {
+               return syscall.WSASendto(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil)
+       })
+       return n, err
+}
+
+// Call ConnectEx. This doesn't need any locking, since it is only
+// called when the descriptor is first created. This is here rather
+// than in the net package so that it can use fd.wop.
+func (fd *FD) ConnectEx(ra syscall.Sockaddr) error {
+       o := &fd.wop
+       o.sa = ra
+       _, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error {
+               return ConnectExFunc(o.fd.Sysfd, o.sa, nil, 0, nil, &o.o)
+       })
+       return err
+}
+
+func (fd *FD) acceptOne(s syscall.Handle, rawsa []syscall.RawSockaddrAny, o *operation) (string, error) {
+       // Submit accept request.
+       o.handle = s
+       o.rsan = int32(unsafe.Sizeof(rawsa[0]))
+       _, err := rsrv.ExecIO(o, "AcceptEx", func(o *operation) error {
+               return AcceptFunc(o.fd.Sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o)
+       })
+       if err != nil {
+               CloseFunc(s)
+               return "acceptex", err
+       }
+
+       // Inherit properties of the listening socket.
+       err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.Sysfd)), int32(unsafe.Sizeof(fd.Sysfd)))
+       if err != nil {
+               CloseFunc(s)
+               return "setsockopt", err
+       }
+
+       return "", nil
+}
+
+// Accept handles accepting a socket. The sysSocket parameter is used
+// to allocate the net socket.
+func (fd *FD) Accept(sysSocket func() (syscall.Handle, error)) (syscall.Handle, []syscall.RawSockaddrAny, uint32, string, error) {
+       if err := fd.readLock(); err != nil {
+               return syscall.InvalidHandle, nil, 0, "", err
+       }
+       defer fd.readUnlock()
+
+       o := &fd.rop
+       var rawsa [2]syscall.RawSockaddrAny
+       for {
+               s, err := sysSocket()
+               if err != nil {
+                       return syscall.InvalidHandle, nil, 0, "", err
+               }
+
+               errcall, err := fd.acceptOne(s, rawsa[:], o)
+               if err == nil {
+                       return s, rawsa[:], uint32(o.rsan), "", nil
+               }
+
+               // Sometimes we see WSAECONNRESET and ERROR_NETNAME_DELETED is
+               // returned here. These happen if connection reset is received
+               // before AcceptEx could complete. These errors relate to new
+               // connection, not to AcceptEx, so ignore broken connection and
+               // try AcceptEx again for more connections.
+               errno, ok := err.(syscall.Errno)
+               if !ok {
+                       return syscall.InvalidHandle, nil, 0, errcall, err
+               }
+               switch errno {
+               case syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET:
+                       // ignore these and try again
+               default:
+                       return syscall.InvalidHandle, nil, 0, errcall, err
+               }
+       }
+}
+
+func (fd *FD) Seek(offset int64, whence int) (ret int64, err error) {
+       if err := fd.incref(); err != nil {
+               return 0, err
+       }
+       defer fd.decref()
+
+       fd.l.Lock()
+       defer fd.l.Unlock()
+
+       return syscall.Seek(fd.Sysfd, offset, whence)
+}
+
+// FindNextFile wraps syscall.FindNextFile.
+func (fd *FD) FindNextFile(data *syscall.Win32finddata) error {
+       if err := fd.incref(); err != nil {
+               return err
+       }
+       defer fd.decref()
+       return syscall.FindNextFile(fd.Sysfd, data)
+}
+
+// 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)
+}
+
+func (fd *FD) GetFileType() (uint32, error) {
+       if err := fd.incref(); err != nil {
+               return 0, err
+       }
+       defer fd.decref()
+       return syscall.GetFileType(fd.Sysfd)
+}
+
+func (fd *FD) GetFileInformationByHandle(data *syscall.ByHandleFileInformation) error {
+       if err := fd.incref(); err != nil {
+               return err
+       }
+       defer fd.decref()
+       return syscall.GetFileInformationByHandle(fd.Sysfd, data)
+}
similarity index 58%
rename from src/net/hook_cloexec.go
rename to src/internal/poll/hook_cloexec.go
index 870f0d78b128a511456fcfce175c7925ae7222ac..062c343abaf36ec04977423a08ec09a607c54e9f 100644 (file)
@@ -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
diff --git a/src/internal/poll/hook_unix.go b/src/internal/poll/hook_unix.go
new file mode 100644 (file)
index 0000000..4a6ff6c
--- /dev/null
@@ -0,0 +1,17 @@
+// 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
diff --git a/src/internal/poll/hook_windows.go b/src/internal/poll/hook_windows.go
new file mode 100644 (file)
index 0000000..9766555
--- /dev/null
@@ -0,0 +1,18 @@
+// 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
diff --git a/src/internal/poll/sendfile_bsd.go b/src/internal/poll/sendfile_bsd.go
new file mode 100644 (file)
index 0000000..9f8b1a3
--- /dev/null
@@ -0,0 +1,51 @@
+// 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
+}
diff --git a/src/internal/poll/sendfile_linux.go b/src/internal/poll/sendfile_linux.go
new file mode 100644 (file)
index 0000000..0bc7529
--- /dev/null
@@ -0,0 +1,48 @@
+// 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
+}
diff --git a/src/internal/poll/sendfile_solaris.go b/src/internal/poll/sendfile_solaris.go
new file mode 100644 (file)
index 0000000..6d03ecc
--- /dev/null
@@ -0,0 +1,64 @@
+// 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
+}
diff --git a/src/internal/poll/sendfile_windows.go b/src/internal/poll/sendfile_windows.go
new file mode 100644 (file)
index 0000000..762165a
--- /dev/null
@@ -0,0 +1,23 @@
+// 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
+}
diff --git a/src/internal/poll/sock_cloexec.go b/src/internal/poll/sock_cloexec.go
new file mode 100644 (file)
index 0000000..28b950c
--- /dev/null
@@ -0,0 +1,52 @@
+// 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
+}
diff --git a/src/internal/poll/sockopt.go b/src/internal/poll/sockopt.go
new file mode 100644 (file)
index 0000000..b841699
--- /dev/null
@@ -0,0 +1,38 @@
+// 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)
+}
diff --git a/src/internal/poll/sockopt_linux.go b/src/internal/poll/sockopt_linux.go
new file mode 100644 (file)
index 0000000..ba616db
--- /dev/null
@@ -0,0 +1,18 @@
+// 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)
+}
diff --git a/src/internal/poll/sockopt_unix.go b/src/internal/poll/sockopt_unix.go
new file mode 100644 (file)
index 0000000..b33644d
--- /dev/null
@@ -0,0 +1,18 @@
+// 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)
+}
diff --git a/src/internal/poll/sockopt_windows.go b/src/internal/poll/sockopt_windows.go
new file mode 100644 (file)
index 0000000..70501a0
--- /dev/null
@@ -0,0 +1,27 @@
+// 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)
+}
diff --git a/src/internal/poll/sockoptip.go b/src/internal/poll/sockoptip.go
new file mode 100644 (file)
index 0000000..28900eb
--- /dev/null
@@ -0,0 +1,27 @@
+// 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)
+}
diff --git a/src/internal/poll/str.go b/src/internal/poll/str.go
new file mode 100644 (file)
index 0000000..2be35c7
--- /dev/null
@@ -0,0 +1,39 @@
+// 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
+}
diff --git a/src/internal/poll/sys_cloexec.go b/src/internal/poll/sys_cloexec.go
new file mode 100644 (file)
index 0000000..d001245
--- /dev/null
@@ -0,0 +1,36 @@
+// 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
+}
diff --git a/src/internal/poll/writev.go b/src/internal/poll/writev.go
new file mode 100644 (file)
index 0000000..fcee388
--- /dev/null
@@ -0,0 +1,81 @@
+// 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
+}
diff --git a/src/internal/poll/writev_test.go b/src/internal/poll/writev_test.go
new file mode 100644 (file)
index 0000000..b46657c
--- /dev/null
@@ -0,0 +1,62 @@
+// 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)
+               }
+       }
+}
index 50bba5a49e426eb465a1f1910ee0da14150edc8f..0a7da408fe526a567a60f208c82132bc5973d88d 100644 (file)
@@ -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)
index 9919d72ce3b79b90500835e3a46ec3cf2b38d183..9825bc92abc69adaa85ce4904a4dfa8056b01767 100644 (file)
@@ -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)
index 85267bbddc02a28e8d0ea3c1d8dee8bcee29ca34..4464804c701e4cfe99d0dbcf3c602c0d6d0e1913 100644 (file)
@@ -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 {
diff --git a/src/net/error_posix.go b/src/net/error_posix.go
new file mode 100644 (file)
index 0000000..dd9754c
--- /dev/null
@@ -0,0 +1,21 @@
+// 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 windows
+
+package net
+
+import (
+       "os"
+       "syscall"
+)
+
+// 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
+}
index c23da49fad91289da0ccea8dcc2cd344427decf0..61abfae5f0eee607eb6f885d32faf42b74f6b575 100644 (file)
@@ -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)
index 300d8c4543e90bb93cf3122e69abe958e787d6d6..7496e36ca7a0fe92bbab2a3fc0da69978de3a085 100644 (file)
@@ -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")
-}
diff --git a/src/net/fd_posix.go b/src/net/fd_posix.go
deleted file mode 100644 (file)
index b4b908a..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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 net
-
-import (
-       "io"
-       "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
-       }
-       return err
-}
diff --git a/src/net/fd_posix_test.go b/src/net/fd_posix_test.go
deleted file mode 100644 (file)
index 85711ef..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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)
-               }
-       }
-}
index 3c95fc01d401dbcad0162f17e571f8ea656ffe2c..9f36069bf367b65d136d4e4b949630d3f40de58c 100644 (file)
@@ -8,7 +8,7 @@ package net
 
 import (
        "context"
-       "io"
+       "internal/poll"
        "os"
        "runtime"
        "sync/atomic"
@@ -17,38 +17,36 @@ import (
 
 // 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
-       sysfd       int
        family      int
        sotype      int
-       isStream    bool
        isConnected bool
        net         string
        laddr       Addr
        raddr       Addr
-
-       // writev cache.
-       iovecs *[]syscall.Iovec
-
-       // wait server
-       pd pollDesc
 }
 
 func sysInit() {
 }
 
 func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
-       return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net, isStream: sotype == syscall.SOCK_STREAM}, nil
+       ret := &netFD{
+               pfd: poll.FD{
+                       Sysfd:         sysfd,
+                       IsStream:      sotype == syscall.SOCK_STREAM,
+                       ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
+               },
+               family: family,
+               sotype: sotype,
+               net:    net,
+       }
+       return ret, nil
 }
 
 func (fd *netFD) init() error {
-       if err := fd.pd.init(fd); err != nil {
-               return err
-       }
-       return nil
+       return fd.pfd.Init()
 }
 
 func (fd *netFD) setAddr(laddr, raddr Addr) {
@@ -72,7 +70,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
        // Do not need to call fd.writeLock here,
        // because fd is not yet accessible to user,
        // so no concurrent operations are possible.
-       switch err := connectFunc(fd.sysfd, ra); err {
+       switch err := connectFunc(fd.pfd.Sysfd, ra); err {
        case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
        case nil, syscall.EISCONN:
                select {
@@ -80,9 +78,10 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
                        return mapErr(ctx.Err())
                default:
                }
-               if err := fd.init(); err != nil {
+               if err := fd.pfd.Init(); err != nil {
                        return err
                }
+               runtime.KeepAlive(fd)
                return nil
        case syscall.EINVAL:
                // On Solaris we can see EINVAL if the socket has
@@ -97,12 +96,12 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
        default:
                return os.NewSyscallError("connect", err)
        }
-       if err := fd.init(); err != nil {
+       if err := fd.pfd.Init(); err != nil {
                return err
        }
        if deadline, _ := ctx.Deadline(); !deadline.IsZero() {
-               fd.setWriteDeadline(deadline)
-               defer fd.setWriteDeadline(noDeadline)
+               fd.pfd.SetWriteDeadline(deadline)
+               defer fd.pfd.SetWriteDeadline(noDeadline)
        }
 
        // Start the "interrupter" goroutine, if this context might be canceled.
@@ -119,7 +118,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
                defer func() {
                        close(done)
                        if ctxErr := <-interruptRes; ctxErr != nil && ret == nil {
-                               // The interrupter goroutine called setWriteDeadline,
+                               // The interrupter goroutine called SetWriteDeadline,
                                // but the connect code below had returned from
                                // waitWrite already and did a successful connect (ret
                                // == nil). Because we've now poisoned the connection
@@ -135,7 +134,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
                                // Force the runtime's poller to immediately give up
                                // waiting for writability, unblocking waitWrite
                                // below.
-                               fd.setWriteDeadline(aLongTimeAgo)
+                               fd.pfd.SetWriteDeadline(aLongTimeAgo)
                                testHookCanceledDial()
                                interruptRes <- ctx.Err()
                        case <-done:
@@ -153,7 +152,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
                // SO_ERROR socket option to see if the connection
                // succeeded or failed. See issue 7474 for further
                // details.
-               if err := fd.pd.waitWrite(); err != nil {
+               if err := fd.pfd.WaitWrite(); err != nil {
                        select {
                        case <-ctx.Done():
                                return mapErr(ctx.Err())
@@ -161,7 +160,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
                        }
                        return err
                }
-               nerr, err := getsockoptIntFunc(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+               nerr, err := getsockoptIntFunc(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
                if err != nil {
                        return os.NewSyscallError("getsockopt", err)
                }
@@ -174,45 +173,26 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
                        // See golang.org/issue/14548.
                        // On Darwin, multiple connect system calls on
                        // a non-blocking socket never harm SO_ERROR.
-                       switch err := connectFunc(fd.sysfd, ra); err {
+                       switch err := connectFunc(fd.pfd.Sysfd, ra); err {
                        case nil, syscall.EISCONN:
                                return nil
                        }
                default:
                        return os.NewSyscallError("getsockopt", err)
                }
+               runtime.KeepAlive(fd)
        }
 }
 
-func (fd *netFD) destroy() {
-       // Poller may want to unregister fd in readiness notification mechanism,
-       // so this must be executed before closeFunc.
-       fd.pd.close()
-       closeFunc(fd.sysfd)
-       fd.sysfd = -1
-       runtime.SetFinalizer(fd, nil)
-}
-
 func (fd *netFD) 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()
-       fd.decref()
-       return nil
+       runtime.SetFinalizer(fd, nil)
+       return fd.pfd.Close()
 }
 
 func (fd *netFD) shutdown(how int) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("shutdown", syscall.Shutdown(fd.sysfd, how))
+       err := fd.pfd.Shutdown(how)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("shutdown", err)
 }
 
 func (fd *netFD) closeRead() error {
@@ -224,233 +204,59 @@ func (fd *netFD) closeWrite() error {
 }
 
 func (fd *netFD) 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 and eofError turns that into
-               // 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) > 1<<30 {
-               p = p[:1<<30]
-       }
-       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
-       }
-       if _, ok := err.(syscall.Errno); ok {
-               err = os.NewSyscallError("read", err)
-       }
-       return
+       n, err = fd.pfd.Read(p)
+       runtime.KeepAlive(fd)
+       return n, wrapSyscallError("read", err)
 }
 
 func (fd *netFD) readFrom(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
-       }
-       if _, ok := err.(syscall.Errno); ok {
-               err = os.NewSyscallError("recvfrom", err)
-       }
-       return
+       n, sa, err = fd.pfd.RecvFrom(p)
+       runtime.KeepAlive(fd)
+       return n, sa, wrapSyscallError("recvfrom", err)
 }
 
 func (fd *netFD) 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
-       }
-       if _, ok := err.(syscall.Errno); ok {
-               err = os.NewSyscallError("recvmsg", err)
-       }
-       return
+       n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob)
+       runtime.KeepAlive(fd)
+       return n, oobn, flags, sa, wrapSyscallError("recvmsg", err)
 }
 
 func (fd *netFD) 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 > 1<<30 {
-                       max = nn + 1<<30
-               }
-               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
-               }
-       }
-       if _, ok := err.(syscall.Errno); ok {
-               err = os.NewSyscallError("write", err)
-       }
-       return nn, err
+       nn, err = fd.pfd.Write(p)
+       runtime.KeepAlive(fd)
+       return nn, wrapSyscallError("write", err)
 }
 
 func (fd *netFD) 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)
-       }
-       if _, ok := err.(syscall.Errno); ok {
-               err = os.NewSyscallError("sendto", err)
-       }
-       return
+       n, err = fd.pfd.WriteTo(p, sa)
+       runtime.KeepAlive(fd)
+       return n, wrapSyscallError("sendto", err)
 }
 
 func (fd *netFD) 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)
-       }
-       if _, ok := err.(syscall.Errno); ok {
-               err = os.NewSyscallError("sendmsg", err)
-       }
-       return
+       n, oobn, err = fd.pfd.WriteMsg(p, oob, sa)
+       runtime.KeepAlive(fd)
+       return n, oobn, wrapSyscallError("sendmsg", err)
 }
 
 func (fd *netFD) accept() (netfd *netFD, err error) {
-       if err := fd.readLock(); err != nil {
-               return nil, err
-       }
-       defer fd.readUnlock()
-
-       var s int
-       var rsa syscall.Sockaddr
-       if err = fd.pd.prepareRead(); err != nil {
-               return nil, err
-       }
-       for {
-               s, rsa, err = accept(fd.sysfd)
-               if err != nil {
-                       nerr, ok := err.(*os.SyscallError)
-                       if !ok {
-                               return nil, err
-                       }
-                       switch nerr.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 nil, err
+       d, rsa, errcall, err := fd.pfd.Accept()
+       if err != nil {
+               if errcall != "" {
+                       err = wrapSyscallError(errcall, err)
                }
-               break
+               return nil, err
        }
 
-       if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil {
-               closeFunc(s)
+       if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil {
+               poll.CloseFunc(d)
                return nil, err
        }
        if err = netfd.init(); err != nil {
                fd.Close()
                return nil, err
        }
-       lsa, _ := syscall.Getsockname(netfd.sysfd)
+       lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd)
        netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
        return netfd, nil
 }
@@ -503,7 +309,7 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) {
 }
 
 func (fd *netFD) dup() (f *os.File, err error) {
-       ns, err := dupCloseOnExec(fd.sysfd)
+       ns, err := dupCloseOnExec(fd.pfd.Sysfd)
        if err != nil {
                return nil, err
        }
index a976f2ac7f9d324d404118347b60e304db00f5da..2182b730f914381892f8171c002cd824ecea11e9 100644 (file)
@@ -6,62 +6,14 @@ package net
 
 import (
        "context"
-       "internal/race"
+       "internal/poll"
        "os"
        "runtime"
-       "sync"
        "syscall"
        "unsafe"
 )
 
-var (
-       initErr error
-       ioSync  uint64
-)
-
-// CancelIo Windows API cancels all outstanding IO for a particular
-// socket on current thread. To overcome that limitation, we run
-// special goroutine, locked to OS single thread, that both starts
-// and cancels IO. It means, there are 2 unavoidable thread switches
-// for every IO.
-// Some newer versions of Windows has new CancelIoEx API, that does
-// not have that limitation and can be used from any thread. This
-// package uses CancelIoEx API, if present, otherwise it fallback
-// to CancelIo.
-
-var (
-       canCancelIO                               bool // determines if CancelIoEx API is present
-       skipSyncNotif                             bool
-       hasLoadSetFileCompletionNotificationModes bool
-)
-
 func sysInit() {
-       var d syscall.WSAData
-       e := syscall.WSAStartup(uint32(0x202), &d)
-       if e != nil {
-               initErr = os.NewSyscallError("wsastartup", e)
-       }
-       canCancelIO = syscall.LoadCancelIoEx() == nil
-       hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil
-       if hasLoadSetFileCompletionNotificationModes {
-               // It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed:
-               // http://support.microsoft.com/kb/2568167
-               skipSyncNotif = true
-               protos := [2]int32{syscall.IPPROTO_TCP, 0}
-               var buf [32]syscall.WSAProtocolInfo
-               len := uint32(unsafe.Sizeof(buf))
-               n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len)
-               if err != nil {
-                       skipSyncNotif = false
-               } else {
-                       for i := int32(0); i < n; i++ {
-                               if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 {
-                                       skipSyncNotif = false
-                                       break
-                               }
-                       }
-               }
-       }
 }
 
 // canUseConnectEx reports whether we can use the ConnectEx Windows API call
@@ -75,257 +27,39 @@ func canUseConnectEx(net string) bool {
        return false
 }
 
-// operation contains superset of data necessary to perform all async IO.
-type operation struct {
-       // Used by IOCP interface, it must be first field
-       // of the struct, as our code rely on it.
-       o syscall.Overlapped
-
-       // fields used by runtime.netpoll
-       runtimeCtx uintptr
-       mode       int32
-       errno      int32
-       qty        uint32
-
-       // fields used only by net package
-       fd     *netFD
-       errc   chan error
-       buf    syscall.WSABuf
-       sa     syscall.Sockaddr
-       rsa    *syscall.RawSockaddrAny
-       rsan   int32
-       handle syscall.Handle
-       flags  uint32
-       bufs   []syscall.WSABuf
-}
-
-func (o *operation) InitBuf(buf []byte) {
-       o.buf.Len = uint32(len(buf))
-       o.buf.Buf = nil
-       if len(buf) != 0 {
-               o.buf.Buf = &buf[0]
-       }
-}
-
-func (o *operation) InitBufs(buf *Buffers) {
-       if o.bufs == nil {
-               o.bufs = make([]syscall.WSABuf, 0, len(*buf))
-       } else {
-               o.bufs = o.bufs[:0]
-       }
-       for _, b := range *buf {
-               var p *byte
-               if len(b) > 0 {
-                       p = &b[0]
-               }
-               o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: p})
-       }
-}
-
-// ClearBufs clears all pointers to Buffers parameter captured
-// by InitBufs, so it can be released by garbage collector.
-func (o *operation) ClearBufs() {
-       for i := range o.bufs {
-               o.bufs[i].Buf = nil
-       }
-       o.bufs = o.bufs[:0]
-}
-
-// ioSrv executes net IO requests.
-type ioSrv struct {
-       req chan ioSrvReq
-}
-
-type ioSrvReq struct {
-       o      *operation
-       submit func(o *operation) error // if nil, cancel the operation
-}
-
-// ProcessRemoteIO will execute submit IO requests on behalf
-// of other goroutines, all on a single os thread, so it can
-// cancel them later. Results of all operations will be sent
-// back to their requesters via channel supplied in request.
-// It is used only when the CancelIoEx API is unavailable.
-func (s *ioSrv) ProcessRemoteIO() {
-       runtime.LockOSThread()
-       defer runtime.UnlockOSThread()
-       for r := range s.req {
-               if r.submit != nil {
-                       r.o.errc <- r.submit(r.o)
-               } else {
-                       r.o.errc <- syscall.CancelIo(r.o.fd.sysfd)
-               }
-       }
-}
-
-// ExecIO executes a single IO operation o. It submits and cancels
-// IO in the current thread for systems where Windows CancelIoEx API
-// is available. Alternatively, it passes the request onto
-// runtime netpoll and waits for completion or cancels request.
-func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) error) (int, error) {
-       fd := o.fd
-       // Notify runtime netpoll about starting IO.
-       err := fd.pd.prepare(int(o.mode))
-       if err != nil {
-               return 0, err
-       }
-       // Start IO.
-       if canCancelIO {
-               err = submit(o)
-       } else {
-               // Send request to a special dedicated thread,
-               // so it can stop the IO with CancelIO later.
-               s.req <- ioSrvReq{o, submit}
-               err = <-o.errc
-       }
-       switch err {
-       case nil:
-               // IO completed immediately
-               if o.fd.skipSyncNotif {
-                       // No completion message will follow, so return immediately.
-                       return int(o.qty), nil
-               }
-               // Need to get our completion message anyway.
-       case syscall.ERROR_IO_PENDING:
-               // IO started, and we have to wait for its completion.
-               err = nil
-       default:
-               return 0, err
-       }
-       // Wait for our request to complete.
-       err = fd.pd.wait(int(o.mode))
-       if err == nil {
-               // All is good. Extract our IO results and return.
-               if o.errno != 0 {
-                       err = syscall.Errno(o.errno)
-                       return 0, err
-               }
-               return int(o.qty), nil
-       }
-       // IO is interrupted by "close" or "timeout"
-       netpollErr := err
-       switch netpollErr {
-       case errClosing, errTimeout:
-               // will deal with those.
-       default:
-               panic("net: unexpected runtime.netpoll error: " + netpollErr.Error())
-       }
-       // Cancel our request.
-       if canCancelIO {
-               err := syscall.CancelIoEx(fd.sysfd, &o.o)
-               // Assuming ERROR_NOT_FOUND is returned, if IO is completed.
-               if err != nil && err != syscall.ERROR_NOT_FOUND {
-                       // TODO(brainman): maybe do something else, but panic.
-                       panic(err)
-               }
-       } else {
-               s.req <- ioSrvReq{o, nil}
-               <-o.errc
-       }
-       // Wait for cancelation to complete.
-       fd.pd.waitCanceled(int(o.mode))
-       if o.errno != 0 {
-               err = syscall.Errno(o.errno)
-               if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
-                       err = netpollErr
-               }
-               return 0, err
-       }
-       // We issued a cancelation request. But, it seems, IO operation succeeded
-       // before the cancelation request run. We need to treat the IO operation as
-       // succeeded (the bytes are actually sent/recv from network).
-       return int(o.qty), nil
-}
-
-// Start helper goroutines.
-var rsrv, wsrv *ioSrv
-var onceStartServer sync.Once
-
-func startServer() {
-       rsrv = new(ioSrv)
-       wsrv = new(ioSrv)
-       if !canCancelIO {
-               // Only CancelIo API is available. Lets start two special goroutines
-               // locked to an OS thread, that both starts and cancels IO. One will
-               // process read requests, while other will do writes.
-               rsrv.req = make(chan ioSrvReq)
-               go rsrv.ProcessRemoteIO()
-               wsrv.req = make(chan ioSrvReq)
-               go wsrv.ProcessRemoteIO()
-       }
-}
-
 // 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
-       sysfd         syscall.Handle
-       family        int
-       sotype        int
-       isStream      bool
-       isConnected   bool
-       skipSyncNotif bool
-       net           string
-       laddr         Addr
-       raddr         Addr
-
-       rop operation // read operation
-       wop operation // write operation
-
-       // wait server
-       pd pollDesc
+       family      int
+       sotype      int
+       isConnected bool
+       net         string
+       laddr       Addr
+       raddr       Addr
 }
 
 func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) {
-       if initErr != nil {
-               return nil, initErr
+       ret := &netFD{
+               pfd: poll.FD{
+                       Sysfd:         sysfd,
+                       IsStream:      sotype == syscall.SOCK_STREAM,
+                       ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
+               },
+               family: family,
+               sotype: sotype,
+               net:    net,
        }
-       onceStartServer.Do(startServer)
-       return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net, isStream: sotype == syscall.SOCK_STREAM}, nil
+       return ret, nil
 }
 
 func (fd *netFD) init() error {
-       if err := fd.pd.init(fd); err != nil {
-               return err
-       }
-       if hasLoadSetFileCompletionNotificationModes {
-               // We do not use events, so we can skip them always.
-               flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE)
-               // It's not safe to skip completion notifications for UDP:
-               // http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx
-               if skipSyncNotif && fd.net == "tcp" {
-                       flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
-               }
-               err := syscall.SetFileCompletionNotificationModes(fd.sysfd, flags)
-               if err == nil && flags&syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS != 0 {
-                       fd.skipSyncNotif = true
-               }
-       }
-       // Disable SIO_UDP_CONNRESET behavior.
-       // http://support.microsoft.com/kb/263823
-       switch fd.net {
-       case "udp", "udp4", "udp6":
-               ret := uint32(0)
-               flag := uint32(0)
-               size := uint32(unsafe.Sizeof(flag))
-               err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
-               if err != nil {
-                       return os.NewSyscallError("wsaioctl", err)
-               }
-       }
-       fd.rop.mode = 'r'
-       fd.wop.mode = 'w'
-       fd.rop.fd = fd
-       fd.wop.fd = fd
-       fd.rop.runtimeCtx = fd.pd.runtimeCtx
-       fd.wop.runtimeCtx = fd.pd.runtimeCtx
-       if !canCancelIO {
-               fd.rop.errc = make(chan error)
-               fd.wop.errc = make(chan error)
+       errcall, err := fd.pfd.Init(fd.net)
+       if errcall != "" {
+               err = wrapSyscallError(errcall, err)
        }
-       return nil
+       return err
 }
 
 func (fd *netFD) setAddr(laddr, raddr Addr) {
@@ -342,11 +76,11 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
                return err
        }
        if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
-               fd.setWriteDeadline(deadline)
-               defer fd.setWriteDeadline(noDeadline)
+               fd.pfd.SetWriteDeadline(deadline)
+               defer fd.pfd.SetWriteDeadline(noDeadline)
        }
        if !canUseConnectEx(fd.net) {
-               err := connectFunc(fd.sysfd, ra)
+               err := connectFunc(fd.pfd.Sysfd, ra)
                return os.NewSyscallError("connect", err)
        }
        // ConnectEx windows API requires an unconnected, previously bound socket.
@@ -359,13 +93,10 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
                default:
                        panic("unexpected type in connect")
                }
-               if err := syscall.Bind(fd.sysfd, la); err != nil {
+               if err := syscall.Bind(fd.pfd.Sysfd, la); err != nil {
                        return os.NewSyscallError("bind", err)
                }
        }
-       // Call ConnectEx API.
-       o := &fd.wop
-       o.sa = ra
 
        // Wait for the goroutine converting context.Done into a write timeout
        // to exist, otherwise our caller might cancel the context and
@@ -377,16 +108,14 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
                case <-ctx.Done():
                        // Force the runtime's poller to immediately give
                        // up waiting for writability.
-                       fd.setWriteDeadline(aLongTimeAgo)
+                       fd.pfd.SetWriteDeadline(aLongTimeAgo)
                        <-done
                case <-done:
                }
        }()
 
-       _, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error {
-               return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o)
-       })
-       if err != nil {
+       // Call ConnectEx API.
+       if err := fd.pfd.ConnectEx(ra); err != nil {
                select {
                case <-ctx.Done():
                        return mapErr(ctx.Err())
@@ -398,38 +127,18 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
                }
        }
        // Refresh socket properties.
-       return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))))
-}
-
-func (fd *netFD) destroy() {
-       if fd.sysfd == syscall.InvalidHandle {
-               return
-       }
-       // Poller may want to unregister fd in readiness notification mechanism,
-       // so this must be executed before closeFunc.
-       fd.pd.close()
-       closeFunc(fd.sysfd)
-       fd.sysfd = syscall.InvalidHandle
-       // no need for a finalizer anymore
-       runtime.SetFinalizer(fd, nil)
+       return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.pfd.Sysfd)), int32(unsafe.Sizeof(fd.pfd.Sysfd))))
 }
 
 func (fd *netFD) Close() error {
-       if !fd.fdmu.increfAndClose() {
-               return errClosing
-       }
-       // unblock pending reader and writer
-       fd.pd.evict()
-       fd.decref()
-       return nil
+       runtime.SetFinalizer(fd, nil)
+       return fd.pfd.Close()
 }
 
 func (fd *netFD) shutdown(how int) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return syscall.Shutdown(fd.sysfd, how)
+       err := fd.pfd.Shutdown(how)
+       runtime.KeepAlive(fd)
+       return err
 }
 
 func (fd *netFD) closeRead() error {
@@ -441,72 +150,21 @@ func (fd *netFD) closeWrite() error {
 }
 
 func (fd *netFD) Read(buf []byte) (int, error) {
-       if err := fd.readLock(); err != nil {
-               return 0, err
-       }
-       defer fd.readUnlock()
-       o := &fd.rop
-       o.InitBuf(buf)
-       n, err := rsrv.ExecIO(o, "WSARecv", func(o *operation) error {
-               return syscall.WSARecv(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil)
-       })
-       if race.Enabled {
-               race.Acquire(unsafe.Pointer(&ioSync))
-       }
-       if len(buf) != 0 {
-               err = fd.eofError(n, err)
-       }
-       if _, ok := err.(syscall.Errno); ok {
-               err = os.NewSyscallError("wsarecv", err)
-       }
-       return n, err
+       n, err := fd.pfd.Read(buf)
+       runtime.KeepAlive(fd)
+       return n, wrapSyscallError("wsarecv", err)
 }
 
 func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
-       if len(buf) == 0 {
-               return 0, nil, nil
-       }
-       if err := fd.readLock(); err != nil {
-               return 0, nil, err
-       }
-       defer fd.readUnlock()
-       o := &fd.rop
-       o.InitBuf(buf)
-       n, err := rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error {
-               if o.rsa == nil {
-                       o.rsa = new(syscall.RawSockaddrAny)
-               }
-               o.rsan = int32(unsafe.Sizeof(*o.rsa))
-               return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil)
-       })
-       err = fd.eofError(n, err)
-       if _, ok := err.(syscall.Errno); ok {
-               err = os.NewSyscallError("wsarecvfrom", err)
-       }
-       if err != nil {
-               return n, nil, err
-       }
-       sa, _ := o.rsa.Sockaddr()
-       return n, sa, nil
+       n, sa, err := fd.pfd.RecvFrom(buf)
+       runtime.KeepAlive(fd)
+       return n, sa, wrapSyscallError("wsarecvfrom", err)
 }
 
 func (fd *netFD) Write(buf []byte) (int, error) {
-       if err := fd.writeLock(); err != nil {
-               return 0, err
-       }
-       defer fd.writeUnlock()
-       if race.Enabled {
-               race.ReleaseMerge(unsafe.Pointer(&ioSync))
-       }
-       o := &fd.wop
-       o.InitBuf(buf)
-       n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error {
-               return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil)
-       })
-       if _, ok := err.(syscall.Errno); ok {
-               err = os.NewSyscallError("wsasend", err)
-       }
-       return n, err
+       n, err := fd.pfd.Write(buf)
+       runtime.KeepAlive(fd)
+       return n, wrapSyscallError("wsasend", err)
 }
 
 func (c *conn) writeBuffers(v *Buffers) (int64, error) {
@@ -521,61 +179,33 @@ func (c *conn) writeBuffers(v *Buffers) (int64, error) {
 }
 
 func (fd *netFD) writeBuffers(buf *Buffers) (int64, error) {
-       if len(*buf) == 0 {
-               return 0, nil
-       }
-       if err := fd.writeLock(); err != nil {
-               return 0, err
-       }
-       defer fd.writeUnlock()
-       if race.Enabled {
-               race.ReleaseMerge(unsafe.Pointer(&ioSync))
-       }
-       o := &fd.wop
-       o.InitBufs(buf)
-       n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error {
-               return syscall.WSASend(o.fd.sysfd, &o.bufs[0], uint32(len(*buf)), &o.qty, 0, &o.o, nil)
-       })
-       o.ClearBufs()
-       if _, ok := err.(syscall.Errno); ok {
-               err = os.NewSyscallError("wsasend", err)
-       }
-       testHookDidWritev(n)
-       buf.consume(int64(n))
-       return int64(n), err
+       n, err := fd.pfd.Writev((*[][]byte)(buf))
+       runtime.KeepAlive(fd)
+       return n, wrapSyscallError("wsasend", err)
 }
 
 func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
-       if len(buf) == 0 {
-               return 0, nil
-       }
-       if err := fd.writeLock(); err != nil {
-               return 0, err
-       }
-       defer fd.writeUnlock()
-       o := &fd.wop
-       o.InitBuf(buf)
-       o.sa = sa
-       n, err := wsrv.ExecIO(o, "WSASendto", func(o *operation) error {
-               return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil)
-       })
-       if _, ok := err.(syscall.Errno); ok {
-               err = os.NewSyscallError("wsasendto", err)
-       }
-       return n, err
+       n, err := fd.pfd.WriteTo(buf, sa)
+       runtime.KeepAlive(fd)
+       return n, wrapSyscallError("wsasendto", err)
 }
 
-func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD, error) {
-       // Get new socket.
-       s, err := sysSocket(fd.family, fd.sotype, 0)
+func (fd *netFD) accept() (*netFD, error) {
+       s, rawsa, rsan, errcall, err := fd.pfd.Accept(func() (syscall.Handle, error) {
+               return sysSocket(fd.family, fd.sotype, 0)
+       })
+
        if err != nil {
+               if errcall != "" {
+                       err = wrapSyscallError(errcall, err)
+               }
                return nil, err
        }
 
        // Associate our new socket with IOCP.
        netfd, err := newFD(s, fd.family, fd.sotype, fd.net)
        if err != nil {
-               closeFunc(s)
+               poll.CloseFunc(s)
                return nil, err
        }
        if err := netfd.init(); err != nil {
@@ -583,71 +213,11 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
                return nil, err
        }
 
-       // Submit accept request.
-       o.handle = s
-       o.rsan = int32(unsafe.Sizeof(rawsa[0]))
-       _, err = rsrv.ExecIO(o, "AcceptEx", func(o *operation) error {
-               return acceptFunc(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o)
-       })
-       if err != nil {
-               netfd.Close()
-               if _, ok := err.(syscall.Errno); ok {
-                       err = os.NewSyscallError("acceptex", err)
-               }
-               return nil, err
-       }
-
-       // Inherit properties of the listening socket.
-       err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
-       if err != nil {
-               netfd.Close()
-               return nil, os.NewSyscallError("setsockopt", err)
-       }
-       runtime.KeepAlive(fd)
-       return netfd, nil
-}
-
-func (fd *netFD) accept() (*netFD, error) {
-       if err := fd.readLock(); err != nil {
-               return nil, err
-       }
-       defer fd.readUnlock()
-
-       o := &fd.rop
-       var netfd *netFD
-       var err error
-       var rawsa [2]syscall.RawSockaddrAny
-       for {
-               netfd, err = fd.acceptOne(rawsa[:], o)
-               if err == nil {
-                       break
-               }
-               // Sometimes we see WSAECONNRESET and ERROR_NETNAME_DELETED is
-               // returned here. These happen if connection reset is received
-               // before AcceptEx could complete. These errors relate to new
-               // connection, not to AcceptEx, so ignore broken connection and
-               // try AcceptEx again for more connections.
-               nerr, ok := err.(*os.SyscallError)
-               if !ok {
-                       return nil, err
-               }
-               errno, ok := nerr.Err.(syscall.Errno)
-               if !ok {
-                       return nil, err
-               }
-               switch errno {
-               case syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET:
-                       // ignore these and try again
-               default:
-                       return nil, err
-               }
-       }
-
        // Get local and peer addr out of AcceptEx buffer.
        var lrsa, rrsa *syscall.RawSockaddrAny
        var llen, rlen int32
        syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])),
-               0, uint32(o.rsan), uint32(o.rsan), &lrsa, &llen, &rrsa, &rlen)
+               0, rsan, rsan, &lrsa, &llen, &rrsa, &rlen)
        lsa, _ := lrsa.Sockaddr()
        rsa, _ := rrsa.Sockaddr()
 
index 9e581fcb419ad14b4f773206bf36fc5e1c8f5d10..d67dff8e0569d44a8849ea2dddd621ec7eb9b48d 100644 (file)
@@ -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)
index cf52567fcfdad88ce65d3f5d39650bdb4e7a6610..fee62a972f8c7ed9add7d3b2904e95a2470344b4 100644 (file)
@@ -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
 )
index 63ea35ab8c444a60bc1710ad01ddb2c5ce77686b..4e64dcef517e6a781bc67bca875dbace2bde4acb 100644 (file)
@@ -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
 )
index b7fd344c8ad4a931fce68286f3b58e56a9101807..1cd8fa23ffc45dfa3157b1015164303ffe21b95a 100644 (file)
@@ -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
index ff280c3e4e84e8adc7f8319c94bda916df00a645..5cb85f8c15c393d29d196c885e9b93b0b14809bd 100644 (file)
@@ -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 {
index 7903819585995319901e57a3a82e27f73a043d82..ade71a94906dd2acbcd8f06d56f19906cf124f76 100644 (file)
@@ -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
 }
index 0cc129f34ddae7205e1cc3aa417958f592b2b98d..9cfbc8efc406aa6a7d329510323849642fad5a6e 100644 (file)
@@ -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)
        }
 }
index 6ea318c2a5f3a747da8dba620df3b96805909bf1..f38a3a0d668179388751af798cd1d7b7486f6a8d 100644 (file)
@@ -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)
        }
 }
index 81206ea1cb6c837cad43ab04d0f5e8f707900595..9c27f1baf91ccd05c47df10972506decf678d242 100644 (file)
@@ -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
index 67e80c9c6a7758838c662ce76f76b12ae481218d..7a2b48c6cfa46774f4e7295914b901645efc4903 100644 (file)
@@ -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
 }
index 7e741f979411d8c085732abcd042d493dd1bfef9..c537ea68b2b410cadf094a747d27ad719654b7e4 100644 (file)
@@ -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
 }
index add70c3147e653d69b66feb8190cc6342ec6f8cd..63ca9d47b8ae288219b34aaa8e844049e74c037e 100644 (file)
@@ -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
 }
index bc0b7fb5b2508fa89401a8dad960b2c589442fbe..bccd8b149f738e55ce61d406b1400dff25069b6b 100644 (file)
@@ -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)
index 616a101eacb5086d8772a8c8e64d3e08fec5da9a..3f5be2d62c60a856f0222150af418d75bc6c8edc 100644 (file)
@@ -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
-}
index 16351e1f14ed8d7ee51295b75ef4f6a2ea5b970a..8985f8f23f1241715ebb4fb9b205c4f5d8251e38 100644 (file)
@@ -8,6 +8,7 @@ package net
 
 import (
        "context"
+       "internal/poll"
        "os"
        "syscall"
 )
@@ -43,11 +44,11 @@ func socket(ctx context.Context, net string, family, sotype, proto int, ipv6only
                return nil, err
        }
        if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
-               closeFunc(s)
+               poll.CloseFunc(s)
                return nil, err
        }
        if fd, err = newFD(s, family, sotype, net); err != nil {
-               closeFunc(s)
+               poll.CloseFunc(s)
                return nil, err
        }
 
@@ -127,7 +128,7 @@ func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error {
                if lsa, err = laddr.sockaddr(fd.family); err != nil {
                        return err
                } else if lsa != nil {
-                       if err := syscall.Bind(fd.sysfd, lsa); err != nil {
+                       if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
                                return os.NewSyscallError("bind", err)
                        }
                }
@@ -146,8 +147,8 @@ func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error {
                        return err
                }
        }
-       lsa, _ = syscall.Getsockname(fd.sysfd)
-       if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil {
+       lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
+       if rsa, _ = syscall.Getpeername(fd.pfd.Sysfd); rsa != nil {
                fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa))
        } else {
                fd.setAddr(fd.addrFunc()(lsa), raddr)
@@ -156,23 +157,23 @@ func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error {
 }
 
 func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
-       if err := setDefaultListenerSockopts(fd.sysfd); err != nil {
+       if err := setDefaultListenerSockopts(fd.pfd.Sysfd); err != nil {
                return err
        }
        if lsa, err := laddr.sockaddr(fd.family); err != nil {
                return err
        } else if lsa != nil {
-               if err := syscall.Bind(fd.sysfd, lsa); err != nil {
+               if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
                        return os.NewSyscallError("bind", err)
                }
        }
-       if err := listenFunc(fd.sysfd, backlog); err != nil {
+       if err := listenFunc(fd.pfd.Sysfd, backlog); err != nil {
                return os.NewSyscallError("listen", err)
        }
        if err := fd.init(); err != nil {
                return err
        }
-       lsa, _ := syscall.Getsockname(fd.sysfd)
+       lsa, _ := syscall.Getsockname(fd.pfd.Sysfd)
        fd.setAddr(fd.addrFunc()(lsa), nil)
        return nil
 }
@@ -188,7 +189,7 @@ func (fd *netFD) listenDatagram(laddr sockaddr) error {
                // multiple UDP listeners that listen on the same UDP
                // port to join the same group address.
                if addr.IP != nil && addr.IP.IsMulticast() {
-                       if err := setDefaultMulticastSockopts(fd.sysfd); err != nil {
+                       if err := setDefaultMulticastSockopts(fd.pfd.Sysfd); err != nil {
                                return err
                        }
                        addr := *addr
@@ -204,14 +205,14 @@ func (fd *netFD) listenDatagram(laddr sockaddr) error {
        if lsa, err := laddr.sockaddr(fd.family); err != nil {
                return err
        } else if lsa != nil {
-               if err := syscall.Bind(fd.sysfd, lsa); err != nil {
+               if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
                        return os.NewSyscallError("bind", err)
                }
        }
        if err := fd.init(); err != nil {
                return err
        }
-       lsa, _ := syscall.Getsockname(fd.sysfd)
+       lsa, _ := syscall.Getsockname(fd.pfd.Sysfd)
        fd.setAddr(fd.addrFunc()(lsa), nil)
        return nil
 }
index cd3d56228941e20b406deb9844da285c949d7779..e8af84f418ebe71824f90024734983b9ba04e435 100644 (file)
@@ -7,7 +7,7 @@
 package net
 
 import (
-       "os"
+       "runtime"
        "syscall"
 )
 
@@ -101,27 +101,21 @@ done:
 }
 
 func setReadBuffer(fd *netFD, bytes int) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes))
+       err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
 
 func setWriteBuffer(fd *netFD, bytes int) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes))
+       err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
 
 func setKeepAlive(fd *netFD, keepalive bool) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive)))
+       err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
 
 func setLinger(fd *netFD, sec int) error {
@@ -133,9 +127,7 @@ func setLinger(fd *netFD, sec int) error {
                l.Onoff = 0
                l.Linger = 0
        }
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l))
+       err := fd.pfd.SetsockoptLinger(syscall.SOL_SOCKET, syscall.SO_LINGER, &l)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
index b15c6396ba17f2c8674f8579c8462c9466ba9107..b11f3a4edbe241fb1bc8692a1e869534941884c1 100644 (file)
@@ -7,28 +7,24 @@
 package net
 
 import (
-       "os"
+       "runtime"
        "syscall"
 )
 
 func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
        ip, err := interfaceToIPv4Addr(ifi)
        if err != nil {
-               return os.NewSyscallError("setsockopt", err)
+               return wrapSyscallError("setsockopt", err)
        }
        var a [4]byte
        copy(a[:], ip.To4())
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, a))
+       err = fd.pfd.SetsockoptInet4Addr(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, a)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v))))
+       err := fd.pfd.SetsockoptByte(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v)))
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
index c1dcc911c7363ee956528ca854d7f54ca00bccd5..bd7d8344258e2418fb8ac8c36463deb19fcec96e 100644 (file)
@@ -5,7 +5,7 @@
 package net
 
 import (
-       "os"
+       "runtime"
        "syscall"
 )
 
@@ -15,17 +15,13 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
                v = int32(ifi.Index)
        }
        mreq := &syscall.IPMreqn{Ifindex: v}
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq))
+       err := fd.pfd.SetsockoptIPMreqn(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)))
+       err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
index d50886003eb87de719a0e2a5cc891e7be95cbed6..4e10f2a6a5e9c2752f7823c398e001f772cb1345 100644 (file)
@@ -7,7 +7,7 @@
 package net
 
 import (
-       "os"
+       "runtime"
        "syscall"
 )
 
@@ -16,11 +16,9 @@ func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
        if err := setIPv4MreqToInterface(mreq, ifi); err != nil {
                return err
        }
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
+       err := fd.pfd.SetsockoptIPMreq(syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
 
 func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
@@ -28,19 +26,15 @@ func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
        if ifi != nil {
                v = ifi.Index
        }
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v))
+       err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
 
 func setIPv6MulticastLoopback(fd *netFD, v bool) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v)))
+       err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v))
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
 
 func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
@@ -49,9 +43,7 @@ func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
        if ifi != nil {
                mreq.Interface = uint32(ifi.Index)
        }
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq))
+       err := fd.pfd.SetsockoptIPv6Mreq(syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
index 916debebc6f70338ba71ed06d9d889e4e21467c1..62676039a3b0a528770f8ab37298a9cb27c29dee 100644 (file)
@@ -6,6 +6,7 @@ package net
 
 import (
        "os"
+       "runtime"
        "syscall"
        "unsafe"
 )
@@ -17,17 +18,13 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
        }
        var a [4]byte
        copy(a[:], ip.To4())
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, (*byte)(unsafe.Pointer(&a[0])), 4))
+       err = fd.pfd.Setsockopt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, (*byte)(unsafe.Pointer(&a[0])), 4)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)))
+       err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
index ba266e6534cbc7df02b5c68fe36cfd92e8d5b3f5..b7a842501ece696050990480ffa95dab22e7fff2 100644 (file)
@@ -10,6 +10,7 @@
 package net
 
 import (
+       "internal/poll"
        "os"
        "syscall"
 )
@@ -28,30 +29,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) {
-       // 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
-}
index 69731ebc9143c4f7d869727bda19203a03546277..a544a5b3c32c27370018f3fc424cdec597583518 100644 (file)
@@ -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
index 0d1310eaf9ea793c0e0a98b3a6f2e36a08b4a0ff..7415c763c501bb6e0261a6b4584e16d0f9f81f5d 100644 (file)
@@ -5,7 +5,7 @@
 package net
 
 import (
-       "os"
+       "runtime"
        "syscall"
        "time"
 )
@@ -13,17 +13,15 @@ import (
 const sysTCP_KEEPINTVL = 0x101
 
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
        // The kernel expects seconds so round to next highest second.
        d += (time.Second - time.Nanosecond)
        secs := int(d.Seconds())
-       switch err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs); err {
+       switch err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs); err {
        case nil, syscall.ENOPROTOOPT: // OS X 10.7 and earlier don't support this option
        default:
-               return os.NewSyscallError("setsockopt", err)
+               return wrapSyscallError("setsockopt", err)
        }
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs))
+       err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
index 805b56b5c765ed21a181fd5c1783012f4116c6e2..9cef434b6fa26a50b5bc26a7eaaeb0fcdbe25b58 100644 (file)
@@ -7,14 +7,12 @@
 package net
 
 import (
-       "os"
+       "runtime"
        "syscall"
 )
 
 func setNoDelay(fd *netFD, noDelay bool) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay)))
+       err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
index 76285e5d2e566a24ea1b19d43f9fe06423abdd6a..019fe349eb21d44aed407ee7329d164236805a68 100644 (file)
@@ -5,16 +5,12 @@
 package net
 
 import (
-       "os"
+       "runtime"
        "syscall"
        "time"
 )
 
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
        // The kernel expects milliseconds so round to next highest
        // millisecond.
        d += (time.Millisecond - time.Nanosecond)
@@ -31,5 +27,7 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
        // allocate a constant with a different meaning for the value of
        // TCP_KEEPINTVL on illumos.
 
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD, msecs))
+       err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD, msecs)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
index 8d44fb209546e9dd0957fb9286f5f557fb8b6d9f..c1df6605be4f608056de46fc4ce27dd7ae3210bf 100644 (file)
@@ -7,21 +7,19 @@
 package net
 
 import (
-       "os"
+       "runtime"
        "syscall"
        "time"
 )
 
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
        // The kernel expects seconds so round to next highest second.
        d += (time.Second - time.Nanosecond)
        secs := int(d.Seconds())
-       if err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs); err != nil {
-               return os.NewSyscallError("setsockopt", err)
+       if err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs); err != nil {
+               return wrapSyscallError("setsockopt", err)
        }
-       return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs))
+       err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs)
+       runtime.KeepAlive(fd)
+       return wrapSyscallError("setsockopt", err)
 }
index 45a4dca5257d3e0a7b314fc31c5f53b8593bdae8..73dead11d00be6597a8b4a792fb3e0fde3aaad7d 100644 (file)
@@ -6,16 +6,13 @@ package net
 
 import (
        "os"
+       "runtime"
        "syscall"
        "time"
        "unsafe"
 )
 
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
-       if err := fd.incref(); err != nil {
-               return err
-       }
-       defer fd.decref()
        // The kernel expects milliseconds so round to next highest
        // millisecond.
        d += (time.Millisecond - time.Nanosecond)
@@ -27,6 +24,7 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
        }
        ret := uint32(0)
        size := uint32(unsafe.Sizeof(ka))
-       err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0)
+       err := fd.pfd.WSAIoctl(syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0)
+       runtime.KeepAlive(fd)
        return os.NewSyscallError("wsaioctl", err)
 }
index 55bbf4402d98042f738aec5b244cb4ee21f2de05..9de7801ad107a8b8c2f7f42bd5b39fb183132963 100644 (file)
@@ -6,6 +6,7 @@ package net
 
 import (
        "fmt"
+       "internal/poll"
        "internal/testenv"
        "io"
        "io/ioutil"
@@ -145,9 +146,9 @@ var acceptTimeoutTests = []struct {
 }{
        // Tests that accept deadlines in the past work, even if
        // there's incoming connections available.
-       {-5 * time.Second, [2]error{errTimeout, errTimeout}},
+       {-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}},
 
-       {50 * time.Millisecond, [2]error{nil, errTimeout}},
+       {50 * time.Millisecond, [2]error{nil, poll.ErrTimeout}},
 }
 
 func TestAcceptTimeout(t *testing.T) {
@@ -299,9 +300,9 @@ var readTimeoutTests = []struct {
 }{
        // Tests that read deadlines work, even if there's data ready
        // to be read.
-       {-5 * time.Second, [2]error{errTimeout, errTimeout}},
+       {-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}},
 
-       {50 * time.Millisecond, [2]error{nil, errTimeout}},
+       {50 * time.Millisecond, [2]error{nil, poll.ErrTimeout}},
 }
 
 func TestReadTimeout(t *testing.T) {
@@ -423,9 +424,9 @@ var readFromTimeoutTests = []struct {
 }{
        // Tests that read deadlines work, even if there's data ready
        // to be read.
-       {-5 * time.Second, [2]error{errTimeout, errTimeout}},
+       {-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}},
 
-       {50 * time.Millisecond, [2]error{nil, errTimeout}},
+       {50 * time.Millisecond, [2]error{nil, poll.ErrTimeout}},
 }
 
 func TestReadFromTimeout(t *testing.T) {
@@ -496,9 +497,9 @@ var writeTimeoutTests = []struct {
 }{
        // Tests that write deadlines work, even if there's buffer
        // space available to write.
-       {-5 * time.Second, [2]error{errTimeout, errTimeout}},
+       {-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}},
 
-       {10 * time.Millisecond, [2]error{nil, errTimeout}},
+       {10 * time.Millisecond, [2]error{nil, poll.ErrTimeout}},
 }
 
 func TestWriteTimeout(t *testing.T) {
@@ -610,9 +611,9 @@ var writeToTimeoutTests = []struct {
 }{
        // Tests that write deadlines work, even if there's buffer
        // space available to write.
-       {-5 * time.Second, [2]error{errTimeout, errTimeout}},
+       {-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}},
 
-       {10 * time.Millisecond, [2]error{nil, errTimeout}},
+       {10 * time.Millisecond, [2]error{nil, poll.ErrTimeout}},
 }
 
 func TestWriteToTimeout(t *testing.T) {
index b25d492f5915bd2747a319bd8c270529e599e256..d29514e47b32075d58b697752f444a0a432a8f65 100644 (file)
@@ -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
index 7160d28c3a0fbf113205e417436078ac2ae9f484..4c05be473d9ecd681ebbdde2d0de4d9932660759 100644 (file)
@@ -7,6 +7,7 @@ package net
 import (
        "bytes"
        "fmt"
+       "internal/poll"
        "io"
        "io/ioutil"
        "reflect"
@@ -99,13 +100,13 @@ func TestBuffers_WriteTo(t *testing.T) {
 }
 
 func testBuffer_writeTo(t *testing.T, chunks int, useCopy bool) {
-       oldHook := testHookDidWritev
-       defer func() { testHookDidWritev = oldHook }()
+       oldHook := poll.TestHookDidWritev
+       defer func() { poll.TestHookDidWritev = oldHook }()
        var writeLog struct {
                sync.Mutex
                log []int
        }
-       testHookDidWritev = func(size int) {
+       poll.TestHookDidWritev = func(size int) {
                writeLog.Lock()
                writeLog.log = append(writeLog.log, size)
                writeLog.Unlock()
index 174e6bc51e3a65b8f3546ad7c4c88f966cf006ee..bf0fbf8a13611fedf6f72961fd7d9d36fa6c9634 100644 (file)
@@ -7,10 +7,8 @@
 package net
 
 import (
-       "io"
-       "os"
+       "runtime"
        "syscall"
-       "unsafe"
 )
 
 func (c *conn) writeBuffers(v *Buffers) (int64, error) {
@@ -25,71 +23,7 @@ func (c *conn) writeBuffers(v *Buffers) (int64, error) {
 }
 
 func (fd *netFD) writeBuffers(v *Buffers) (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)
-               v.consume(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
-               }
-       }
-       if _, ok := err.(syscall.Errno); ok {
-               err = os.NewSyscallError("writev", err)
-       }
-       return n, err
+       n, err = fd.pfd.Writev((*[][]byte)(v))
+       runtime.KeepAlive(fd)
+       return n, wrapSyscallError("writev", err)
 }
index 10fd089aea327287b9c4d7aff6ab68ef7b25ca9b..b1ac7c788765006772555f337e55617621388da5 100644 (file)
@@ -8,12 +8,12 @@ import (
        _ "unsafe"
 )
 
-//go:linkname runtime_ignoreHangup net.runtime_ignoreHangup
+//go:linkname runtime_ignoreHangup internal/poll.runtime_ignoreHangup
 func runtime_ignoreHangup() {
        getg().m.ignoreHangup = true
 }
 
-//go:linkname runtime_unignoreHangup net.runtime_unignoreHangup
+//go:linkname runtime_unignoreHangup internal/poll.runtime_unignoreHangup
 func runtime_unignoreHangup(sig string) {
        getg().m.ignoreHangup = false
 }
index 10a3c88a0972dfff2713db59f1f7f6782fcdcd69..ac8d071045828674ed8e603562136b1fef8eb54f 100644 (file)
@@ -81,8 +81,8 @@ var (
        pollcache     pollCache
 )
 
-//go:linkname net_runtime_pollServerInit net.runtime_pollServerInit
-func net_runtime_pollServerInit() {
+//go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit
+func poll_runtime_pollServerInit() {
        netpollinit()
        atomic.Store(&netpollInited, 1)
 }
@@ -91,8 +91,8 @@ func netpollinited() bool {
        return atomic.Load(&netpollInited) != 0
 }
 
-//go:linkname net_runtime_pollOpen net.runtime_pollOpen
-func net_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
+//go:linkname poll_runtime_pollOpen internal/poll.runtime_pollOpen
+func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
        pd := pollcache.alloc()
        lock(&pd.lock)
        if pd.wg != 0 && pd.wg != pdReady {
@@ -115,8 +115,8 @@ func net_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
        return pd, int(errno)
 }
 
-//go:linkname net_runtime_pollClose net.runtime_pollClose
-func net_runtime_pollClose(pd *pollDesc) {
+//go:linkname poll_runtime_pollClose internal/poll.runtime_pollClose
+func poll_runtime_pollClose(pd *pollDesc) {
        if !pd.closing {
                throw("netpollClose: close w/o unblock")
        }
@@ -137,8 +137,8 @@ func (c *pollCache) free(pd *pollDesc) {
        unlock(&c.lock)
 }
 
-//go:linkname net_runtime_pollReset net.runtime_pollReset
-func net_runtime_pollReset(pd *pollDesc, mode int) int {
+//go:linkname poll_runtime_pollReset internal/poll.runtime_pollReset
+func poll_runtime_pollReset(pd *pollDesc, mode int) int {
        err := netpollcheckerr(pd, int32(mode))
        if err != 0 {
                return err
@@ -151,8 +151,8 @@ func net_runtime_pollReset(pd *pollDesc, mode int) int {
        return 0
 }
 
-//go:linkname net_runtime_pollWait net.runtime_pollWait
-func net_runtime_pollWait(pd *pollDesc, mode int) int {
+//go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait
+func poll_runtime_pollWait(pd *pollDesc, mode int) int {
        err := netpollcheckerr(pd, int32(mode))
        if err != 0 {
                return err
@@ -173,16 +173,16 @@ func net_runtime_pollWait(pd *pollDesc, mode int) int {
        return 0
 }
 
-//go:linkname net_runtime_pollWaitCanceled net.runtime_pollWaitCanceled
-func net_runtime_pollWaitCanceled(pd *pollDesc, mode int) {
+//go:linkname poll_runtime_pollWaitCanceled internal/poll.runtime_pollWaitCanceled
+func poll_runtime_pollWaitCanceled(pd *pollDesc, mode int) {
        // This function is used only on windows after a failed attempt to cancel
        // a pending async IO operation. Wait for ioready, ignore closing or timeouts.
        for !netpollblock(pd, int32(mode), true) {
        }
 }
 
-//go:linkname net_runtime_pollSetDeadline net.runtime_pollSetDeadline
-func net_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
+//go:linkname poll_runtime_pollSetDeadline internal/poll.runtime_pollSetDeadline
+func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
        lock(&pd.lock)
        if pd.closing {
                unlock(&pd.lock)
@@ -251,8 +251,8 @@ func net_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
        }
 }
 
-//go:linkname net_runtime_pollUnblock net.runtime_pollUnblock
-func net_runtime_pollUnblock(pd *pollDesc) {
+//go:linkname poll_runtime_pollUnblock internal/poll.runtime_pollUnblock
+func poll_runtime_pollUnblock(pd *pollDesc) {
        lock(&pd.lock)
        if pd.closing {
                throw("netpollUnblock: already closing")
index 7ad115850d58fdc9a505fc7071852d6801aa93f0..32c120c4c30e1c8ed8acc2539acafd75848606e9 100644 (file)
@@ -12,7 +12,8 @@ const _DWORD_MAX = 0xffffffff
 
 const _INVALID_HANDLE_VALUE = ^uintptr(0)
 
-// net_op must be the same as beginning of net.operation. Keep these in sync.
+// net_op must be the same as beginning of internal/poll.operation.
+// Keep these in sync.
 type net_op struct {
        // used by windows
        o overlapped
index 40463117039fa7882c339861b6a7a143477a961e..5b9a264ebd93272ddb570dd3229d657e4f4805cd 100644 (file)
@@ -61,8 +61,8 @@ func sync_runtime_Semacquire(addr *uint32) {
        semacquire(addr, semaBlockProfile)
 }
 
-//go:linkname net_runtime_Semacquire net.runtime_Semacquire
-func net_runtime_Semacquire(addr *uint32) {
+//go:linkname poll_runtime_Semacquire internal/poll.runtime_Semacquire
+func poll_runtime_Semacquire(addr *uint32) {
        semacquire(addr, semaBlockProfile)
 }
 
@@ -76,8 +76,8 @@ func sync_runtime_SemacquireMutex(addr *uint32) {
        semacquire(addr, semaBlockProfile|semaMutexProfile)
 }
 
-//go:linkname net_runtime_Semrelease net.runtime_Semrelease
-func net_runtime_Semrelease(addr *uint32) {
+//go:linkname poll_runtime_Semrelease internal/poll.runtime_Semrelease
+func poll_runtime_Semrelease(addr *uint32) {
        semrelease(addr)
 }
 
index a095ec04fddeac8596b0e09c2e072497e0edf785..c296338e9ba89c2931e4bb34a7d6d6407010005f 100644 (file)
@@ -292,8 +292,8 @@ func siftdownTimer(i int) {
 
 // Entry points for net, time to call nanotime.
 
-//go:linkname net_runtimeNano net.runtimeNano
-func net_runtimeNano() int64 {
+//go:linkname poll_runtimeNano internal/poll.runtimeNano
+func poll_runtimeNano() int64 {
        return nanotime()
 }
 
index f8abf66500eac4271cac9cf30b1902b22d049c35..d6a3858b913376d42b91349c87e4bcd0debc27cc 100644 (file)
@@ -231,6 +231,7 @@ func TestTraceSymbolize(t *testing.T) {
        if runtime.GOOS != "windows" && runtime.GOOS != "plan9" {
                want = append(want, []eventDesc{
                        {trace.EvGoBlockNet, []frame{
+                               {"internal/poll.(*FD).Accept", 0},
                                {"net.(*netFD).accept", 0},
                                {"net.(*TCPListener).accept", 0},
                                {"net.(*TCPListener).Accept", 0},