From bfa7e3fe75c0e204f982a9a579e3e59faaf41f20 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 11 Oct 2018 00:16:11 +0200 Subject: [PATCH] p2p/simulations: avoid holding Network lock while stopping node This fixes a rare deadlock with the inproc adapter: - A node is stopped, which acquires Network.lock. - The protocol code being simulated (swarm/network in my case) waits for its goroutines to shut down. - One of those goroutines calls into the simulation to add a peer, which waits for Network.lock. --- p2p/simulations/network.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/p2p/simulations/network.go b/p2p/simulations/network.go index 1501a0d2a3..200015ff39 100644 --- a/p2p/simulations/network.go +++ b/p2p/simulations/network.go @@ -250,7 +250,6 @@ func (net *Network) watchPeerEvents(id enode.ID, events chan *p2p.PeerEvent, sub // Stop stops the node with the given ID func (net *Network) Stop(id enode.ID) error { net.lock.Lock() - defer net.lock.Unlock() node := net.getNode(id) if node == nil { return fmt.Errorf("node %v does not exist", id) @@ -258,12 +257,17 @@ func (net *Network) Stop(id enode.ID) error { if !node.Up { return fmt.Errorf("node %v already down", id) } - if err := node.Stop(); err != nil { + node.Up = false + net.lock.Unlock() + + err := node.Stop() + if err != nil { + net.lock.Lock() + node.Up = true + net.lock.Unlock() return err } - node.Up = false - log.Info(fmt.Sprintf("stop node %v: %v", id, node.Up)) - + log.Info("Stopped node", "id", id, "err", err) net.events.Send(ControlEvent(node)) return nil }