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 self fields have different types so that users cannot convert between
    12  // 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  	self *Ticker
    19  }
    20  
    21  // Ticker must be allocated from the runtime and not copied.
    22  func (t *Ticker) checkValid(meth string) {
    23  	if t.self == nil {
    24  		panic("time: " + meth + " called on uninitialized Ticker")
    25  	} else if t.self != t {
    26  		panic("time: " + meth + " called on copied Ticker")
    27  	}
    28  }
    29  
    30  // NewTicker returns a new [Ticker] containing a channel that will send
    31  // the current time on the channel after each tick. The period of the
    32  // ticks is specified by the duration argument. The ticker will adjust
    33  // the time interval or drop ticks to make up for slow receivers.
    34  // The duration d must be greater than zero; if not, NewTicker will
    35  // panic.
    36  //
    37  // Before Go 1.23, the garbage collector did not recover
    38  // tickers that had not yet expired or been stopped, so code often
    39  // immediately deferred t.Stop after calling NewTicker, to make
    40  // the ticker recoverable when it was no longer needed.
    41  // As of Go 1.23, the garbage collector can recover unreferenced
    42  // tickers, even if they haven't been stopped.
    43  // The Stop method is no longer necessary to help the garbage collector.
    44  // (Code may of course still want to call Stop to stop the ticker for other reasons.)
    45  func NewTicker(d Duration) *Ticker {
    46  	if d <= 0 {
    47  		panic("non-positive interval for NewTicker")
    48  	}
    49  	// Give the channel a 1-element time buffer.
    50  	// If the client falls behind while reading, we drop ticks
    51  	// on the floor until the client catches up.
    52  	c := make(chan Time, 1)
    53  	t := (*Ticker)(unsafe.Pointer(newTimer(when(d), int64(d), sendTime, c, syncTimer(c))))
    54  	t.C = c
    55  	return t
    56  }
    57  
    58  // Stop turns off a ticker. After Stop, no more ticks will be sent.
    59  // Stop does not close the channel, to permit calling [Ticker.Reset],
    60  // and to prevent a concurrent goroutine reading from the channel
    61  // from seeing an erroneous "tick".
    62  func (t *Ticker) Stop() {
    63  	if t.self != t {
    64  		// This is misuse, and the same for time.Timer would panic,
    65  		// but this didn't always panic, and we keep it not panicking
    66  		// to avoid breaking old programs. See issue 21874.
    67  		return
    68  	}
    69  	stopTimer((*Timer)(unsafe.Pointer(t)))
    70  }
    71  
    72  // Reset stops a ticker and resets its period to the specified duration.
    73  // The next tick will arrive after the new period elapses. The duration d
    74  // must be greater than zero; if not, Reset will panic.
    75  func (t *Ticker) Reset(d Duration) {
    76  	if d <= 0 {
    77  		panic("non-positive interval for Ticker.Reset")
    78  	}
    79  	t.checkValid("Reset")
    80  	resetTimer((*Timer)(unsafe.Pointer(t)), when(d), int64(d))
    81  }
    82  
    83  // Tick is a convenience wrapper for [NewTicker] providing access to the ticking
    84  // channel only. Unlike NewTicker, Tick will return nil if d <= 0.
    85  //
    86  // Before Go 1.23, this documentation warned that the underlying
    87  // [Ticker] would never be recovered by the garbage collector, and that
    88  // if efficiency was a concern, code should use NewTicker instead and
    89  // call [Ticker.Stop] when the ticker is no longer needed.
    90  // As of Go 1.23, the garbage collector can recover unreferenced
    91  // tickers, even if they haven't been stopped.
    92  // The Stop method is no longer necessary to help the garbage collector.
    93  // There is no longer any reason to prefer NewTicker when Tick will do.
    94  func Tick(d Duration) <-chan Time {
    95  	if d <= 0 {
    96  		return nil
    97  	}
    98  	return NewTicker(d).C
    99  }
   100  

View as plain text