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.
This commit is contained in:
Felix Lange 2018-10-11 00:16:11 +02:00
parent dd6751488c
commit bfa7e3fe75

View file

@ -250,7 +250,6 @@ func (net *Network) watchPeerEvents(id enode.ID, events chan *p2p.PeerEvent, sub
// Stop stops the node with the given ID // Stop stops the node with the given ID
func (net *Network) Stop(id enode.ID) error { func (net *Network) Stop(id enode.ID) error {
net.lock.Lock() net.lock.Lock()
defer net.lock.Unlock()
node := net.getNode(id) node := net.getNode(id)
if node == nil { if node == nil {
return fmt.Errorf("node %v does not exist", id) return fmt.Errorf("node %v does not exist", id)
@ -258,12 +257,17 @@ func (net *Network) Stop(id enode.ID) error {
if !node.Up { if !node.Up {
return fmt.Errorf("node %v already down", id) 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 return err
} }
node.Up = false log.Info("Stopped node", "id", id, "err", err)
log.Info(fmt.Sprintf("stop node %v: %v", id, node.Up))
net.events.Send(ControlEvent(node)) net.events.Send(ControlEvent(node))
return nil return nil
} }