| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package time | |
| import ( | |
| "container/heap" | |
| "sync" | |
| ) | |
| // The Timer type represents a single event. | |
| // When the Timer expires, the current time will be sent on C | |
| // unless the Timer represents an AfterFunc event. | |
| type Timer struct { | |
| C <-chan int64 | |
| t int64 // The absolute time that the event should fire. | |
| f func(int64) // The function to call when the event fires. | |
| i int // The event's index inside eventHeap. | |
| } | |
| type timerHeap []*Timer | |
| // forever is the absolute time (in ns) of an event that is forever away. | |
| const forever = 1 << 62 | |
| // maxSleepTime is the maximum length of time that a sleeper | |
| // sleeps for before checking if it is defunct. | |
| const maxSleepTime = 1e9 | |
| var ( | |
| // timerMutex guards the variables inside this var group. | |
| timerMutex sync.Mutex | |
| // timers holds a binary heap of pending events, terminated with a sentinel. | |
| timers timerHeap | |
| // currentSleeper is an ever-incrementing counter which represents | |
| // the current sleeper. It allows older sleepers to detect that they are | |
| // defunct and exit. | |
| currentSleeper int64 | |
| ) | |
| func init() { | |
| timers.Push(&Timer{t: forever}) // sentinel | |
| } | |
| // NewTimer creates a new Timer that will send | |
| // the current time on its channel after at least ns nanoseconds. | |
| func NewTimer(ns int64) *Timer { | |
| c := make(chan int64, 1) | |
| e := after(ns, func(t int64) { c <- t }) | |
| e.C = c | |
| return e | |
| } | |
| // After waits at least ns nanoseconds before sending the current time | |
| // on the returned channel. | |
| // It is equivalent to NewTimer(ns).C. | |
| func After(ns int64) <-chan int64 { | |
| return NewTimer(ns).C | |
| } | |
| // AfterFunc waits at least ns nanoseconds before calling f | |
| // in its own goroutine. It returns a Timer that can | |
| // be used to cancel the call using its Stop method. | |
| func AfterFunc(ns int64, f func()) *Timer { | |
| return after(ns, func(_ int64) { | |
| go f() | |
| }) | |
| } | |
| // Stop prevents the Timer from firing. | |
| // It returns true if the call stops the timer, false if the timer has already | |
| // expired or stopped. | |
| func (e *Timer) Stop() (ok bool) { | |
| timerMutex.Lock() | |
| // Avoid removing the first event in the queue so that | |
| // we don't start a new sleeper unnecessarily. | |
| if e.i > 0 { | |
| heap.Remove(timers, e.i) | |
| } | |
| ok = e.f != nil | |
| e.f = nil | |
| timerMutex.Unlock() | |
| return | |
| } | |
| // after is the implementation of After and AfterFunc. | |
| // When the current time is after ns, it calls f with the current time. | |
| // It assumes that f will not block. | |
| func after(ns int64, f func(int64)) (e *Timer) { | |
| now := Nanoseconds() | |
| t := now + ns | |
| if ns > 0 && t < now { | |
| panic("time: time overflow") | |
| } | |
| timerMutex.Lock() | |
| t0 := timers[0].t | |
| e = &Timer{nil, t, f, -1} | |
| heap.Push(timers, e) | |
| // Start a new sleeper if the new event is before | |
| // the first event in the queue. If the length of time | |
| // until the new event is at least maxSleepTime, | |
| // then we're guaranteed that the sleeper will wake up | |
| // in time to service it, so no new sleeper is needed. | |
| if t0 > t && (t0 == forever || ns < maxSleepTime) { | |
| currentSleeper++ | |
| go sleeper(currentSleeper) | |
| } | |
| timerMutex.Unlock() | |
| return | |
| } | |
| // sleeper continually looks at the earliest event in the queue, waits until it happens, | |
| // then removes any events in the queue that are due. It stops when the queue | |
| // is empty or when another sleeper has been started. | |
| func sleeper(sleeperId int64) { | |
| timerMutex.Lock() | |
| e := timers[0] | |
| t := Nanoseconds() | |
| for e.t != forever { | |
| if dt := e.t - t; dt > 0 { | |
| if dt > maxSleepTime { | |
| dt = maxSleepTime | |
| } | |
| timerMutex.Unlock() | |
| sysSleep(dt) | |
| timerMutex.Lock() | |
| if currentSleeper != sleeperId { | |
| // Another sleeper has been started, making this one redundant. | |
| break | |
| } | |
| } | |
| e = timers[0] | |
| t = Nanoseconds() | |
| for t >= e.t { | |
| if e.f != nil { | |
| e.f(t) | |
| e.f = nil | |
| } | |
| heap.Pop(timers) | |
| e = timers[0] | |
| } | |
| } | |
| timerMutex.Unlock() | |
| } | |
| func (timerHeap) Len() int { | |
| return len(timers) | |
| } | |
| func (timerHeap) Less(i, j int) bool { | |
| return timers[i].t < timers[j].t | |
| } | |
| func (timerHeap) Swap(i, j int) { | |
| timers[i], timers[j] = timers[j], timers[i] | |
| timers[i].i = i | |
| timers[j].i = j | |
| } | |
| func (timerHeap) Push(x interface{}) { | |
| e := x.(*Timer) | |
| e.i = len(timers) | |
| timers = append(timers, e) | |
| } | |
| func (timerHeap) Pop() interface{} { | |
| // TODO: possibly shrink array. | |
| n := len(timers) - 1 | |
| e := timers[n] | |
| timers[n] = nil | |
| timers = timers[0:n] | |
| e.i = -1 | |
| return e | |
| } |