| 1234567891011121314151617181920212223242526272829303132333435363738394041 |
- //go:build windows
- package nebula
- import (
- "sync"
- "time"
- "unsafe"
- "golang.org/x/sys/windows"
- )
- var (
- procQueryInterruptTime = windows.NewLazySystemDLL("kernelbase.dll").NewProc("QueryInterruptTime")
- procQueryUnbiasedInterruptTime = windows.NewLazySystemDLL("kernel32.dll").NewProc("QueryUnbiasedInterruptTime")
- // QueryInterruptTime needs Windows 10; probe once and stay dormant on anything older.
- wakeClockAvailable = sync.OnceValue(func() bool {
- return procQueryInterruptTime.Find() == nil && procQueryUnbiasedInterruptTime.Find() == nil
- })
- )
- // suspendClockDelta returns interrupt time minus unbiased interrupt time, both in 100ns units. The unbiased count
- // excludes time the system spends suspended while the biased one includes it, so the difference grows by exactly
- // the time spent asleep.
- //
- // The pausing (unbiased) clock is read first so scheduling jitter between the two reads biases the delta positive;
- // the wakeDetector clamps out the noise.
- func suspendClockDelta() (time.Duration, bool) {
- if !wakeClockAvailable() {
- return 0, false
- }
- var unbiased, biased uint64
- if r1, _, _ := procQueryUnbiasedInterruptTime.Call(uintptr(unsafe.Pointer(&unbiased))); r1 == 0 {
- return 0, false
- }
- // Returns void, cannot fail once resolved.
- _, _, _ = procQueryInterruptTime.Call(uintptr(unsafe.Pointer(&biased)))
- return time.Duration(int64(biased-unbiased)) * 100, true
- }
|