diff options
Diffstat (limited to 'vendor/golang.org/x/net/netutil/listen.go')
-rw-r--r-- | vendor/golang.org/x/net/netutil/listen.go | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/vendor/golang.org/x/net/netutil/listen.go b/vendor/golang.org/x/net/netutil/listen.go index 56f43bf..cee46e3 100644 --- a/vendor/golang.org/x/net/netutil/listen.go +++ b/vendor/golang.org/x/net/netutil/listen.go @@ -14,27 +14,53 @@ import ( // LimitListener returns a Listener that accepts at most n simultaneous // connections from the provided Listener. func LimitListener(l net.Listener, n int) net.Listener { - return &limitListener{l, make(chan struct{}, n)} + return &limitListener{ + Listener: l, + sem: make(chan struct{}, n), + done: make(chan struct{}), + } } type limitListener struct { net.Listener - sem chan struct{} + sem chan struct{} + closeOnce sync.Once // ensures the done chan is only closed once + done chan struct{} // no values sent; closed when Close is called } -func (l *limitListener) acquire() { l.sem <- struct{}{} } +// acquire acquires the limiting semaphore. Returns true if successfully +// accquired, false if the listener is closed and the semaphore is not +// acquired. +func (l *limitListener) acquire() bool { + select { + case <-l.done: + return false + case l.sem <- struct{}{}: + return true + } +} func (l *limitListener) release() { <-l.sem } func (l *limitListener) Accept() (net.Conn, error) { - l.acquire() + acquired := l.acquire() + // If the semaphore isn't acquired because the listener was closed, expect + // that this call to accept won't block, but immediately return an error. c, err := l.Listener.Accept() if err != nil { - l.release() + if acquired { + l.release() + } return nil, err } return &limitListenerConn{Conn: c, release: l.release}, nil } +func (l *limitListener) Close() error { + err := l.Listener.Close() + l.closeOnce.Do(func() { close(l.done) }) + return err +} + type limitListenerConn struct { net.Conn releaseOnce sync.Once |