Source file src/time/tick.go

     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 := 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".
    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  

View as plain text