1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 package time
6 7 import "unsafe"
8 9 // Note: The runtime knows the layout of struct Ticker, since newTimer allocates it.
10 // Note also that Ticker and Timer have the same layout, so that newTimer can handle both.
11 // The initTimer and initTicker fields are named differently so that
12 // users cannot convert between the two without unsafe.
13 14 // A Ticker holds a channel that delivers “ticks” of a clock
15 // at intervals.
16 type Ticker struct {
17 C <-chan Time // The channel on which the ticks are delivered.
18 initTicker bool
19 }
20 21 // NewTicker returns a new [Ticker] containing a channel that will send
22 // the current time on the channel after each tick. The period of the
23 // ticks is specified by the duration argument. The ticker will adjust
24 // the time interval or drop ticks to make up for slow receivers.
25 // The duration d must be greater than zero; if not, NewTicker will
26 // panic.
27 //
28 // Before Go 1.23, the garbage collector did not recover
29 // tickers that had not yet expired or been stopped, so code often
30 // immediately deferred t.Stop after calling NewTicker, to make
31 // the ticker recoverable when it was no longer needed.
32 // As of Go 1.23, the garbage collector can recover unreferenced
33 // tickers, even if they haven't been stopped.
34 // The Stop method is no longer necessary to help the garbage collector.
35 // (Code may of course still want to call Stop to stop the ticker for other reasons.)
36 func NewTicker(d Duration) *Ticker {
37 if d <= 0 {
38 panic("non-positive interval for NewTicker")
39 }
40 // Give the channel a 1-element time buffer.
41 // If the client falls behind while reading, we drop ticks
42 // on the floor until the client catches up.
43 c := chan Time{1}
44 t := (*Ticker)(unsafe.Pointer(newTimer(when(d), int64(d), sendTime, c, syncTimer(c))))
45 t.C = c
46 return t
47 }
48 49 // Stop turns off a ticker. After Stop, no more ticks will be sent.
50 // Stop does not close the channel, to prevent a concurrent goroutine
51 // reading from the channel from seeing an erroneous "tick".
52 func (t *Ticker) Stop() {
53 if !t.initTicker {
54 // This is misuse, and the same for time.Timer would panic,
55 // but this didn't always panic, and we keep it not panicking
56 // to avoid breaking old programs. See issue 21874.
57 return
58 }
59 stopTimer((*Timer)(unsafe.Pointer(t)))
60 }
61 62 // Reset stops a ticker and resets its period to the specified duration.
63 // The next tick will arrive after the new period elapses. The duration d
64 // must be greater than zero; if not, Reset will panic.
65 func (t *Ticker) Reset(d Duration) {
66 if d <= 0 {
67 panic("non-positive interval for Ticker.Reset")
68 }
69 if !t.initTicker {
70 panic("time: Reset called on uninitialized Ticker")
71 }
72 resetTimer((*Timer)(unsafe.Pointer(t)), when(d), int64(d))
73 }
74 75 // Tick is a convenience wrapper for [NewTicker] providing access to the ticking
76 // channel only. Unlike NewTicker, Tick will return nil if d <= 0.
77 //
78 // Before Go 1.23, this documentation warned that the underlying
79 // [Ticker] would never be recovered by the garbage collector, and that
80 // if efficiency was a concern, code should use NewTicker instead and
81 // call [Ticker.Stop] when the ticker is no longer needed.
82 // As of Go 1.23, the garbage collector can recover unreferenced
83 // tickers, even if they haven't been stopped.
84 // The Stop method is no longer necessary to help the garbage collector.
85 // There is no longer any reason to prefer NewTicker when Tick will do.
86 func Tick(d Duration) <-chan Time {
87 if d <= 0 {
88 return nil
89 }
90 return NewTicker(d).C
91 }
92