mirror of
https://github.com/golang/go.git
synced 2025-05-19 14:24:46 +00:00
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:
parent
b548eee3d9
commit
3792db5183
95
src/cmd/dist/deps.go
vendored
95
src/cmd/dist/deps.go
vendored
@ -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"},
|
||||||
}
|
}
|
||||||
|
@ -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++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
},
|
},
|
||||||
|
39
src/internal/poll/export_test.go
Normal file
39
src/internal/poll/export_test.go
Normal 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
44
src/internal/poll/fd.go
Normal 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) {}
|
@ -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.
|
@ -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()
|
||||||
}
|
}
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
180
src/internal/poll/fd_plan9.go
Normal file
180
src/internal/poll/fd_plan9.go
Normal 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")
|
||||||
|
}
|
@ -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
|
@ -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
|
57
src/internal/poll/fd_posix.go
Normal file
57
src/internal/poll/fd_posix.go
Normal 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)
|
||||||
|
}
|
43
src/internal/poll/fd_posix_test.go
Normal file
43
src/internal/poll/fd_posix_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
398
src/internal/poll/fd_unix.go
Normal file
398
src/internal/poll/fd_unix.go
Normal 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)
|
||||||
|
}
|
816
src/internal/poll/fd_windows.go
Normal file
816
src/internal/poll/fd_windows.go
Normal 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)
|
||||||
|
}
|
@ -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
|
|
||||||
)
|
|
17
src/internal/poll/hook_unix.go
Normal file
17
src/internal/poll/hook_unix.go
Normal 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
|
18
src/internal/poll/hook_windows.go
Normal file
18
src/internal/poll/hook_windows.go
Normal 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
|
51
src/internal/poll/sendfile_bsd.go
Normal file
51
src/internal/poll/sendfile_bsd.go
Normal 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
|
||||||
|
}
|
48
src/internal/poll/sendfile_linux.go
Normal file
48
src/internal/poll/sendfile_linux.go
Normal 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
|
||||||
|
}
|
64
src/internal/poll/sendfile_solaris.go
Normal file
64
src/internal/poll/sendfile_solaris.go
Normal 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
|
||||||
|
}
|
23
src/internal/poll/sendfile_windows.go
Normal file
23
src/internal/poll/sendfile_windows.go
Normal 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
|
||||||
|
}
|
52
src/internal/poll/sock_cloexec.go
Normal file
52
src/internal/poll/sock_cloexec.go
Normal 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
|
||||||
|
}
|
38
src/internal/poll/sockopt.go
Normal file
38
src/internal/poll/sockopt.go
Normal 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)
|
||||||
|
}
|
18
src/internal/poll/sockopt_linux.go
Normal file
18
src/internal/poll/sockopt_linux.go
Normal 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)
|
||||||
|
}
|
18
src/internal/poll/sockopt_unix.go
Normal file
18
src/internal/poll/sockopt_unix.go
Normal 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)
|
||||||
|
}
|
27
src/internal/poll/sockopt_windows.go
Normal file
27
src/internal/poll/sockopt_windows.go
Normal 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)
|
||||||
|
}
|
27
src/internal/poll/sockoptip.go
Normal file
27
src/internal/poll/sockoptip.go
Normal 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
39
src/internal/poll/str.go
Normal 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
|
||||||
|
}
|
36
src/internal/poll/sys_cloexec.go
Normal file
36
src/internal/poll/sys_cloexec.go
Normal 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
|
||||||
|
}
|
81
src/internal/poll/writev.go
Normal file
81
src/internal/poll/writev.go
Normal 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
|
||||||
|
}
|
62
src/internal/poll/writev_test.go
Normal file
62
src/internal/poll/writev_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
21
src/net/error_posix.go
Normal 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
|
||||||
|
}
|
@ -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)
|
||||||
|
@ -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")
|
|
||||||
}
|
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
|
||||||
)
|
)
|
||||||
|
@ -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
|
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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))
|
|
||||||
}
|
}
|
||||||
|
@ -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))))
|
|
||||||
}
|
}
|
||||||
|
@ -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)))
|
|
||||||
}
|
}
|
||||||
|
@ -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))
|
|
||||||
}
|
}
|
||||||
|
@ -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)))
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)))
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user