device: fix data race in peer.timersActive
Found by the race detector and existing tests. To avoid introducing a lock into this hot path, calculate and cache whether any peers exist. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This commit is contained in:
parent
70861686d3
commit
f7bbdc31a0
|
@ -49,8 +49,9 @@ type Device struct {
|
|||
}
|
||||
|
||||
peers struct {
|
||||
sync.RWMutex
|
||||
keyMap map[NoisePublicKey]*Peer
|
||||
empty AtomicBool // empty reports whether len(keyMap) == 0
|
||||
sync.RWMutex // protects keyMap
|
||||
keyMap map[NoisePublicKey]*Peer
|
||||
}
|
||||
|
||||
// unprotected / "self-synchronising resources"
|
||||
|
@ -129,6 +130,7 @@ func unsafeRemovePeer(device *Device, peer *Peer, key NoisePublicKey) {
|
|||
// remove from peer map
|
||||
|
||||
delete(device.peers.keyMap, key)
|
||||
device.peers.empty.Set(len(device.peers.keyMap) == 0)
|
||||
}
|
||||
|
||||
func deviceUpdateState(device *Device) {
|
||||
|
|
|
@ -125,6 +125,7 @@ func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) {
|
|||
// add
|
||||
|
||||
device.peers.keyMap[pk] = peer
|
||||
device.peers.empty.Set(false)
|
||||
|
||||
// start peer
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ func (timer *Timer) IsPending() bool {
|
|||
}
|
||||
|
||||
func (peer *Peer) timersActive() bool {
|
||||
return peer.isRunning.Get() && peer.device != nil && peer.device.isUp.Get() && len(peer.device.peers.keyMap) > 0
|
||||
return peer.isRunning.Get() && peer.device != nil && peer.device.isUp.Get() && !peer.device.peers.empty.Get()
|
||||
}
|
||||
|
||||
func expiredRetransmitHandshake(peer *Peer) {
|
||||
|
|
Loading…
Reference in a new issue