package scheduling import ( "sync" "time" ) type clock interface { now() float64 runAt(ts float64, f func()) close() } type scheduleInfo struct { ts float64 f func() } type systemClock struct { since time.Time schedule chan scheduleInfo wg sync.WaitGroup } func newSystemClock() *systemClock { c := &systemClock{ since: time.Now(), schedule: make(chan scheduleInfo), } c.start() return c } func (c *systemClock) now() float64 { return time.Since(c.since).Seconds() } func (c *systemClock) runAt(ts float64, f func()) { select { case c.schedule <- scheduleInfo{ts: ts, f: f}: default: // timer fired, scheduleRequest will call runAt again } } func (c *systemClock) close() { close(c.schedule) c.wg.Wait() } func (c *systemClock) start() { c.wg.Add(1) go func() { defer c.wg.Done() t := time.NewTimer(0) <-t.C var f func() for { select { case <-t.C: if f != nil { f() f = nil } case s, ok := <-c.schedule: if !ok { return } var d time.Duration now := c.now() if now < s.ts { d = time.Duration((s.ts - now) * 1e9) } if !t.Stop() { select { case <-t.C: default: } } t.Reset(d) f = s.f } } }() }