| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647 |
- 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
- }
|