tick.mx raw

   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