| // 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 "unsafe" |
| |
| // Note: The runtime knows the layout of struct Ticker, since newTimer allocates it. |
| // Note also that Ticker and Timer have the same layout, so that newTimer can handle both. |
| // The initTimer and initTicker fields are named differently so that |
| // users cannot convert between the two without unsafe. |
| |
| // A Ticker holds a channel that delivers “ticks” of a clock |
| // at intervals. |
| type Ticker struct { |
| C <-chan Time // The channel on which the ticks are delivered. |
| initTicker bool |
| } |
| |
| // NewTicker returns a new [Ticker] containing a channel that will send |
| // the current time on the channel after each tick. The period of the |
| // ticks is specified by the duration argument. The ticker will adjust |
| // the time interval or drop ticks to make up for slow receivers. |
| // The duration d must be greater than zero; if not, NewTicker will |
| // panic. |
| // |
| // Before Go 1.23, the garbage collector did not recover |
| // tickers that had not yet expired or been stopped, so code often |
| // immediately deferred t.Stop after calling NewTicker, to make |
| // the ticker recoverable when it was no longer needed. |
| // As of Go 1.23, the garbage collector can recover unreferenced |
| // tickers, even if they haven't been stopped. |
| // The Stop method is no longer necessary to help the garbage collector. |
| // (Code may of course still want to call Stop to stop the ticker for other reasons.) |
| func NewTicker(d Duration) *Ticker { |
| if d <= 0 { |
| panic("non-positive interval for NewTicker") |
| } |
| // Give the channel a 1-element time buffer. |
| // If the client falls behind while reading, we drop ticks |
| // on the floor until the client catches up. |
| c := make(chan Time, 1) |
| t := (*Ticker)(unsafe.Pointer(newTimer(when(d), int64(d), sendTime, c, syncTimer(c)))) |
| t.C = c |
| return t |
| } |
| |
| // Stop turns off a ticker. After Stop, no more ticks will be sent. |
| // Stop does not close the channel, to prevent a concurrent goroutine |
| // reading from the channel from seeing an erroneous "tick". |
| func (t *Ticker) Stop() { |
| if !t.initTicker { |
| // This is misuse, and the same for time.Timer would panic, |
| // but this didn't always panic, and we keep it not panicking |
| // to avoid breaking old programs. See issue 21874. |
| return |
| } |
| stopTimer((*Timer)(unsafe.Pointer(t))) |
| } |
| |
| // Reset stops a ticker and resets its period to the specified duration. |
| // The next tick will arrive after the new period elapses. The duration d |
| // must be greater than zero; if not, Reset will panic. |
| func (t *Ticker) Reset(d Duration) { |
| if d <= 0 { |
| panic("non-positive interval for Ticker.Reset") |
| } |
| if !t.initTicker { |
| panic("time: Reset called on uninitialized Ticker") |
| } |
| resetTimer((*Timer)(unsafe.Pointer(t)), when(d), int64(d)) |
| } |
| |
| // Tick is a convenience wrapper for [NewTicker] providing access to the ticking |
| // channel only. Unlike NewTicker, Tick will return nil if d <= 0. |
| // |
| // Before Go 1.23, this documentation warned that the underlying |
| // [Ticker] would never be recovered by the garbage collector, and that |
| // if efficiency was a concern, code should use NewTicker instead and |
| // call [Ticker.Stop] when the ticker is no longer needed. |
| // As of Go 1.23, the garbage collector can recover unreferenced |
| // tickers, even if they haven't been stopped. |
| // The Stop method is no longer necessary to help the garbage collector. |
| // There is no longer any reason to prefer NewTicker when Tick will do. |
| func Tick(d Duration) <-chan Time { |
| if d <= 0 { |
| return nil |
| } |
| return NewTicker(d).C |
| } |