p2p: wait for listener goroutines on shutdown (#20569)

* p2p: wait for goroutine exit, fixes #20558

* p2p: wait for all slots on exit

Co-authored-by: Martin Holst Swende <martin@swende.se>
This commit is contained in:
Felix Lange 2020-01-16 13:10:15 +01:00 committed by Péter Szilágyi
parent 1ee754b056
commit fcafa0baa5

@ -864,9 +864,9 @@ func (srv *Server) maxDialedConns() int {
// listenLoop runs in its own goroutine and accepts // listenLoop runs in its own goroutine and accepts
// inbound connections. // inbound connections.
func (srv *Server) listenLoop() { func (srv *Server) listenLoop() {
defer srv.loopWG.Done()
srv.log.Debug("TCP listener up", "addr", srv.listener.Addr()) srv.log.Debug("TCP listener up", "addr", srv.listener.Addr())
// The slots channel limits accepts of new connections.
tokens := defaultMaxPendingPeers tokens := defaultMaxPendingPeers
if srv.MaxPendingPeers > 0 { if srv.MaxPendingPeers > 0 {
tokens = srv.MaxPendingPeers tokens = srv.MaxPendingPeers
@ -876,6 +876,15 @@ func (srv *Server) listenLoop() {
slots <- struct{}{} slots <- struct{}{}
} }
// Wait for slots to be returned on exit. This ensures all connection goroutines
// are down before listenLoop returns.
defer srv.loopWG.Done()
defer func() {
for i := 0; i < cap(slots); i++ {
<-slots
}
}()
for { for {
// Wait for a free slot before accepting. // Wait for a free slot before accepting.
<-slots <-slots
@ -891,6 +900,7 @@ func (srv *Server) listenLoop() {
continue continue
} else if err != nil { } else if err != nil {
srv.log.Debug("Read error", "err", err) srv.log.Debug("Read error", "err", err)
slots <- struct{}{}
return return
} }
break break