diff --git a/wgengine/monitor/monitor.go b/wgengine/monitor/monitor.go index f5e3f64d6..d2ddfb8c3 100644 --- a/wgengine/monitor/monitor.go +++ b/wgengine/monitor/monitor.go @@ -185,13 +185,7 @@ func (m *Mon) Start() { } m.started = true - switch runtime.GOOS { - case "ios", "android": - // For battery reasons, and because these platforms - // don't really sleep in the same way, don't poll - // for the wall time to detect for wake-for-sleep - // walltime jumps. - default: + if shouldMonitorTimeJump { m.wallTimer = time.AfterFunc(pollWallTimeInterval, m.pollWallTime) } @@ -304,16 +298,9 @@ func (m *Mon) debounce() { } else { m.mu.Lock() - // See if we have a queued or new time jump signal. - m.checkWallTimeAdvanceLocked() - timeJumped := m.timeJumped - if timeJumped { - m.logf("time jumped (probably wake from sleep); synthesizing major change event") - } - oldState := m.ifState - ifChanged := !curState.EqualFiltered(oldState, interfaces.UseInterestingInterfaces, interfaces.UseInterestingIPs) - if ifChanged { + changed := !curState.EqualFiltered(oldState, interfaces.UseInterestingInterfaces, interfaces.UseInterestingIPs) + if changed { m.gwValid = false m.ifState = curState @@ -322,9 +309,14 @@ func (m *Mon) debounce() { jsonSummary(oldState), jsonSummary(curState)) } } - changed := ifChanged || timeJumped - if changed { - m.timeJumped = false + // See if we have a queued or new time jump signal. + if shouldMonitorTimeJump && m.checkWallTimeAdvanceLocked() { + m.resetTimeJumpedLocked() + if !changed { + // Only log if it wasn't an interesting change. + m.logf("time jumped (probably wake from sleep); synthesizing major change event") + changed = true + } } for _, cb := range m.cbs { go cb(changed, m.ifState) @@ -360,22 +352,37 @@ func (m *Mon) pollWallTime() { if m.closed { return } - m.checkWallTimeAdvanceLocked() - if m.timeJumped { + if m.checkWallTimeAdvanceLocked() { m.InjectEvent() } m.wallTimer.Reset(pollWallTimeInterval) } -// checkWallTimeAdvanceLocked updates m.timeJumped, if wall time jumped -// more than 150% of pollWallTimeInterval, indicating we probably just -// came out of sleep. -func (m *Mon) checkWallTimeAdvanceLocked() { +// shouldMonitorTimeJump is whether we keep a regular periodic timer running in +// the background watching for jumps in wall time. +// +// We don't do this on mobile platforms for battery reasons, and because these +// platforms don't really sleep in the same way. +const shouldMonitorTimeJump = runtime.GOOS != "android" && runtime.GOOS != "ios" + +// checkWallTimeAdvanceLocked reports whether wall time jumped more than 150% of +// pollWallTimeInterval, indicating we probably just came out of sleep. Once a +// time jump is detected it must be reset by calling resetTimeJumpedLocked. +func (m *Mon) checkWallTimeAdvanceLocked() bool { + if !shouldMonitorTimeJump { + panic("unreachable") // if callers are correct + } now := wallTime() if now.Sub(m.lastWall) > pollWallTimeInterval*3/2 { - m.timeJumped = true + m.timeJumped = true // it is reset by debounce. } m.lastWall = now + return m.timeJumped +} + +// resetTimeJumpedLocked consumes the signal set by checkWallTimeAdvanceLocked. +func (m *Mon) resetTimeJumpedLocked() { + m.timeJumped = false } type ipRuleDeletedMessage struct {