mirror of
https://github.com/slackhq/nebula.git
synced 2026-08-15 03:57:03 +02:00
48 lines
1.6 KiB
Go
48 lines
1.6 KiB
Go
package nebula
|
|
|
|
import "time"
|
|
|
|
// wakeDetector notices when the machine has returned from system sleep and measures how long it was suspended.
|
|
//
|
|
// It samples the spread between two kernel clocks: one that pauses across a suspend and one that keeps counting
|
|
// (suspendClockDelta, per platform). While the machine is awake the spread is constant no matter how starved,
|
|
// stopped, or stepped this process is — SIGSTOP, debugger pauses, scheduler starvation, and NTP adjustments move
|
|
// both clocks together or neither, so none of them can fake a wake. A true suspend is the only thing that grows
|
|
// the spread, and it grows by exactly the time spent suspended.
|
|
//
|
|
// Sample is intended to piggyback on a ticker the caller already runs; it costs two clock reads. It is not safe
|
|
// for concurrent use.
|
|
type wakeDetector struct {
|
|
// read returns the current spread between the two clocks, false if this platform can't provide one.
|
|
read func() (time.Duration, bool)
|
|
last time.Duration
|
|
primed bool
|
|
}
|
|
|
|
func newWakeDetector() *wakeDetector {
|
|
return &wakeDetector{read: suspendClockDelta}
|
|
}
|
|
|
|
// Sample returns how long the machine was suspended since the previous call, 0 if it wasn't, and false if the
|
|
// platform has no way to tell. The first call primes the baseline and always reports 0.
|
|
func (w *wakeDetector) Sample() (time.Duration, bool) {
|
|
delta, ok := w.read()
|
|
if !ok {
|
|
return 0, false
|
|
}
|
|
|
|
if !w.primed {
|
|
w.primed = true
|
|
w.last = delta
|
|
return 0, true
|
|
}
|
|
|
|
slept := delta - w.last
|
|
w.last = delta
|
|
if slept < 0 {
|
|
// The clock pair is read non-atomically so tiny negative jitter is possible; it is never a wake.
|
|
slept = 0
|
|
}
|
|
return slept, true
|
|
}
|