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 5package time 6 7import "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. 16type 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.) 36func 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 := make(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". 52func (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. 65func (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. 86func Tick(d Duration) <-chan Time { 87 if d <= 0 { 88 return nil 89 } 90 return NewTicker(d).C 91} 92