diff options
Diffstat (limited to 'src/time/sleep.go')
-rw-r--r-- | src/time/sleep.go | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/src/time/sleep.go b/src/time/sleep.go new file mode 100644 index 0000000..cdab478 --- /dev/null +++ b/src/time/sleep.go @@ -0,0 +1,177 @@ +// 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 + +// Sleep pauses the current goroutine for at least the duration d. +// A negative or zero duration causes Sleep to return immediately. +func Sleep(d Duration) + +// Interface to timers implemented in package runtime. +// Must be in sync with ../runtime/time.go:/^type timer +type runtimeTimer struct { + pp uintptr + when int64 + period int64 + f func(any, uintptr) // NOTE: must not be closure + arg any + seq uintptr + nextwhen int64 + status uint32 +} + +// when is a helper function for setting the 'when' field of a runtimeTimer. +// It returns what the time will be, in nanoseconds, Duration d in the future. +// If d is negative, it is ignored. If the returned value would be less than +// zero because of an overflow, MaxInt64 is returned. +func when(d Duration) int64 { + if d <= 0 { + return runtimeNano() + } + t := runtimeNano() + int64(d) + if t < 0 { + // N.B. runtimeNano() and d are always positive, so addition + // (including overflow) will never result in t == 0. + t = 1<<63 - 1 // math.MaxInt64 + } + return t +} + +func startTimer(*runtimeTimer) +func stopTimer(*runtimeTimer) bool +func resetTimer(*runtimeTimer, int64) bool +func modTimer(t *runtimeTimer, when, period int64, f func(any, uintptr), arg any, seq uintptr) + +// The Timer type represents a single event. +// When the Timer expires, the current time will be sent on C, +// unless the Timer was created by AfterFunc. +// A Timer must be created with NewTimer or AfterFunc. +type Timer struct { + C <-chan Time + r runtimeTimer +} + +// Stop prevents the Timer from firing. +// It returns true if the call stops the timer, false if the timer has already +// expired or been stopped. +// Stop does not close the channel, to prevent a read from the channel succeeding +// incorrectly. +// +// To ensure the channel is empty after a call to Stop, check the +// return value and drain the channel. +// For example, assuming the program has not received from t.C already: +// +// if !t.Stop() { +// <-t.C +// } +// +// This cannot be done concurrent to other receives from the Timer's +// channel or other calls to the Timer's Stop method. +// +// For a timer created with AfterFunc(d, f), if t.Stop returns false, then the timer +// has already expired and the function f has been started in its own goroutine; +// Stop does not wait for f to complete before returning. +// If the caller needs to know whether f is completed, it must coordinate +// with f explicitly. +func (t *Timer) Stop() bool { + if t.r.f == nil { + panic("time: Stop called on uninitialized Timer") + } + return stopTimer(&t.r) +} + +// NewTimer creates a new Timer that will send +// the current time on its channel after at least duration d. +func NewTimer(d Duration) *Timer { + c := make(chan Time, 1) + t := &Timer{ + C: c, + r: runtimeTimer{ + when: when(d), + f: sendTime, + arg: c, + }, + } + startTimer(&t.r) + return t +} + +// Reset changes the timer to expire after duration d. +// It returns true if the timer had been active, false if the timer had +// expired or been stopped. +// +// For a Timer created with NewTimer, Reset should be invoked only on +// stopped or expired timers with drained channels. +// +// If a program has already received a value from t.C, the timer is known +// to have expired and the channel drained, so t.Reset can be used directly. +// If a program has not yet received a value from t.C, however, +// the timer must be stopped and—if Stop reports that the timer expired +// before being stopped—the channel explicitly drained: +// +// if !t.Stop() { +// <-t.C +// } +// t.Reset(d) +// +// This should not be done concurrent to other receives from the Timer's +// channel. +// +// Note that it is not possible to use Reset's return value correctly, as there +// is a race condition between draining the channel and the new timer expiring. +// Reset should always be invoked on stopped or expired channels, as described above. +// The return value exists to preserve compatibility with existing programs. +// +// For a Timer created with AfterFunc(d, f), Reset either reschedules +// when f will run, in which case Reset returns true, or schedules f +// to run again, in which case it returns false. +// When Reset returns false, Reset neither waits for the prior f to +// complete before returning nor does it guarantee that the subsequent +// goroutine running f does not run concurrently with the prior +// one. If the caller needs to know whether the prior execution of +// f is completed, it must coordinate with f explicitly. +func (t *Timer) Reset(d Duration) bool { + if t.r.f == nil { + panic("time: Reset called on uninitialized Timer") + } + w := when(d) + return resetTimer(&t.r, w) +} + +// sendTime does a non-blocking send of the current time on c. +func sendTime(c any, seq uintptr) { + select { + case c.(chan Time) <- Now(): + default: + } +} + +// After waits for the duration to elapse and then sends the current time +// on the returned channel. +// It is equivalent to NewTimer(d).C. +// The underlying Timer is not recovered by the garbage collector +// until the timer fires. If efficiency is a concern, use NewTimer +// instead and call Timer.Stop if the timer is no longer needed. +func After(d Duration) <-chan Time { + return NewTimer(d).C +} + +// AfterFunc waits for the duration to elapse and then calls f +// in its own goroutine. It returns a Timer that can +// be used to cancel the call using its Stop method. +func AfterFunc(d Duration, f func()) *Timer { + t := &Timer{ + r: runtimeTimer{ + when: when(d), + f: goFunc, + arg: f, + }, + } + startTimer(&t.r) + return t +} + +func goFunc(arg any, seq uintptr) { + go arg.(func())() +} |