Commit b7498450 authored by Ian Lance Taylor's avatar Ian Lance Taylor

net: limit concurrent threads to limit on file descriptors

At least on Darwin, if getaddrinfo can't open a file descriptor it
returns EAI_NONAME ("no such host") rather than a meaningful error.
Limit the number of concurrent getaddrinfo calls to the number of file
descriptors we can open, to make that meaningless error less likely.

We don't apply the same limit to Go lookups, because for that we will
return a meaningful "too many open files" error.

Fixes #25694

Change-Id: I601857190aeb64f11e22b4a834c1c6a722a0788d
Reviewed-on: https://go-review.googlesource.com/121176Reviewed-by: 's avatarBryan C. Mills <bcmills@google.com>
Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 7c4c87c0
......@@ -50,3 +50,9 @@ func (*Resolver) lookupTXT(ctx context.Context, name string) (txts []string, err
func (*Resolver) lookupAddr(ctx context.Context, addr string) (ptrs []string, err error) {
return nil, syscall.ENOPROTOOPT
}
// concurrentThreadsLimit returns the number of threads we permit to
// run concurrently doing DNS lookups.
func concurrentThreadsLimit() int {
return 500
}
......@@ -329,3 +329,9 @@ func (*Resolver) lookupAddr(ctx context.Context, addr string) (name []string, er
}
return
}
// concurrentThreadsLimit returns the number of threads we permit to
// run concurrently doing DNS lookups.
func concurrentThreadsLimit() int {
return 500
}
......@@ -9,6 +9,7 @@ package net
import (
"context"
"sync"
"syscall"
"golang_org/x/net/dns/dnsmessage"
)
......@@ -315,3 +316,27 @@ func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error
}
return r.goLookupPTR(ctx, addr)
}
// concurrentThreadsLimit returns the number of threads we permit to
// run concurrently doing DNS lookups via cgo. A DNS lookup may use a
// file descriptor so we limit this to less than the number of
// permitted open files. On some systems, notably Darwin, if
// getaddrinfo is unable to open a file descriptor it simply returns
// EAI_NONAME rather than a useful error. Limiting the number of
// concurrent getaddrinfo calls to less than the permitted number of
// file descriptors makes that error less likely. We don't bother to
// apply the same limit to DNS lookups run directly from Go, because
// there we will return a meaningful "too many open files" error.
func concurrentThreadsLimit() int {
var rlim syscall.Rlimit
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil {
return 500
}
r := int(rlim.Cur)
if r > 500 {
r = 500
} else if r > 30 {
r -= 30
}
return r
}
......@@ -364,3 +364,9 @@ Cname:
}
return name
}
// concurrentThreadsLimit returns the number of threads we permit to
// run concurrently doing DNS lookups.
func concurrentThreadsLimit() int {
return 500
}
......@@ -84,6 +84,7 @@ import (
"internal/poll"
"io"
"os"
"sync"
"syscall"
"time"
)
......@@ -610,9 +611,14 @@ func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
// server is not responding. Then the many lookups each use a different
// thread, and the system or the program runs out of threads.
var threadLimit = make(chan struct{}, 500)
var threadLimit chan struct{}
var threadOnce sync.Once
func acquireThread() {
threadOnce.Do(func() {
threadLimit = make(chan struct{}, concurrentThreadsLimit())
})
threadLimit <- struct{}{}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment