From 34d026862df50e36bdb74f010f746f91b7d6a052 Mon Sep 17 00:00:00 2001 From: Bryan Mills Date: Tue, 31 Jan 2023 20:55:23 +0000 Subject: [PATCH] Revert "net: move context cancellation logic of blocking calls to a common function." This reverts CL 463231. Reason for revert: introduced a data race on darwin. Fixes #58169. Change-Id: I35f02273db38c257369c166547bb4945f92fdc3a Reviewed-on: https://go-review.googlesource.com/c/go/+/464375 Auto-Submit: Bryan Mills Reviewed-by: Damien Neil TryBot-Result: Gopher Robot Run-TryBot: Bryan Mills Reviewed-by: Ian Lance Taylor --- src/net/cgo_unix.go | 128 ++++++++++++++++++++++++++++++-------------- 1 file changed, 87 insertions(+), 41 deletions(-) diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go index d76652f054..8e43bad8b6 100644 --- a/src/net/cgo_unix.go +++ b/src/net/cgo_unix.go @@ -29,33 +29,20 @@ func (eai addrinfoErrno) Error() string { return _C_gai_strerror(_C_int(eai)) func (eai addrinfoErrno) Temporary() bool { return eai == _C_EAI_AGAIN } func (eai addrinfoErrno) Timeout() bool { return false } -// doBlockingWithCtx executes a blocking function in a separate goroutine when the provided -// context is cancellable. It is intended for use with calls that don't support context -// cancellation (cgo, syscalls). blocking func may still be running after this function finishes. -func doBlockingWithCtx[T any](ctx context.Context, blocking func() (T, error)) (T, error) { - if ctx.Done() == nil { - return blocking() - } - - type result struct { - res T - err error - } +type portLookupResult struct { + port int + err error +} - res := make(chan result, 1) - go func() { - var r result - r.res, r.err = blocking() - res <- r - }() +type ipLookupResult struct { + addrs []IPAddr + cname string + err error +} - select { - case r := <-res: - return r.res, r.err - case <-ctx.Done(): - var zero T - return zero, mapErr(ctx.Err()) - } +type reverseLookupResult struct { + names []string + err error } func cgoLookupHost(ctx context.Context, name string) (hosts []string, err error, completed bool) { @@ -85,11 +72,20 @@ func cgoLookupPort(ctx context.Context, network, service string) (port int, err case '6': *_C_ai_family(&hints) = _C_AF_INET6 } - - port, err = doBlockingWithCtx(ctx, func() (int, error) { - return cgoLookupServicePort(&hints, network, service) - }) - return port, err, true + if ctx.Done() == nil { + port, err := cgoLookupServicePort(&hints, network, service) + return port, err, true + } + result := make(chan portLookupResult, 1) + go cgoPortLookup(result, &hints, network, service) + select { + case r := <-result: + return r.port, r.err, true + case <-ctx.Done(): + // Since there isn't a portable way to cancel the lookup, + // we just let it finish and write to the buffered channel. + return 0, mapErr(ctx.Err()), false + } } func cgoLookupServicePort(hints *_C_struct_addrinfo, network, service string) (port int, err error) { @@ -131,6 +127,11 @@ func cgoLookupServicePort(hints *_C_struct_addrinfo, network, service string) (p return 0, &DNSError{Err: "unknown port", Name: network + "/" + service} } +func cgoPortLookup(result chan<- portLookupResult, hints *_C_struct_addrinfo, network, service string) { + port, err := cgoLookupServicePort(hints, network, service) + result <- portLookupResult{port, err} +} + func cgoLookupIPCNAME(network, name string) (addrs []IPAddr, cname string, err error) { acquireThread() defer releaseThread() @@ -205,12 +206,24 @@ func cgoLookupIPCNAME(network, name string) (addrs []IPAddr, cname string, err e return addrs, cname, nil } +func cgoIPLookup(result chan<- ipLookupResult, network, name string) { + addrs, cname, err := cgoLookupIPCNAME(network, name) + result <- ipLookupResult{addrs, cname, err} +} + func cgoLookupIP(ctx context.Context, network, name string) (addrs []IPAddr, err error, completed bool) { - addrs, err = doBlockingWithCtx(ctx, func() ([]IPAddr, error) { + if ctx.Done() == nil { addrs, _, err = cgoLookupIPCNAME(network, name) - return addrs, err - }) - return addrs, err, true + return addrs, err, true + } + result := make(chan ipLookupResult, 1) + go cgoIPLookup(result, network, name) + select { + case r := <-result: + return r.addrs, r.err, true + case <-ctx.Done(): + return nil, mapErr(ctx.Err()), true + } } // These are roughly enough for the following: @@ -239,11 +252,18 @@ func cgoLookupPTR(ctx context.Context, addr string) (names []string, err error, if sa == nil { return nil, &DNSError{Err: "invalid address " + ip.String(), Name: addr}, true } - - names, err = doBlockingWithCtx(ctx, func() ([]string, error) { - return cgoLookupAddrPTR(addr, sa, salen) - }) - return names, err, true + if ctx.Done() == nil { + names, err := cgoLookupAddrPTR(addr, sa, salen) + return names, err, true + } + result := make(chan reverseLookupResult, 1) + go cgoReverseLookup(result, addr, sa, salen) + select { + case r := <-result: + return r.names, r.err, true + case <-ctx.Done(): + return nil, mapErr(ctx.Err()), true + } } func cgoLookupAddrPTR(addr string, sa *_C_struct_sockaddr, salen _C_socklen_t) (names []string, err error) { @@ -285,6 +305,11 @@ func cgoLookupAddrPTR(addr string, sa *_C_struct_sockaddr, salen _C_socklen_t) ( return []string{absDomainName(string(b))}, nil } +func cgoReverseLookup(result chan<- reverseLookupResult, addr string, sa *_C_struct_sockaddr, salen _C_socklen_t) { + names, err := cgoLookupAddrPTR(addr, sa, salen) + result <- reverseLookupResult{names, err} +} + func cgoSockaddr(ip IP, zone string) (*_C_struct_sockaddr, _C_socklen_t) { if ip4 := ip.To4(); ip4 != nil { return cgoSockaddrInet4(ip4), _C_socklen_t(syscall.SizeofSockaddrInet4) @@ -310,9 +335,30 @@ func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, // resSearch will make a call to the 'res_nsearch' routine in the C library // and parse the output as a slice of DNS resources. func resSearch(ctx context.Context, hostname string, rtype, class int) ([]dnsmessage.Resource, error) { - return doBlockingWithCtx(ctx, func() ([]dnsmessage.Resource, error) { + if ctx.Done() == nil { return cgoResSearch(hostname, rtype, class) - }) + } + + type result struct { + res []dnsmessage.Resource + err error + } + + res := make(chan result, 1) + go func() { + r, err := cgoResSearch(hostname, rtype, class) + res <- result{ + res: r, + err: err, + } + }() + + select { + case res := <-res: + return res.res, res.err + case <-ctx.Done(): + return nil, mapErr(ctx.Err()) + } } func cgoResSearch(hostname string, rtype, class int) ([]dnsmessage.Resource, error) { -- 2.50.0