net: refactor poller into new internal/poll package

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

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

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

Change-Id: I1413685928017c32df5654ded73a2643820977ae
Reviewed-on: https://go-review.googlesource.com/36799
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
Ian Lance Taylor 2017-02-10 14:59:38 -08:00
parent b548eee3d9
commit 3792db5183
79 changed files with 2722 additions and 1619 deletions

95
src/cmd/dist/deps.go vendored
View File

@ -5,68 +5,69 @@ package main
var builddeps = map[string][]string{ var builddeps = map[string][]string{
"bufio": {"bytes", "errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"}, "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"}, "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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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"}, "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/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/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/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"}, "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": {"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"}, "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/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/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/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": {"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/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/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/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/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/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"}, "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"}, "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/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"}, "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/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/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/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/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/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/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/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/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/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/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/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"}, "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": {"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"}, "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/race": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
"internal/singleflight": {"internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"}, "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": {"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/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"}, "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": {"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"}, "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/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"}, "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"}, "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"}, "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/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": {"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/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/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/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"}, "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": {"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"}, "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": {"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"}, "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": {"internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync/atomic"},
"sync/atomic": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"}, "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"}, "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": {"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/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/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"}, "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": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
"unicode/utf16": {"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"}, "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"},
} }

View 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) 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 { if p.Standard {
switch p.ImportPath { switch p.ImportPath {
case "bytes", "net", "os", "runtime/pprof", "sync", "time": case "bytes", "internal/poll", "net", "os", "runtime/pprof", "sync", "time":
extFiles++ extFiles++
} }
} }

View File

@ -150,7 +150,8 @@ var pkgDeps = map[string][]string{
"syscall", "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"}, "path/filepath": {"L2", "os", "syscall"},
"io/ioutil": {"L2", "os", "path/filepath", "time"}, "io/ioutil": {"L2", "os", "path/filepath", "time"},
"os/exec": {"L2", "os", "context", "path/filepath", "syscall"}, "os/exec": {"L2", "os", "context", "path/filepath", "syscall"},
@ -300,7 +301,7 @@ var pkgDeps = map[string][]string{
"net": { "net": {
"L0", "CGO", "L0", "CGO",
"context", "math/rand", "os", "sort", "syscall", "time", "context", "math/rand", "os", "sort", "syscall", "time",
"internal/nettrace", "internal/nettrace", "internal/poll",
"internal/syscall/windows", "internal/singleflight", "internal/race", "internal/syscall/windows", "internal/singleflight", "internal/race",
"golang_org/x/net/lif", "golang_org/x/net/route", "golang_org/x/net/lif", "golang_org/x/net/route",
}, },

View File

@ -0,0 +1,39 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Export guts for testing.
// Since testing imports os and os imports internal/poll,
// the internal/poll tests can not be in package poll.
package poll
var Consume = consume
type FDMutex struct {
fdMutex
}
func (mu *FDMutex) Incref() bool {
return mu.incref()
}
func (mu *FDMutex) IncrefAndClose() bool {
return mu.increfAndClose()
}
func (mu *FDMutex) Decref() bool {
return mu.decref()
}
func (mu *FDMutex) RWLock(read bool) bool {
return mu.rwlock(read)
}
func (mu *FDMutex) RWUnlock(read bool) bool {
return mu.rwunlock(read)
}
func (fd *FD) EOFError(n int, err error) error {
return fd.eofError(n, err)
}

44
src/internal/poll/fd.go Normal file
View File

@ -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) {}

View File

@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package net package poll
import ( import (
"os"
"runtime" "runtime"
"sync" "sync"
"syscall" "syscall"
@ -49,7 +48,7 @@ func newAsyncIO(fn func([]byte) (int, error), b []byte) *asyncIO {
// Go runtime. // Go runtime.
runtime.LockOSThread() runtime.LockOSThread()
runtime_ignoreHangup() runtime_ignoreHangup()
aio.pid = os.Getpid() aio.pid = syscall.Getpid()
aio.mu.Unlock() aio.mu.Unlock()
n, err := fn(b) n, err := fn(b)
@ -64,8 +63,6 @@ func newAsyncIO(fn func([]byte) (int, error), b []byte) *asyncIO {
return aio return aio
} }
var hangupNote os.Signal = syscall.Note("hangup")
// Cancel interrupts the I/O operation, causing // Cancel interrupts the I/O operation, causing
// the Wait function to return. // the Wait function to return.
func (aio *asyncIO) Cancel() { func (aio *asyncIO) Cancel() {
@ -74,11 +71,12 @@ func (aio *asyncIO) Cancel() {
if aio.pid == -1 { if aio.pid == -1 {
return return
} }
proc, err := os.FindProcess(aio.pid) f, e := syscall.Open("/proc/"+itoa(aio.pid)+"/note", syscall.O_WRONLY)
if err != nil { if e != nil {
return return
} }
proc.Signal(hangupNote) syscall.Write(f, []byte("hangup"))
syscall.Close(f)
} }
// Wait for the I/O operation to complete. // Wait for the I/O operation to complete.

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package net package poll
import "sync/atomic" import "sync/atomic"
// fdMutex is a specialized synchronization primitive that manages // fdMutex is a specialized synchronization primitive that manages
// lifetime of an fd and serializes access to Read, Write and Close // lifetime of an fd and serializes access to Read, Write and Close
// methods on netFD. // methods on FD.
type fdMutex struct { type fdMutex struct {
state uint64 state uint64
rsema uint32 rsema uint32
@ -16,7 +16,7 @@ type fdMutex struct {
} }
// fdMutex.state is organized as follows: // 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 read operations.
// 1 bit - lock for write operations. // 1 bit - lock for write operations.
// 20 bits - total number of references (read+write+misc). // 20 bits - total number of references (read+write+misc).
@ -196,9 +196,9 @@ func runtime_Semrelease(sema *uint32)
// incref adds a reference to fd. // incref adds a reference to fd.
// It returns an error when fd cannot be used. // It returns an error when fd cannot be used.
func (fd *netFD) incref() error { func (fd *FD) incref() error {
if !fd.fdmu.incref() { if !fd.fdmu.incref() {
return errClosing return ErrClosing
} }
return nil return nil
} }
@ -206,17 +206,18 @@ func (fd *netFD) incref() error {
// decref removes a reference from fd. // decref removes a reference from fd.
// It also closes fd when the state of fd is set to closed and there // It also closes fd when the state of fd is set to closed and there
// is no remaining reference. // is no remaining reference.
func (fd *netFD) decref() { func (fd *FD) decref() error {
if fd.fdmu.decref() { if fd.fdmu.decref() {
fd.destroy() return fd.destroy()
} }
return nil
} }
// readLock adds a reference to fd and locks fd for reading. // readLock adds a reference to fd and locks fd for reading.
// It returns an error when fd cannot be used 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) { if !fd.fdmu.rwlock(true) {
return errClosing return ErrClosing
} }
return nil return nil
} }
@ -224,7 +225,7 @@ func (fd *netFD) readLock() error {
// readUnlock removes a reference from fd and unlocks fd for reading. // 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 // It also closes fd when the state of fd is set to closed and there
// is no remaining reference. // is no remaining reference.
func (fd *netFD) readUnlock() { func (fd *FD) readUnlock() {
if fd.fdmu.rwunlock(true) { if fd.fdmu.rwunlock(true) {
fd.destroy() fd.destroy()
} }
@ -232,9 +233,9 @@ func (fd *netFD) readUnlock() {
// writeLock adds a reference to fd and locks fd for writing. // writeLock adds a reference to fd and locks fd for writing.
// It returns an error when fd cannot be used 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) { if !fd.fdmu.rwlock(false) {
return errClosing return ErrClosing
} }
return nil return nil
} }
@ -242,7 +243,7 @@ func (fd *netFD) writeLock() error {
// writeUnlock removes a reference from fd and unlocks fd for writing. // 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 // It also closes fd when the state of fd is set to closed and there
// is no remaining reference. // is no remaining reference.
func (fd *netFD) writeUnlock() { func (fd *FD) writeUnlock() {
if fd.fdmu.rwunlock(false) { if fd.fdmu.rwunlock(false) {
fd.destroy() fd.destroy()
} }

View File

@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package net package poll_test
import ( import (
. "internal/poll"
"math/rand" "math/rand"
"runtime" "runtime"
"testing" "testing"
@ -12,57 +13,57 @@ import (
) )
func TestMutexLock(t *testing.T) { func TestMutexLock(t *testing.T) {
var mu fdMutex var mu FDMutex
if !mu.incref() { if !mu.Incref() {
t.Fatal("broken") t.Fatal("broken")
} }
if mu.decref() { if mu.Decref() {
t.Fatal("broken") t.Fatal("broken")
} }
if !mu.rwlock(true) { if !mu.RWLock(true) {
t.Fatal("broken") t.Fatal("broken")
} }
if mu.rwunlock(true) { if mu.RWUnlock(true) {
t.Fatal("broken") t.Fatal("broken")
} }
if !mu.rwlock(false) { if !mu.RWLock(false) {
t.Fatal("broken") t.Fatal("broken")
} }
if mu.rwunlock(false) { if mu.RWUnlock(false) {
t.Fatal("broken") t.Fatal("broken")
} }
} }
func TestMutexClose(t *testing.T) { func TestMutexClose(t *testing.T) {
var mu fdMutex var mu FDMutex
if !mu.increfAndClose() { if !mu.IncrefAndClose() {
t.Fatal("broken") t.Fatal("broken")
} }
if mu.incref() { if mu.Incref() {
t.Fatal("broken") t.Fatal("broken")
} }
if mu.rwlock(true) { if mu.RWLock(true) {
t.Fatal("broken") t.Fatal("broken")
} }
if mu.rwlock(false) { if mu.RWLock(false) {
t.Fatal("broken") t.Fatal("broken")
} }
if mu.increfAndClose() { if mu.IncrefAndClose() {
t.Fatal("broken") t.Fatal("broken")
} }
} }
func TestMutexCloseUnblock(t *testing.T) { func TestMutexCloseUnblock(t *testing.T) {
c := make(chan bool) c := make(chan bool)
var mu fdMutex var mu FDMutex
mu.rwlock(true) mu.RWLock(true)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
go func() { go func() {
if mu.rwlock(true) { if mu.RWLock(true) {
t.Error("broken") t.Error("broken")
return return
} }
@ -76,7 +77,7 @@ func TestMutexCloseUnblock(t *testing.T) {
t.Fatal("broken") t.Fatal("broken")
default: default:
} }
mu.increfAndClose() // Must unblock the readers. mu.IncrefAndClose() // Must unblock the readers.
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
select { select {
case <-c: case <-c:
@ -84,10 +85,10 @@ func TestMutexCloseUnblock(t *testing.T) {
t.Fatal("broken") t.Fatal("broken")
} }
} }
if mu.decref() { if mu.Decref() {
t.Fatal("broken") t.Fatal("broken")
} }
if !mu.rwunlock(true) { if !mu.RWUnlock(true) {
t.Fatal("broken") t.Fatal("broken")
} }
} }
@ -102,22 +103,22 @@ func TestMutexPanic(t *testing.T) {
f() f()
} }
var mu fdMutex var mu FDMutex
ensurePanics(func() { mu.decref() }) ensurePanics(func() { mu.Decref() })
ensurePanics(func() { mu.rwunlock(true) }) ensurePanics(func() { mu.RWUnlock(true) })
ensurePanics(func() { mu.rwunlock(false) }) ensurePanics(func() { mu.RWUnlock(false) })
ensurePanics(func() { mu.incref(); mu.decref(); mu.decref() }) ensurePanics(func() { mu.Incref(); mu.Decref(); mu.Decref() })
ensurePanics(func() { mu.rwlock(true); mu.rwunlock(true); mu.rwunlock(true) }) 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.RWLock(false); mu.RWUnlock(false); mu.RWUnlock(false) })
// ensure that it's still not broken // ensure that it's still not broken
mu.incref() mu.Incref()
mu.decref() mu.Decref()
mu.rwlock(true) mu.RWLock(true)
mu.rwunlock(true) mu.RWUnlock(true)
mu.rwlock(false) mu.RWLock(false)
mu.rwunlock(false) mu.RWUnlock(false)
} }
func TestMutexStress(t *testing.T) { func TestMutexStress(t *testing.T) {
@ -129,7 +130,7 @@ func TestMutexStress(t *testing.T) {
} }
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P)) defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
done := make(chan bool) done := make(chan bool)
var mu fdMutex var mu FDMutex
var readState [2]uint64 var readState [2]uint64
var writeState [2]uint64 var writeState [2]uint64
for p := 0; p < P; p++ { for p := 0; p < P; p++ {
@ -138,16 +139,16 @@ func TestMutexStress(t *testing.T) {
for i := 0; i < N; i++ { for i := 0; i < N; i++ {
switch r.Intn(3) { switch r.Intn(3) {
case 0: case 0:
if !mu.incref() { if !mu.Incref() {
t.Error("broken") t.Error("broken")
return return
} }
if mu.decref() { if mu.Decref() {
t.Error("broken") t.Error("broken")
return return
} }
case 1: case 1:
if !mu.rwlock(true) { if !mu.RWLock(true) {
t.Error("broken") t.Error("broken")
return return
} }
@ -158,12 +159,12 @@ func TestMutexStress(t *testing.T) {
} }
readState[0]++ readState[0]++
readState[1]++ readState[1]++
if mu.rwunlock(true) { if mu.RWUnlock(true) {
t.Error("broken") t.Error("broken")
return return
} }
case 2: case 2:
if !mu.rwlock(false) { if !mu.RWLock(false) {
t.Error("broken") t.Error("broken")
return return
} }
@ -174,7 +175,7 @@ func TestMutexStress(t *testing.T) {
} }
writeState[0]++ writeState[0]++
writeState[1]++ writeState[1]++
if mu.rwunlock(false) { if mu.RWUnlock(false) {
t.Error("broken") t.Error("broken")
return return
} }
@ -186,10 +187,10 @@ func TestMutexStress(t *testing.T) {
for p := 0; p < P; p++ { for p := 0; p < P; p++ {
<-done <-done
} }
if !mu.increfAndClose() { if !mu.IncrefAndClose() {
t.Fatal("broken") t.Fatal("broken")
} }
if !mu.decref() { if !mu.Decref() {
t.Fatal("broken") t.Fatal("broken")
} }
} }

View File

@ -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")
}

View File

@ -2,34 +2,32 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package net package poll
import ( import (
"runtime"
"syscall" "syscall"
"time" "time"
) )
type pollDesc struct { type pollDesc struct {
fd *netFD fd *FD
closing bool 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) close() {}
func (pd *pollDesc) evict() { func (pd *pollDesc) evict() {
pd.closing = true pd.closing = true
if pd.fd != nil { if pd.fd != nil {
syscall.StopIO(pd.fd.sysfd) syscall.StopIO(pd.fd.Sysfd)
runtime.KeepAlive(pd.fd)
} }
} }
func (pd *pollDesc) prepare(mode int) error { func (pd *pollDesc) prepare(mode int) error {
if pd.closing { if pd.closing {
return errClosing return ErrClosing
} }
return nil return nil
} }
@ -40,9 +38,9 @@ func (pd *pollDesc) prepareWrite() error { return pd.prepare('w') }
func (pd *pollDesc) wait(mode int) error { func (pd *pollDesc) wait(mode int) error {
if pd.closing { if pd.closing {
return errClosing return ErrClosing
} }
return errTimeout return ErrTimeout
} }
func (pd *pollDesc) waitRead() error { return pd.wait('r') } func (pd *pollDesc) waitRead() error { return pd.wait('r') }
@ -55,19 +53,19 @@ func (pd *pollDesc) waitCanceledRead() {}
func (pd *pollDesc) waitCanceledWrite() {} 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') 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') 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') 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() d := t.UnixNano()
if t.IsZero() { if t.IsZero() {
d = 0 d = 0
@ -77,12 +75,12 @@ func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
} }
switch mode { switch mode {
case 'r': case 'r':
syscall.SetReadDeadline(fd.sysfd, d) syscall.SetReadDeadline(fd.Sysfd, d)
case 'w': case 'w':
syscall.SetWriteDeadline(fd.sysfd, d) syscall.SetWriteDeadline(fd.Sysfd, d)
case 'r' + 'w': case 'r' + 'w':
syscall.SetReadDeadline(fd.sysfd, d) syscall.SetReadDeadline(fd.Sysfd, d)
syscall.SetWriteDeadline(fd.sysfd, d) syscall.SetWriteDeadline(fd.Sysfd, d)
} }
fd.decref() fd.decref()
return nil return nil

View File

@ -4,10 +4,10 @@
// +build darwin dragonfly freebsd linux netbsd openbsd windows solaris // +build darwin dragonfly freebsd linux netbsd openbsd windows solaris
package net package poll
import ( import (
"runtime" "errors"
"sync" "sync"
"syscall" "syscall"
"time" "time"
@ -31,11 +31,14 @@ type pollDesc struct {
var serverInit sync.Once var serverInit sync.Once
func (pd *pollDesc) init(fd *netFD) error { func (pd *pollDesc) init(fd *FD) error {
serverInit.Do(runtime_pollServerInit) serverInit.Do(runtime_pollServerInit)
ctx, errno := runtime_pollOpen(uintptr(fd.sysfd)) ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd))
runtime.KeepAlive(fd)
if errno != 0 { if errno != 0 {
if ctx != 0 {
runtime_pollUnblock(ctx)
runtime_pollClose(ctx)
}
return syscall.Errno(errno) return syscall.Errno(errno)
} }
pd.runtimeCtx = ctx pd.runtimeCtx = ctx
@ -59,6 +62,9 @@ func (pd *pollDesc) evict() {
} }
func (pd *pollDesc) prepare(mode int) error { func (pd *pollDesc) prepare(mode int) error {
if pd.runtimeCtx == 0 {
return nil
}
res := runtime_pollReset(pd.runtimeCtx, mode) res := runtime_pollReset(pd.runtimeCtx, mode)
return convertErr(res) return convertErr(res)
} }
@ -72,6 +78,9 @@ func (pd *pollDesc) prepareWrite() error {
} }
func (pd *pollDesc) wait(mode int) 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) res := runtime_pollWait(pd.runtimeCtx, mode)
return convertErr(res) return convertErr(res)
} }
@ -85,6 +94,9 @@ func (pd *pollDesc) waitWrite() error {
} }
func (pd *pollDesc) waitCanceled(mode int) { func (pd *pollDesc) waitCanceled(mode int) {
if pd.runtimeCtx == 0 {
return
}
runtime_pollWaitCanceled(pd.runtimeCtx, mode) runtime_pollWaitCanceled(pd.runtimeCtx, mode)
} }
@ -101,27 +113,27 @@ func convertErr(res int) error {
case 0: case 0:
return nil return nil
case 1: case 1:
return errClosing return ErrClosing
case 2: case 2:
return errTimeout return ErrTimeout
} }
println("unreachable: ", res) println("unreachable: ", res)
panic("unreachable") panic("unreachable")
} }
func (fd *netFD) setDeadline(t time.Time) error { func (fd *FD) SetDeadline(t time.Time) error {
return setDeadlineImpl(fd, t, 'r'+'w') 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') 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') 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)) diff := int64(time.Until(t))
d := runtimeNano() + diff d := runtimeNano() + diff
if d <= 0 && diff > 0 { 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 { if err := fd.incref(); err != nil {
return err return err
} }
if fd.pd.runtimeCtx == 0 {
return errors.New("file type does not support deadlines")
}
runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode) runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode)
fd.decref() fd.decref()
return nil return nil

View File

@ -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)
}

View File

@ -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)
}
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -4,11 +4,9 @@
// +build freebsd linux // +build freebsd linux
package net package poll
import "syscall" import "syscall"
var ( // Accept4Func is used to hook the accept4 call.
// Placeholders for socket system calls. var Accept4Func func(int, int) (int, syscall.Sockaddr, error) = syscall.Accept4
accept4Func func(int, int) (int, syscall.Sockaddr, error) = syscall.Accept4
)

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

39
src/internal/poll/str.go Normal file
View File

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

View File

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

View File

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

View File

@ -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)
}
}
}

View File

@ -7,6 +7,7 @@ package net
import ( import (
"context" "context"
"internal/nettrace" "internal/nettrace"
"internal/poll"
"time" "time"
) )
@ -110,7 +111,7 @@ func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, er
} }
timeRemaining := deadline.Sub(now) timeRemaining := deadline.Sub(now)
if timeRemaining <= 0 { if timeRemaining <= 0 {
return time.Time{}, errTimeout return time.Time{}, poll.ErrTimeout
} }
// Tentatively allocate equal time to each remaining address. // Tentatively allocate equal time to each remaining address.
timeout := timeRemaining / time.Duration(addrsRemaining) timeout := timeRemaining / time.Duration(addrsRemaining)

View File

@ -7,6 +7,7 @@ package net
import ( import (
"bufio" "bufio"
"context" "context"
"internal/poll"
"internal/testenv" "internal/testenv"
"io" "io"
"net/internal/socktest" "net/internal/socktest"
@ -94,7 +95,7 @@ func TestDialTimeoutFDLeak(t *testing.T) {
default: default:
sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) { sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
time.Sleep(2 * T) time.Sleep(2 * T)
return nil, errTimeout return nil, poll.ErrTimeout
}) })
defer sw.Set(socktest.FilterConnect, nil) defer sw.Set(socktest.FilterConnect, nil)
} }
@ -585,8 +586,8 @@ func TestDialerPartialDeadline(t *testing.T) {
{now, noDeadline, 1, noDeadline, nil}, {now, noDeadline, 1, noDeadline, nil},
// Step the clock forward and cross the deadline. // Step the clock forward and cross the deadline.
{now.Add(-1 * time.Millisecond), now, 1, now, nil}, {now.Add(-1 * time.Millisecond), now, 1, now, nil},
{now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout}, {now.Add(0 * time.Millisecond), now, 1, noDeadline, poll.ErrTimeout},
{now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout}, {now.Add(1 * time.Millisecond), now, 1, noDeadline, poll.ErrTimeout},
} }
for i, tt := range testCases { for i, tt := range testCases {
deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs) deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs)

View File

@ -9,6 +9,7 @@ package net
import ( import (
"context" "context"
"fmt" "fmt"
"internal/poll"
"internal/testenv" "internal/testenv"
"io/ioutil" "io/ioutil"
"os" "os"
@ -767,7 +768,7 @@ func TestRetryTimeout(t *testing.T) {
if s == "192.0.2.1:53" { if s == "192.0.2.1:53" {
deadline0 = deadline deadline0 = deadline
time.Sleep(10 * time.Millisecond) time.Sleep(10 * time.Millisecond)
return nil, errTimeout return nil, poll.ErrTimeout
} }
if deadline == deadline0 { if deadline == deadline0 {

21
src/net/error_posix.go Normal file
View File

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

View File

@ -7,6 +7,7 @@ package net
import ( import (
"context" "context"
"fmt" "fmt"
"internal/poll"
"io" "io"
"io/ioutil" "io/ioutil"
"net/internal/socktest" "net/internal/socktest"
@ -87,7 +88,7 @@ second:
return nil return nil
} }
switch err := nestedErr.(type) { switch err := nestedErr.(type) {
case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError: case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *poll.TimeoutError, UnknownNetworkError:
return nil return nil
case *os.SyscallError: case *os.SyscallError:
nestedErr = err.Err nestedErr = err.Err
@ -97,7 +98,7 @@ second:
goto third goto third
} }
switch nestedErr { switch nestedErr {
case errCanceled, errClosing, errMissingAddress, errNoSuitableAddress, case errCanceled, poll.ErrClosing, errMissingAddress, errNoSuitableAddress,
context.DeadlineExceeded, context.Canceled: context.DeadlineExceeded, context.Canceled:
return nil return nil
} }
@ -432,7 +433,7 @@ second:
goto third goto third
} }
switch nestedErr { switch nestedErr {
case errClosing, errTimeout: case poll.ErrClosing, poll.ErrTimeout:
return nil return nil
} }
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@ -467,14 +468,14 @@ second:
return nil return nil
} }
switch err := nestedErr.(type) { switch err := nestedErr.(type) {
case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError: case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *poll.TimeoutError, UnknownNetworkError:
return nil return nil
case *os.SyscallError: case *os.SyscallError:
nestedErr = err.Err nestedErr = err.Err
goto third goto third
} }
switch nestedErr { switch nestedErr {
case errCanceled, errClosing, errMissingAddress, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF: case errCanceled, poll.ErrClosing, errMissingAddress, poll.ErrTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
return nil return nil
} }
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@ -517,7 +518,7 @@ second:
goto third goto third
} }
switch nestedErr { switch nestedErr {
case errClosing: case poll.ErrClosing:
return nil return nil
} }
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@ -613,7 +614,7 @@ second:
goto third goto third
} }
switch nestedErr { switch nestedErr {
case errClosing, errTimeout: case poll.ErrClosing, poll.ErrTimeout:
return nil return nil
} }
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@ -692,7 +693,7 @@ second:
goto third goto third
} }
switch nestedErr { switch nestedErr {
case errClosing: case poll.ErrClosing:
return nil return nil
} }
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)

View File

@ -5,23 +5,15 @@
package net package net
import ( import (
"internal/poll"
"io" "io"
"os" "os"
"sync/atomic"
"syscall" "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. // Network file descriptor.
type netFD struct { type netFD struct {
// locking/lifetime of sysfd + serialize access to Read and Write methods pfd poll.FD
fdmu fdMutex
// immutable until Close // immutable until Close
net string net string
@ -30,14 +22,6 @@ type netFD struct {
listen, ctl, data *os.File listen, ctl, data *os.File
laddr, raddr Addr laddr, raddr Addr
isStream bool 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 ( var (
@ -49,7 +33,7 @@ func sysInit() {
} }
func newFD(net, name string, listen, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) { func newFD(net, name string, listen, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
return &netFD{ ret := &netFD{
net: net, net: net,
n: name, n: name,
dir: netdir + "/" + net + "/" + 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, ctl: ctl, data: data,
laddr: laddr, laddr: laddr,
raddr: raddr, raddr: raddr,
}, nil }
ret.pfd.Destroy = ret.destroy
return ret, nil
} }
func (fd *netFD) init() error { func (fd *netFD) init() error {
@ -99,28 +85,10 @@ func (fd *netFD) destroy() {
} }
func (fd *netFD) Read(b []byte) (n int, err error) { func (fd *netFD) Read(b []byte) (n int, err error) {
if fd.rtimedout.isSet() {
return 0, errTimeout
}
if !fd.ok() || fd.data == nil { if !fd.ok() || fd.data == nil {
return 0, syscall.EINVAL return 0, syscall.EINVAL
} }
if err := fd.readLock(); err != nil { n, err = fd.pfd.Read(fd.data.Read, b)
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
}
if fd.net == "udp" && err == io.EOF { if fd.net == "udp" && err == io.EOF {
n = 0 n = 0
err = nil 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) { func (fd *netFD) Write(b []byte) (n int, err error) {
if fd.wtimedout.isSet() {
return 0, errTimeout
}
if !fd.ok() || fd.data == nil { if !fd.ok() || fd.data == nil {
return 0, syscall.EINVAL return 0, syscall.EINVAL
} }
if err := fd.writeLock(); err != nil { return fd.pfd.Write(fd.data.Write, b)
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
} }
func (fd *netFD) closeRead() error { func (fd *netFD) closeRead() error {
@ -163,8 +118,8 @@ func (fd *netFD) closeWrite() error {
} }
func (fd *netFD) Close() error { func (fd *netFD) Close() error {
if !fd.fdmu.increfAndClose() { if err := fd.pfd.Close(); err != nil {
return errClosing return err
} }
if !fd.ok() { if !fd.ok() {
return syscall.EINVAL 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 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 { func setReadBuffer(fd *netFD, bytes int) error {
return syscall.EPLAN9 return syscall.EPLAN9
} }
@ -294,11 +178,3 @@ func setReadBuffer(fd *netFD, bytes int) error {
func setWriteBuffer(fd *netFD, bytes int) error { func setWriteBuffer(fd *netFD, bytes int) error {
return syscall.EPLAN9 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")
}

View File

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

View File

@ -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)
}
}
}

View File

@ -8,7 +8,7 @@ package net
import ( import (
"context" "context"
"io" "internal/poll"
"os" "os"
"runtime" "runtime"
"sync/atomic" "sync/atomic"
@ -17,38 +17,36 @@ import (
// Network file descriptor. // Network file descriptor.
type netFD struct { type netFD struct {
// locking/lifetime of sysfd + serialize access to Read and Write methods pfd poll.FD
fdmu fdMutex
// immutable until Close // immutable until Close
sysfd int
family int family int
sotype int sotype int
isStream bool
isConnected bool isConnected bool
net string net string
laddr Addr laddr Addr
raddr Addr raddr Addr
// writev cache.
iovecs *[]syscall.Iovec
// wait server
pd pollDesc
} }
func sysInit() { func sysInit() {
} }
func newFD(sysfd, family, sotype int, net string) (*netFD, error) { 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 { func (fd *netFD) init() error {
if err := fd.pd.init(fd); err != nil { return fd.pfd.Init()
return err
}
return nil
} }
func (fd *netFD) setAddr(laddr, raddr Addr) { 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, // Do not need to call fd.writeLock here,
// because fd is not yet accessible to user, // because fd is not yet accessible to user,
// so no concurrent operations are possible. // 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 syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
case nil, syscall.EISCONN: case nil, syscall.EISCONN:
select { select {
@ -80,9 +78,10 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
return mapErr(ctx.Err()) return mapErr(ctx.Err())
default: default:
} }
if err := fd.init(); err != nil { if err := fd.pfd.Init(); err != nil {
return err return err
} }
runtime.KeepAlive(fd)
return nil return nil
case syscall.EINVAL: case syscall.EINVAL:
// On Solaris we can see EINVAL if the socket has // 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: default:
return os.NewSyscallError("connect", err) return os.NewSyscallError("connect", err)
} }
if err := fd.init(); err != nil { if err := fd.pfd.Init(); err != nil {
return err return err
} }
if deadline, _ := ctx.Deadline(); !deadline.IsZero() { if deadline, _ := ctx.Deadline(); !deadline.IsZero() {
fd.setWriteDeadline(deadline) fd.pfd.SetWriteDeadline(deadline)
defer fd.setWriteDeadline(noDeadline) defer fd.pfd.SetWriteDeadline(noDeadline)
} }
// Start the "interrupter" goroutine, if this context might be canceled. // 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() { defer func() {
close(done) close(done)
if ctxErr := <-interruptRes; ctxErr != nil && ret == nil { 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 // but the connect code below had returned from
// waitWrite already and did a successful connect (ret // waitWrite already and did a successful connect (ret
// == nil). Because we've now poisoned the connection // == 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 // Force the runtime's poller to immediately give up
// waiting for writability, unblocking waitWrite // waiting for writability, unblocking waitWrite
// below. // below.
fd.setWriteDeadline(aLongTimeAgo) fd.pfd.SetWriteDeadline(aLongTimeAgo)
testHookCanceledDial() testHookCanceledDial()
interruptRes <- ctx.Err() interruptRes <- ctx.Err()
case <-done: 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 // SO_ERROR socket option to see if the connection
// succeeded or failed. See issue 7474 for further // succeeded or failed. See issue 7474 for further
// details. // details.
if err := fd.pd.waitWrite(); err != nil { if err := fd.pfd.WaitWrite(); err != nil {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return mapErr(ctx.Err()) return mapErr(ctx.Err())
@ -161,7 +160,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
} }
return err 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 { if err != nil {
return os.NewSyscallError("getsockopt", err) 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. // See golang.org/issue/14548.
// On Darwin, multiple connect system calls on // On Darwin, multiple connect system calls on
// a non-blocking socket never harm SO_ERROR. // 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: case nil, syscall.EISCONN:
return nil return nil
} }
default: default:
return os.NewSyscallError("getsockopt", err) 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 { func (fd *netFD) Close() error {
if !fd.fdmu.increfAndClose() { runtime.SetFinalizer(fd, nil)
return errClosing return fd.pfd.Close()
}
// 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
} }
func (fd *netFD) shutdown(how int) error { func (fd *netFD) shutdown(how int) error {
if err := fd.incref(); err != nil { err := fd.pfd.Shutdown(how)
return err runtime.KeepAlive(fd)
} return wrapSyscallError("shutdown", err)
defer fd.decref()
return os.NewSyscallError("shutdown", syscall.Shutdown(fd.sysfd, how))
} }
func (fd *netFD) closeRead() error { func (fd *netFD) closeRead() error {
@ -224,233 +204,59 @@ func (fd *netFD) closeWrite() error {
} }
func (fd *netFD) Read(p []byte) (n int, err error) { func (fd *netFD) Read(p []byte) (n int, err error) {
if err := fd.readLock(); err != nil { n, err = fd.pfd.Read(p)
return 0, err runtime.KeepAlive(fd)
} return n, wrapSyscallError("read", 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
} }
func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
if err := fd.readLock(); err != nil { n, sa, err = fd.pfd.RecvFrom(p)
return 0, nil, err runtime.KeepAlive(fd)
} return n, sa, wrapSyscallError("recvfrom", 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
} }
func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
if err := fd.readLock(); err != nil { n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob)
return 0, 0, 0, nil, err runtime.KeepAlive(fd)
} return n, oobn, flags, sa, wrapSyscallError("recvmsg", 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
} }
func (fd *netFD) Write(p []byte) (nn int, err error) { func (fd *netFD) Write(p []byte) (nn int, err error) {
if err := fd.writeLock(); err != nil { nn, err = fd.pfd.Write(p)
return 0, err runtime.KeepAlive(fd)
} return nn, wrapSyscallError("write", 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
} }
func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) { func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
if err := fd.writeLock(); err != nil { n, err = fd.pfd.WriteTo(p, sa)
return 0, err runtime.KeepAlive(fd)
} return n, wrapSyscallError("sendto", 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
} }
func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
if err := fd.writeLock(); err != nil { n, oobn, err = fd.pfd.WriteMsg(p, oob, sa)
return 0, 0, err runtime.KeepAlive(fd)
} return n, oobn, wrapSyscallError("sendmsg", 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
} }
func (fd *netFD) accept() (netfd *netFD, err error) { func (fd *netFD) accept() (netfd *netFD, err error) {
if err := fd.readLock(); err != nil { d, rsa, errcall, err := fd.pfd.Accept()
return nil, err if err != nil {
} if errcall != "" {
defer fd.readUnlock() err = wrapSyscallError(errcall, err)
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
} }
break return nil, err
} }
if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil { if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil {
closeFunc(s) poll.CloseFunc(d)
return nil, err return nil, err
} }
if err = netfd.init(); err != nil { if err = netfd.init(); err != nil {
fd.Close() fd.Close()
return nil, err return nil, err
} }
lsa, _ := syscall.Getsockname(netfd.sysfd) lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd)
netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa)) netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
return netfd, nil return netfd, nil
} }
@ -503,7 +309,7 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) {
} }
func (fd *netFD) dup() (f *os.File, 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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -6,62 +6,14 @@ package net
import ( import (
"context" "context"
"internal/race" "internal/poll"
"os" "os"
"runtime" "runtime"
"sync"
"syscall" "syscall"
"unsafe" "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() { 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 // canUseConnectEx reports whether we can use the ConnectEx Windows API call
@ -75,257 +27,39 @@ func canUseConnectEx(net string) bool {
return false 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. // Network file descriptor.
type netFD struct { type netFD struct {
// locking/lifetime of sysfd + serialize access to Read and Write methods pfd poll.FD
fdmu fdMutex
// immutable until Close // immutable until Close
sysfd syscall.Handle family int
family int sotype int
sotype int isConnected bool
isStream bool net string
isConnected bool laddr Addr
skipSyncNotif bool raddr Addr
net string
laddr Addr
raddr Addr
rop operation // read operation
wop operation // write operation
// wait server
pd pollDesc
} }
func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) { func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) {
if initErr != nil { ret := &netFD{
return nil, initErr 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 ret, nil
return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net, isStream: sotype == syscall.SOCK_STREAM}, nil
} }
func (fd *netFD) init() error { func (fd *netFD) init() error {
if err := fd.pd.init(fd); err != nil { errcall, err := fd.pfd.Init(fd.net)
return err if errcall != "" {
err = wrapSyscallError(errcall, err)
} }
if hasLoadSetFileCompletionNotificationModes { return err
// 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)
}
return nil
} }
func (fd *netFD) setAddr(laddr, raddr Addr) { 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 return err
} }
if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
fd.setWriteDeadline(deadline) fd.pfd.SetWriteDeadline(deadline)
defer fd.setWriteDeadline(noDeadline) defer fd.pfd.SetWriteDeadline(noDeadline)
} }
if !canUseConnectEx(fd.net) { if !canUseConnectEx(fd.net) {
err := connectFunc(fd.sysfd, ra) err := connectFunc(fd.pfd.Sysfd, ra)
return os.NewSyscallError("connect", err) return os.NewSyscallError("connect", err)
} }
// ConnectEx windows API requires an unconnected, previously bound socket. // 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: default:
panic("unexpected type in connect") 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) 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 // Wait for the goroutine converting context.Done into a write timeout
// to exist, otherwise our caller might cancel the context and // 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(): case <-ctx.Done():
// Force the runtime's poller to immediately give // Force the runtime's poller to immediately give
// up waiting for writability. // up waiting for writability.
fd.setWriteDeadline(aLongTimeAgo) fd.pfd.SetWriteDeadline(aLongTimeAgo)
<-done <-done
case <-done: case <-done:
} }
}() }()
_, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error { // Call ConnectEx API.
return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o) if err := fd.pfd.ConnectEx(ra); err != nil {
})
if err != nil {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return mapErr(ctx.Err()) return mapErr(ctx.Err())
@ -398,38 +127,18 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
} }
} }
// Refresh socket properties. // 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)))) 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) 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)
} }
func (fd *netFD) Close() error { func (fd *netFD) Close() error {
if !fd.fdmu.increfAndClose() { runtime.SetFinalizer(fd, nil)
return errClosing return fd.pfd.Close()
}
// unblock pending reader and writer
fd.pd.evict()
fd.decref()
return nil
} }
func (fd *netFD) shutdown(how int) error { func (fd *netFD) shutdown(how int) error {
if err := fd.incref(); err != nil { err := fd.pfd.Shutdown(how)
return err runtime.KeepAlive(fd)
} return err
defer fd.decref()
return syscall.Shutdown(fd.sysfd, how)
} }
func (fd *netFD) closeRead() error { func (fd *netFD) closeRead() error {
@ -441,72 +150,21 @@ func (fd *netFD) closeWrite() error {
} }
func (fd *netFD) Read(buf []byte) (int, error) { func (fd *netFD) Read(buf []byte) (int, error) {
if err := fd.readLock(); err != nil { n, err := fd.pfd.Read(buf)
return 0, err runtime.KeepAlive(fd)
} return n, wrapSyscallError("wsarecv", 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
} }
func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) { func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
if len(buf) == 0 { n, sa, err := fd.pfd.RecvFrom(buf)
return 0, nil, nil runtime.KeepAlive(fd)
} return n, sa, wrapSyscallError("wsarecvfrom", err)
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
} }
func (fd *netFD) Write(buf []byte) (int, error) { func (fd *netFD) Write(buf []byte) (int, error) {
if err := fd.writeLock(); err != nil { n, err := fd.pfd.Write(buf)
return 0, err runtime.KeepAlive(fd)
} return n, wrapSyscallError("wsasend", 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
} }
func (c *conn) writeBuffers(v *Buffers) (int64, error) { 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) { func (fd *netFD) writeBuffers(buf *Buffers) (int64, error) {
if len(*buf) == 0 { n, err := fd.pfd.Writev((*[][]byte)(buf))
return 0, nil runtime.KeepAlive(fd)
} return n, wrapSyscallError("wsasend", err)
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
} }
func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) { func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
if len(buf) == 0 { n, err := fd.pfd.WriteTo(buf, sa)
return 0, nil runtime.KeepAlive(fd)
} return n, wrapSyscallError("wsasendto", err)
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
} }
func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD, error) { func (fd *netFD) accept() (*netFD, error) {
// Get new socket. s, rawsa, rsan, errcall, err := fd.pfd.Accept(func() (syscall.Handle, error) {
s, err := sysSocket(fd.family, fd.sotype, 0) return sysSocket(fd.family, fd.sotype, 0)
})
if err != nil { if err != nil {
if errcall != "" {
err = wrapSyscallError(errcall, err)
}
return nil, err return nil, err
} }
// Associate our new socket with IOCP. // Associate our new socket with IOCP.
netfd, err := newFD(s, fd.family, fd.sotype, fd.net) netfd, err := newFD(s, fd.family, fd.sotype, fd.net)
if err != nil { if err != nil {
closeFunc(s) poll.CloseFunc(s)
return nil, err return nil, err
} }
if err := netfd.init(); err != nil { if err := netfd.init(); err != nil {
@ -583,71 +213,11 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
return nil, err 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. // Get local and peer addr out of AcceptEx buffer.
var lrsa, rrsa *syscall.RawSockaddrAny var lrsa, rrsa *syscall.RawSockaddrAny
var llen, rlen int32 var llen, rlen int32
syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])), 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() lsa, _ := lrsa.Sockaddr()
rsa, _ := rrsa.Sockaddr() rsa, _ := rrsa.Sockaddr()

View File

@ -7,6 +7,7 @@
package net package net
import ( import (
"internal/poll"
"os" "os"
"syscall" "syscall"
) )
@ -17,7 +18,7 @@ func dupSocket(f *os.File) (int, error) {
return -1, err return -1, err
} }
if err := syscall.SetNonblock(s, true); err != nil { if err := syscall.SetNonblock(s, true); err != nil {
closeFunc(s) poll.CloseFunc(s)
return -1, os.NewSyscallError("setnonblock", err) return -1, os.NewSyscallError("setnonblock", err)
} }
return s, nil return s, nil
@ -31,7 +32,7 @@ func newFileFD(f *os.File) (*netFD, error) {
family := syscall.AF_UNSPEC family := syscall.AF_UNSPEC
sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE) sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE)
if err != nil { if err != nil {
closeFunc(s) poll.CloseFunc(s)
return nil, os.NewSyscallError("getsockopt", err) return nil, os.NewSyscallError("getsockopt", err)
} }
lsa, _ := syscall.Getsockname(s) lsa, _ := syscall.Getsockname(s)
@ -44,12 +45,12 @@ func newFileFD(f *os.File) (*netFD, error) {
case *syscall.SockaddrUnix: case *syscall.SockaddrUnix:
family = syscall.AF_UNIX family = syscall.AF_UNIX
default: default:
closeFunc(s) poll.CloseFunc(s)
return nil, syscall.EPROTONOSUPPORT return nil, syscall.EPROTONOSUPPORT
} }
fd, err := newFD(s, family, sotype, "") fd, err := newFD(s, family, sotype, "")
if err != nil { if err != nil {
closeFunc(s) poll.CloseFunc(s)
return nil, err return nil, err
} }
laddr := fd.addrFunc()(lsa) laddr := fd.addrFunc()(lsa)

View File

@ -13,10 +13,8 @@ var (
testHookCanceledDial = func() {} // for golang.org/issue/16523 testHookCanceledDial = func() {} // for golang.org/issue/16523
// Placeholders for socket system calls. // Placeholders for socket system calls.
socketFunc func(int, int, int) (int, error) = syscall.Socket socketFunc func(int, int, int) (int, error) = syscall.Socket
closeFunc func(int) error = syscall.Close connectFunc func(int, syscall.Sockaddr) error = syscall.Connect
connectFunc func(int, syscall.Sockaddr) error = syscall.Connect listenFunc func(int, int) error = syscall.Listen
listenFunc func(int, int) error = syscall.Listen getsockoptIntFunc func(int, int, int) (int, error) = syscall.GetsockoptInt
acceptFunc func(int) (int, syscall.Sockaddr, error) = syscall.Accept
getsockoptIntFunc func(int, int, int) (int, error) = syscall.GetsockoptInt
) )

View File

@ -13,10 +13,7 @@ var (
testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349 testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349
// Placeholders for socket system calls. // Placeholders for socket system calls.
socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket 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
connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect listenFunc func(syscall.Handle, int) error = syscall.Listen
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
) )

View File

@ -249,10 +249,10 @@ func (fd *netFD) netFD() (*netFD, error) {
func (fd *netFD) acceptPlan9() (nfd *netFD, err error) { func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
defer func() { fixErr(err) }() defer func() { fixErr(err) }()
if err := fd.readLock(); err != nil { if err := fd.pfd.ReadLock(); err != nil {
return nil, err return nil, err
} }
defer fd.readUnlock() defer fd.pfd.ReadUnlock()
listen, err := os.Open(fd.dir + "/listen") listen, err := os.Open(fd.dir + "/listen")
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -8,6 +8,7 @@ package net
import ( import (
"context" "context"
"internal/poll"
"runtime" "runtime"
"syscall" "syscall"
) )
@ -18,7 +19,7 @@ func probeIPv4Stack() bool {
case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT: case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT:
return false return false
case nil: case nil:
closeFunc(s) poll.CloseFunc(s)
} }
return true return true
} }
@ -68,7 +69,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
if err != nil { if err != nil {
continue continue
} }
defer closeFunc(s) defer poll.CloseFunc(s)
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value) syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value)
sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6) sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6)
if err != nil { if err != nil {

View File

@ -6,6 +6,8 @@
package net package net
import "internal/poll"
func init() { func init() {
extraTestHookInstallers = append(extraTestHookInstallers, installAccept4TestHook) extraTestHookInstallers = append(extraTestHookInstallers, installAccept4TestHook)
extraTestHookUninstallers = append(extraTestHookUninstallers, uninstallAccept4TestHook) extraTestHookUninstallers = append(extraTestHookUninstallers, uninstallAccept4TestHook)
@ -13,13 +15,13 @@ func init() {
var ( var (
// Placeholders for saving original socket system calls. // Placeholders for saving original socket system calls.
origAccept4 = accept4Func origAccept4 = poll.Accept4Func
) )
func installAccept4TestHook() { func installAccept4TestHook() {
accept4Func = sw.Accept4 poll.Accept4Func = sw.Accept4
} }
func uninstallAccept4TestHook() { func uninstallAccept4TestHook() {
accept4Func = origAccept4 poll.Accept4Func = origAccept4
} }

View File

@ -6,13 +6,15 @@
package net package net
import "internal/poll"
var ( var (
// Placeholders for saving original socket system calls. // Placeholders for saving original socket system calls.
origSocket = socketFunc origSocket = socketFunc
origClose = closeFunc origClose = poll.CloseFunc
origConnect = connectFunc origConnect = connectFunc
origListen = listenFunc origListen = listenFunc
origAccept = acceptFunc origAccept = poll.AcceptFunc
origGetsockoptInt = getsockoptIntFunc origGetsockoptInt = getsockoptIntFunc
extraTestHookInstallers []func() extraTestHookInstallers []func()
@ -21,10 +23,10 @@ var (
func installTestHooks() { func installTestHooks() {
socketFunc = sw.Socket socketFunc = sw.Socket
closeFunc = sw.Close poll.CloseFunc = sw.Close
connectFunc = sw.Connect connectFunc = sw.Connect
listenFunc = sw.Listen listenFunc = sw.Listen
acceptFunc = sw.Accept poll.AcceptFunc = sw.Accept
getsockoptIntFunc = sw.GetsockoptInt getsockoptIntFunc = sw.GetsockoptInt
for _, fn := range extraTestHookInstallers { for _, fn := range extraTestHookInstallers {
@ -34,10 +36,10 @@ func installTestHooks() {
func uninstallTestHooks() { func uninstallTestHooks() {
socketFunc = origSocket socketFunc = origSocket
closeFunc = origClose poll.CloseFunc = origClose
connectFunc = origConnect connectFunc = origConnect
listenFunc = origListen listenFunc = origListen
acceptFunc = origAccept poll.AcceptFunc = origAccept
getsockoptIntFunc = origGetsockoptInt getsockoptIntFunc = origGetsockoptInt
for _, fn := range extraTestHookUninstallers { for _, fn := range extraTestHookUninstallers {
@ -48,6 +50,6 @@ func uninstallTestHooks() {
// forceCloseSockets must be called only from TestMain. // forceCloseSockets must be called only from TestMain.
func forceCloseSockets() { func forceCloseSockets() {
for s := range sw.Sockets() { for s := range sw.Sockets() {
closeFunc(s) poll.CloseFunc(s)
} }
} }

View File

@ -4,37 +4,39 @@
package net package net
import "internal/poll"
var ( var (
// Placeholders for saving original socket system calls. // Placeholders for saving original socket system calls.
origSocket = socketFunc origSocket = socketFunc
origClosesocket = closeFunc origClosesocket = poll.CloseFunc
origConnect = connectFunc origConnect = connectFunc
origConnectEx = connectExFunc origConnectEx = poll.ConnectExFunc
origListen = listenFunc origListen = listenFunc
origAccept = acceptFunc origAccept = poll.AcceptFunc
) )
func installTestHooks() { func installTestHooks() {
socketFunc = sw.Socket socketFunc = sw.Socket
closeFunc = sw.Closesocket poll.CloseFunc = sw.Closesocket
connectFunc = sw.Connect connectFunc = sw.Connect
connectExFunc = sw.ConnectEx poll.ConnectExFunc = sw.ConnectEx
listenFunc = sw.Listen listenFunc = sw.Listen
acceptFunc = sw.AcceptEx poll.AcceptFunc = sw.AcceptEx
} }
func uninstallTestHooks() { func uninstallTestHooks() {
socketFunc = origSocket socketFunc = origSocket
closeFunc = origClosesocket poll.CloseFunc = origClosesocket
connectFunc = origConnect connectFunc = origConnect
connectExFunc = origConnectEx poll.ConnectExFunc = origConnectEx
listenFunc = origListen listenFunc = origListen
acceptFunc = origAccept poll.AcceptFunc = origAccept
} }
// forceCloseSockets must be called only from TestMain. // forceCloseSockets must be called only from TestMain.
func forceCloseSockets() { func forceCloseSockets() {
for s := range sw.Sockets() { for s := range sw.Sockets() {
closeFunc(s) poll.CloseFunc(s)
} }
} }

View File

@ -81,6 +81,7 @@ package net
import ( import (
"context" "context"
"errors" "errors"
"internal/poll"
"io" "io"
"os" "os"
"syscall" "syscall"
@ -234,7 +235,7 @@ func (c *conn) SetDeadline(t time.Time) error {
if !c.ok() { if !c.ok() {
return syscall.EINVAL 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 &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
} }
return nil return nil
@ -245,7 +246,7 @@ func (c *conn) SetReadDeadline(t time.Time) error {
if !c.ok() { if !c.ok() {
return syscall.EINVAL 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 &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
} }
return nil return nil
@ -256,7 +257,7 @@ func (c *conn) SetWriteDeadline(t time.Time) error {
if !c.ok() { if !c.ok() {
return syscall.EINVAL 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 &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
} }
return nil return nil
@ -391,10 +392,8 @@ var (
errMissingAddress = errors.New("missing address") errMissingAddress = errors.New("missing address")
// For both read and write operations. // For both read and write operations.
errTimeout error = &timeoutError{} errCanceled = errors.New("operation was canceled")
errCanceled = errors.New("operation was canceled") ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
errClosing = errors.New("use of closed network connection")
ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
) )
// mapErr maps from the context errors to the historical internal net // mapErr maps from the context errors to the historical internal net
@ -407,7 +406,7 @@ func mapErr(err error) error {
case context.Canceled: case context.Canceled:
return errCanceled return errCanceled
case context.DeadlineExceeded: case context.DeadlineExceeded:
return errTimeout return poll.ErrTimeout
default: default:
return err return err
} }
@ -502,12 +501,6 @@ func (e *OpError) Temporary() bool {
return ok && t.Temporary() 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. // A ParseError is the error type of literal network address parsers.
type ParseError struct { type ParseError struct {
// Type is the type of string that was expected, such as // Type is the type of string that was expected, such as
@ -632,8 +625,6 @@ type buffersWriter interface {
writeBuffers(*Buffers) (int64, error) writeBuffers(*Buffers) (int64, error)
} }
var testHookDidWritev = func(wrote int) {}
// Buffers contains zero or more runs of bytes to write. // Buffers contains zero or more runs of bytes to write.
// //
// On certain machines, for certain types of connections, this is // On certain machines, for certain types of connections, this is

View File

@ -7,15 +7,11 @@
package net package net
import ( import (
"internal/poll"
"io" "io"
"os" "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 // sendFile copies the contents of r to c using the sendfile
// system call to minimize copies. // 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 return 0, err, false
} }
if err := c.writeLock(); err != nil { written, err = poll.SendFile(&c.pfd, int(f.Fd()), pos, remain)
return 0, err, true
}
defer c.writeUnlock()
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 { if lr != nil {
lr.N = remain lr.N = remain - written
} }
if err != nil { return written, wrapSyscallError("sendfile", err), written > 0
err = os.NewSyscallError("sendfile", err)
}
return written, err, written > 0
} }

View File

@ -5,15 +5,11 @@
package net package net
import ( import (
"internal/poll"
"io" "io"
"os" "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 // sendFile copies the contents of r to c using the sendfile
// system call to minimize copies. // 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 return 0, nil, false
} }
if err := c.writeLock(); err != nil { written, err = poll.SendFile(&c.pfd, int(f.Fd()), remain)
return 0, err, true
}
defer c.writeUnlock()
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 { if lr != nil {
lr.N = remain lr.N = remain - written
} }
if err != nil { return written, wrapSyscallError("sendfile", err), written > 0
err = os.NewSyscallError("sendfile", err)
}
return written, err, written > 0
} }

View File

@ -5,19 +5,11 @@
package net package net
import ( import (
"internal/poll"
"io" "io"
"os" "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 // sendFile copies the contents of r to c using the sendfile
// system call to minimize copies. // 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 return 0, err, false
} }
if err := c.writeLock(); err != nil { written, err = poll.SendFile(&c.pfd, int(f.Fd()), pos, remain)
return 0, err, true
}
defer c.writeUnlock()
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 { if lr != nil {
lr.N = remain lr.N = remain - written
} }
if err != nil { return written, wrapSyscallError("sendfile", err), written > 0
err = os.NewSyscallError("sendfile", err)
}
return written, err, written > 0
} }

View File

@ -5,6 +5,7 @@
package net package net
import ( import (
"internal/poll"
"io" "io"
"os" "os"
"syscall" "syscall"
@ -34,19 +35,10 @@ func sendFile(fd *netFD, r io.Reader) (written int64, err error, handled bool) {
return 0, nil, false return 0, nil, false
} }
if err := fd.writeLock(); err != nil { done, err := poll.SendFile(&fd.pfd, syscall.Handle(f.Fd()), n)
return 0, err, true
}
defer fd.writeUnlock()
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 { if err != nil {
return 0, os.NewSyscallError("transmitfile", err), false return 0, wrapSyscallError("transmitfile", err), false
} }
if lr != nil { if lr != nil {
lr.N -= int64(done) lr.N -= int64(done)

View File

@ -10,6 +10,7 @@
package net package net
import ( import (
"internal/poll"
"os" "os"
"syscall" "syscall"
) )
@ -42,46 +43,8 @@ func sysSocket(family, sotype, proto int) (int, error) {
return -1, os.NewSyscallError("socket", err) return -1, os.NewSyscallError("socket", err)
} }
if err = syscall.SetNonblock(s, true); err != nil { if err = syscall.SetNonblock(s, true); err != nil {
closeFunc(s) poll.CloseFunc(s)
return -1, os.NewSyscallError("setnonblock", err) return -1, os.NewSyscallError("setnonblock", err)
} }
return s, nil 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
}

View File

@ -8,6 +8,7 @@ package net
import ( import (
"context" "context"
"internal/poll"
"os" "os"
"syscall" "syscall"
) )
@ -43,11 +44,11 @@ func socket(ctx context.Context, net string, family, sotype, proto int, ipv6only
return nil, err return nil, err
} }
if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil { if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
closeFunc(s) poll.CloseFunc(s)
return nil, err return nil, err
} }
if fd, err = newFD(s, family, sotype, net); err != nil { if fd, err = newFD(s, family, sotype, net); err != nil {
closeFunc(s) poll.CloseFunc(s)
return nil, err 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 { if lsa, err = laddr.sockaddr(fd.family); err != nil {
return err return err
} else if lsa != nil { } 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) return os.NewSyscallError("bind", err)
} }
} }
@ -146,8 +147,8 @@ func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error {
return err return err
} }
} }
lsa, _ = syscall.Getsockname(fd.sysfd) lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil { if rsa, _ = syscall.Getpeername(fd.pfd.Sysfd); rsa != nil {
fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa)) fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa))
} else { } else {
fd.setAddr(fd.addrFunc()(lsa), raddr) 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 { 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 return err
} }
if lsa, err := laddr.sockaddr(fd.family); err != nil { if lsa, err := laddr.sockaddr(fd.family); err != nil {
return err return err
} else if lsa != nil { } 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) 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) return os.NewSyscallError("listen", err)
} }
if err := fd.init(); err != nil { if err := fd.init(); err != nil {
return err return err
} }
lsa, _ := syscall.Getsockname(fd.sysfd) lsa, _ := syscall.Getsockname(fd.pfd.Sysfd)
fd.setAddr(fd.addrFunc()(lsa), nil) fd.setAddr(fd.addrFunc()(lsa), nil)
return nil return nil
} }
@ -188,7 +189,7 @@ func (fd *netFD) listenDatagram(laddr sockaddr) error {
// multiple UDP listeners that listen on the same UDP // multiple UDP listeners that listen on the same UDP
// port to join the same group address. // port to join the same group address.
if addr.IP != nil && addr.IP.IsMulticast() { if addr.IP != nil && addr.IP.IsMulticast() {
if err := setDefaultMulticastSockopts(fd.sysfd); err != nil { if err := setDefaultMulticastSockopts(fd.pfd.Sysfd); err != nil {
return err return err
} }
addr := *addr addr := *addr
@ -204,14 +205,14 @@ func (fd *netFD) listenDatagram(laddr sockaddr) error {
if lsa, err := laddr.sockaddr(fd.family); err != nil { if lsa, err := laddr.sockaddr(fd.family); err != nil {
return err return err
} else if lsa != nil { } 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) return os.NewSyscallError("bind", err)
} }
} }
if err := fd.init(); err != nil { if err := fd.init(); err != nil {
return err return err
} }
lsa, _ := syscall.Getsockname(fd.sysfd) lsa, _ := syscall.Getsockname(fd.pfd.Sysfd)
fd.setAddr(fd.addrFunc()(lsa), nil) fd.setAddr(fd.addrFunc()(lsa), nil)
return nil return nil
} }

View File

@ -7,7 +7,7 @@
package net package net
import ( import (
"os" "runtime"
"syscall" "syscall"
) )
@ -101,27 +101,21 @@ done:
} }
func setReadBuffer(fd *netFD, bytes int) error { func setReadBuffer(fd *netFD, bytes int) error {
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes))
} }
func setWriteBuffer(fd *netFD, bytes int) error { func setWriteBuffer(fd *netFD, bytes int) error {
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes))
} }
func setKeepAlive(fd *netFD, keepalive bool) error { func setKeepAlive(fd *netFD, keepalive bool) error {
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive)))
} }
func setLinger(fd *netFD, sec int) error { func setLinger(fd *netFD, sec int) error {
@ -133,9 +127,7 @@ func setLinger(fd *netFD, sec int) error {
l.Onoff = 0 l.Onoff = 0
l.Linger = 0 l.Linger = 0
} }
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptLinger(syscall.SOL_SOCKET, syscall.SO_LINGER, &l)
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l))
} }

View File

@ -7,28 +7,24 @@
package net package net
import ( import (
"os" "runtime"
"syscall" "syscall"
) )
func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
ip, err := interfaceToIPv4Addr(ifi) ip, err := interfaceToIPv4Addr(ifi)
if err != nil { if err != nil {
return os.NewSyscallError("setsockopt", err) return wrapSyscallError("setsockopt", err)
} }
var a [4]byte var a [4]byte
copy(a[:], ip.To4()) copy(a[:], ip.To4())
if err := fd.incref(); err != nil { err = fd.pfd.SetsockoptInet4Addr(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, a)
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, a))
} }
func setIPv4MulticastLoopback(fd *netFD, v bool) error { func setIPv4MulticastLoopback(fd *netFD, v bool) error {
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptByte(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v)))
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v))))
} }

View File

@ -5,7 +5,7 @@
package net package net
import ( import (
"os" "runtime"
"syscall" "syscall"
) )
@ -15,17 +15,13 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
v = int32(ifi.Index) v = int32(ifi.Index)
} }
mreq := &syscall.IPMreqn{Ifindex: v} mreq := &syscall.IPMreqn{Ifindex: v}
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptIPMreqn(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq))
} }
func setIPv4MulticastLoopback(fd *netFD, v bool) error { func setIPv4MulticastLoopback(fd *netFD, v bool) error {
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)))
} }

View File

@ -7,7 +7,7 @@
package net package net
import ( import (
"os" "runtime"
"syscall" "syscall"
) )
@ -16,11 +16,9 @@ func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
if err := setIPv4MreqToInterface(mreq, ifi); err != nil { if err := setIPv4MreqToInterface(mreq, ifi); err != nil {
return err return err
} }
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptIPMreq(syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq)
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
} }
func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error { func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
@ -28,19 +26,15 @@ func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
if ifi != nil { if ifi != nil {
v = ifi.Index v = ifi.Index
} }
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v)
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v))
} }
func setIPv6MulticastLoopback(fd *netFD, v bool) error { func setIPv6MulticastLoopback(fd *netFD, v bool) error {
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v))
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v)))
} }
func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error { 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 { if ifi != nil {
mreq.Interface = uint32(ifi.Index) mreq.Interface = uint32(ifi.Index)
} }
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptIPv6Mreq(syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq)
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq))
} }

View File

@ -6,6 +6,7 @@ package net
import ( import (
"os" "os"
"runtime"
"syscall" "syscall"
"unsafe" "unsafe"
) )
@ -17,17 +18,13 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
} }
var a [4]byte var a [4]byte
copy(a[:], ip.To4()) copy(a[:], ip.To4())
if err := fd.incref(); err != nil { err = fd.pfd.Setsockopt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, (*byte)(unsafe.Pointer(&a[0])), 4)
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", 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))
} }
func setIPv4MulticastLoopback(fd *netFD, v bool) error { func setIPv4MulticastLoopback(fd *netFD, v bool) error {
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptInt(syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)))
} }

View File

@ -10,6 +10,7 @@
package net package net
import ( import (
"internal/poll"
"os" "os"
"syscall" "syscall"
) )
@ -28,30 +29,8 @@ func sysSocket(family, sotype, proto int) (int, error) {
return -1, os.NewSyscallError("socket", err) return -1, os.NewSyscallError("socket", err)
} }
if err = syscall.SetNonblock(s, true); err != nil { if err = syscall.SetNonblock(s, true); err != nil {
closeFunc(s) poll.CloseFunc(s)
return -1, os.NewSyscallError("setnonblock", err) return -1, os.NewSyscallError("setnonblock", err)
} }
return s, nil 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
}

View File

@ -255,7 +255,7 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
if !l.ok() { if !l.ok() {
return syscall.EINVAL 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 &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
} }
return nil return nil

View File

@ -5,7 +5,7 @@
package net package net
import ( import (
"os" "runtime"
"syscall" "syscall"
"time" "time"
) )
@ -13,17 +13,15 @@ import (
const sysTCP_KEEPINTVL = 0x101 const sysTCP_KEEPINTVL = 0x101
func setKeepAlivePeriod(fd *netFD, d time.Duration) error { 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. // The kernel expects seconds so round to next highest second.
d += (time.Second - time.Nanosecond) d += (time.Second - time.Nanosecond)
secs := int(d.Seconds()) 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 case nil, syscall.ENOPROTOOPT: // OS X 10.7 and earlier don't support this option
default: 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)
} }

View File

@ -7,14 +7,12 @@
package net package net
import ( import (
"os" "runtime"
"syscall" "syscall"
) )
func setNoDelay(fd *netFD, noDelay bool) error { func setNoDelay(fd *netFD, noDelay bool) error {
if err := fd.incref(); err != nil { err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
return err runtime.KeepAlive(fd)
} return wrapSyscallError("setsockopt", err)
defer fd.decref()
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay)))
} }

View File

@ -5,16 +5,12 @@
package net package net
import ( import (
"os" "runtime"
"syscall" "syscall"
"time" "time"
) )
func setKeepAlivePeriod(fd *netFD, d time.Duration) error { 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 // The kernel expects milliseconds so round to next highest
// millisecond. // millisecond.
d += (time.Millisecond - time.Nanosecond) 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 // allocate a constant with a different meaning for the value of
// TCP_KEEPINTVL on illumos. // 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)
} }

View File

@ -7,21 +7,19 @@
package net package net
import ( import (
"os" "runtime"
"syscall" "syscall"
"time" "time"
) )
func setKeepAlivePeriod(fd *netFD, d time.Duration) error { 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. // The kernel expects seconds so round to next highest second.
d += (time.Second - time.Nanosecond) d += (time.Second - time.Nanosecond)
secs := int(d.Seconds()) secs := int(d.Seconds())
if err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs); err != nil { if err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs); err != nil {
return os.NewSyscallError("setsockopt", err) 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)
} }

View File

@ -6,16 +6,13 @@ package net
import ( import (
"os" "os"
"runtime"
"syscall" "syscall"
"time" "time"
"unsafe" "unsafe"
) )
func setKeepAlivePeriod(fd *netFD, d time.Duration) error { 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 // The kernel expects milliseconds so round to next highest
// millisecond. // millisecond.
d += (time.Millisecond - time.Nanosecond) d += (time.Millisecond - time.Nanosecond)
@ -27,6 +24,7 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
} }
ret := uint32(0) ret := uint32(0)
size := uint32(unsafe.Sizeof(ka)) 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) return os.NewSyscallError("wsaioctl", err)
} }

View File

@ -6,6 +6,7 @@ package net
import ( import (
"fmt" "fmt"
"internal/poll"
"internal/testenv" "internal/testenv"
"io" "io"
"io/ioutil" "io/ioutil"
@ -145,9 +146,9 @@ var acceptTimeoutTests = []struct {
}{ }{
// Tests that accept deadlines in the past work, even if // Tests that accept deadlines in the past work, even if
// there's incoming connections available. // 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) { func TestAcceptTimeout(t *testing.T) {
@ -299,9 +300,9 @@ var readTimeoutTests = []struct {
}{ }{
// Tests that read deadlines work, even if there's data ready // Tests that read deadlines work, even if there's data ready
// to be read. // 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) { func TestReadTimeout(t *testing.T) {
@ -423,9 +424,9 @@ var readFromTimeoutTests = []struct {
}{ }{
// Tests that read deadlines work, even if there's data ready // Tests that read deadlines work, even if there's data ready
// to be read. // 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) { func TestReadFromTimeout(t *testing.T) {
@ -496,9 +497,9 @@ var writeTimeoutTests = []struct {
}{ }{
// Tests that write deadlines work, even if there's buffer // Tests that write deadlines work, even if there's buffer
// space available to write. // 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) { func TestWriteTimeout(t *testing.T) {
@ -610,9 +611,9 @@ var writeToTimeoutTests = []struct {
}{ }{
// Tests that write deadlines work, even if there's buffer // Tests that write deadlines work, even if there's buffer
// space available to write. // 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) { func TestWriteToTimeout(t *testing.T) {

View File

@ -264,7 +264,7 @@ func (l *UnixListener) SetDeadline(t time.Time) error {
if !l.ok() { if !l.ok() {
return syscall.EINVAL 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 &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
} }
return nil return nil

View File

@ -7,6 +7,7 @@ package net
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"internal/poll"
"io" "io"
"io/ioutil" "io/ioutil"
"reflect" "reflect"
@ -99,13 +100,13 @@ func TestBuffers_WriteTo(t *testing.T) {
} }
func testBuffer_writeTo(t *testing.T, chunks int, useCopy bool) { func testBuffer_writeTo(t *testing.T, chunks int, useCopy bool) {
oldHook := testHookDidWritev oldHook := poll.TestHookDidWritev
defer func() { testHookDidWritev = oldHook }() defer func() { poll.TestHookDidWritev = oldHook }()
var writeLog struct { var writeLog struct {
sync.Mutex sync.Mutex
log []int log []int
} }
testHookDidWritev = func(size int) { poll.TestHookDidWritev = func(size int) {
writeLog.Lock() writeLog.Lock()
writeLog.log = append(writeLog.log, size) writeLog.log = append(writeLog.log, size)
writeLog.Unlock() writeLog.Unlock()

View File

@ -7,10 +7,8 @@
package net package net
import ( import (
"io" "runtime"
"os"
"syscall" "syscall"
"unsafe"
) )
func (c *conn) writeBuffers(v *Buffers) (int64, error) { 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) { func (fd *netFD) writeBuffers(v *Buffers) (n int64, err error) {
if err := fd.writeLock(); err != nil { n, err = fd.pfd.Writev((*[][]byte)(v))
return 0, err runtime.KeepAlive(fd)
} return n, wrapSyscallError("writev", 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
} }

View File

@ -8,12 +8,12 @@ import (
_ "unsafe" _ "unsafe"
) )
//go:linkname runtime_ignoreHangup net.runtime_ignoreHangup //go:linkname runtime_ignoreHangup internal/poll.runtime_ignoreHangup
func runtime_ignoreHangup() { func runtime_ignoreHangup() {
getg().m.ignoreHangup = true getg().m.ignoreHangup = true
} }
//go:linkname runtime_unignoreHangup net.runtime_unignoreHangup //go:linkname runtime_unignoreHangup internal/poll.runtime_unignoreHangup
func runtime_unignoreHangup(sig string) { func runtime_unignoreHangup(sig string) {
getg().m.ignoreHangup = false getg().m.ignoreHangup = false
} }

View File

@ -81,8 +81,8 @@ var (
pollcache pollCache pollcache pollCache
) )
//go:linkname net_runtime_pollServerInit net.runtime_pollServerInit //go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit
func net_runtime_pollServerInit() { func poll_runtime_pollServerInit() {
netpollinit() netpollinit()
atomic.Store(&netpollInited, 1) atomic.Store(&netpollInited, 1)
} }
@ -91,8 +91,8 @@ func netpollinited() bool {
return atomic.Load(&netpollInited) != 0 return atomic.Load(&netpollInited) != 0
} }
//go:linkname net_runtime_pollOpen net.runtime_pollOpen //go:linkname poll_runtime_pollOpen internal/poll.runtime_pollOpen
func net_runtime_pollOpen(fd uintptr) (*pollDesc, int) { func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
pd := pollcache.alloc() pd := pollcache.alloc()
lock(&pd.lock) lock(&pd.lock)
if pd.wg != 0 && pd.wg != pdReady { if pd.wg != 0 && pd.wg != pdReady {
@ -115,8 +115,8 @@ func net_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
return pd, int(errno) return pd, int(errno)
} }
//go:linkname net_runtime_pollClose net.runtime_pollClose //go:linkname poll_runtime_pollClose internal/poll.runtime_pollClose
func net_runtime_pollClose(pd *pollDesc) { func poll_runtime_pollClose(pd *pollDesc) {
if !pd.closing { if !pd.closing {
throw("netpollClose: close w/o unblock") throw("netpollClose: close w/o unblock")
} }
@ -137,8 +137,8 @@ func (c *pollCache) free(pd *pollDesc) {
unlock(&c.lock) unlock(&c.lock)
} }
//go:linkname net_runtime_pollReset net.runtime_pollReset //go:linkname poll_runtime_pollReset internal/poll.runtime_pollReset
func net_runtime_pollReset(pd *pollDesc, mode int) int { func poll_runtime_pollReset(pd *pollDesc, mode int) int {
err := netpollcheckerr(pd, int32(mode)) err := netpollcheckerr(pd, int32(mode))
if err != 0 { if err != 0 {
return err return err
@ -151,8 +151,8 @@ func net_runtime_pollReset(pd *pollDesc, mode int) int {
return 0 return 0
} }
//go:linkname net_runtime_pollWait net.runtime_pollWait //go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait
func net_runtime_pollWait(pd *pollDesc, mode int) int { func poll_runtime_pollWait(pd *pollDesc, mode int) int {
err := netpollcheckerr(pd, int32(mode)) err := netpollcheckerr(pd, int32(mode))
if err != 0 { if err != 0 {
return err return err
@ -173,16 +173,16 @@ func net_runtime_pollWait(pd *pollDesc, mode int) int {
return 0 return 0
} }
//go:linkname net_runtime_pollWaitCanceled net.runtime_pollWaitCanceled //go:linkname poll_runtime_pollWaitCanceled internal/poll.runtime_pollWaitCanceled
func net_runtime_pollWaitCanceled(pd *pollDesc, mode int) { func poll_runtime_pollWaitCanceled(pd *pollDesc, mode int) {
// This function is used only on windows after a failed attempt to cancel // 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. // a pending async IO operation. Wait for ioready, ignore closing or timeouts.
for !netpollblock(pd, int32(mode), true) { for !netpollblock(pd, int32(mode), true) {
} }
} }
//go:linkname net_runtime_pollSetDeadline net.runtime_pollSetDeadline //go:linkname poll_runtime_pollSetDeadline internal/poll.runtime_pollSetDeadline
func net_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) { func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
lock(&pd.lock) lock(&pd.lock)
if pd.closing { if pd.closing {
unlock(&pd.lock) 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 //go:linkname poll_runtime_pollUnblock internal/poll.runtime_pollUnblock
func net_runtime_pollUnblock(pd *pollDesc) { func poll_runtime_pollUnblock(pd *pollDesc) {
lock(&pd.lock) lock(&pd.lock)
if pd.closing { if pd.closing {
throw("netpollUnblock: already closing") throw("netpollUnblock: already closing")

View File

@ -12,7 +12,8 @@ const _DWORD_MAX = 0xffffffff
const _INVALID_HANDLE_VALUE = ^uintptr(0) 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 { type net_op struct {
// used by windows // used by windows
o overlapped o overlapped

View File

@ -61,8 +61,8 @@ func sync_runtime_Semacquire(addr *uint32) {
semacquire(addr, semaBlockProfile) semacquire(addr, semaBlockProfile)
} }
//go:linkname net_runtime_Semacquire net.runtime_Semacquire //go:linkname poll_runtime_Semacquire internal/poll.runtime_Semacquire
func net_runtime_Semacquire(addr *uint32) { func poll_runtime_Semacquire(addr *uint32) {
semacquire(addr, semaBlockProfile) semacquire(addr, semaBlockProfile)
} }
@ -76,8 +76,8 @@ func sync_runtime_SemacquireMutex(addr *uint32) {
semacquire(addr, semaBlockProfile|semaMutexProfile) semacquire(addr, semaBlockProfile|semaMutexProfile)
} }
//go:linkname net_runtime_Semrelease net.runtime_Semrelease //go:linkname poll_runtime_Semrelease internal/poll.runtime_Semrelease
func net_runtime_Semrelease(addr *uint32) { func poll_runtime_Semrelease(addr *uint32) {
semrelease(addr) semrelease(addr)
} }

View File

@ -292,8 +292,8 @@ func siftdownTimer(i int) {
// Entry points for net, time to call nanotime. // Entry points for net, time to call nanotime.
//go:linkname net_runtimeNano net.runtimeNano //go:linkname poll_runtimeNano internal/poll.runtimeNano
func net_runtimeNano() int64 { func poll_runtimeNano() int64 {
return nanotime() return nanotime()
} }

View File

@ -231,6 +231,7 @@ func TestTraceSymbolize(t *testing.T) {
if runtime.GOOS != "windows" && runtime.GOOS != "plan9" { if runtime.GOOS != "windows" && runtime.GOOS != "plan9" {
want = append(want, []eventDesc{ want = append(want, []eventDesc{
{trace.EvGoBlockNet, []frame{ {trace.EvGoBlockNet, []frame{
{"internal/poll.(*FD).Accept", 0},
{"net.(*netFD).accept", 0}, {"net.(*netFD).accept", 0},
{"net.(*TCPListener).accept", 0}, {"net.(*TCPListener).accept", 0},
{"net.(*TCPListener).Accept", 0}, {"net.(*TCPListener).Accept", 0},