github.com/geniusesgroup/libgo@v0.0.0-20220713101832-828057a9d3d4/timer/timer.go (about)

     1  /* For license and copyright information please see LEGAL file in repository */
     2  
     3  package timer
     4  
     5  import (
     6  	"../protocol"
     7  )
     8  
     9  // A Timer must be created with Init, After or AfterFunc.
    10  // Due to atomic function need memory alignment, Don't change fields order.
    11  type Timer struct {
    12  	// Timer wakes up at when, and then at when+period, ... (period > 0 only)
    13  	// each time calling callback(arg) in the timer goroutine, so callback must be
    14  	// a well-behaved function and not block.
    15  	// when must be positive on an active timer.
    16  	when         int64
    17  	period       int64
    18  	periodNumber int64 // -1 means no limit
    19  
    20  	// The status field holds one of the values in status file.
    21  	status status
    22  
    23  	signal chan struct{}
    24  
    25  	// callback function that call when reach
    26  	// it is possible that callback will be called a little after the delay.
    27  	callback func(arg any) // NOTE: must not be closure and must not block the caller.
    28  	arg      any
    29  
    30  	timers *Timers
    31  }
    32  
    33  // Init initialize the Timer with given callback function or make the channel and send signal on it
    34  // Be aware that given function must not be closure and must not block the caller.
    35  func (t *Timer) Init(callback func(arg any), arg any) {
    36  	if t.callback != nil {
    37  		panic("timer: Don't initialize a timer twice. Use Reset() method to change the timer.")
    38  	}
    39  
    40  	if callback == nil {
    41  		// Give the channel a 1-element buffer.
    42  		// If the client falls behind while reading, we drop ticks
    43  		// on the floor until the client catches up.
    44  		t.signal = make(chan struct{}, 1)
    45  		t.callback = notifyTimerChannel
    46  		t.arg = t
    47  	} else {
    48  		t.callback = callback
    49  		t.arg = arg
    50  	}
    51  }
    52  func (t *Timer) Signal() <-chan struct{}                           { return t.signal }
    53  func (t *Timer) Start(d protocol.Duration)                         { t.add(d) }
    54  func (t *Timer) Stop() (alreadyStopped bool)                       { return t.delete() }
    55  func (t *Timer) Reset(d protocol.Duration) (alreadyActivated bool) { return t.modify(d) }
    56  
    57  // After waits for the duration to elapse and then sends signal on the returned channel.
    58  // The underlying Timer is not recovered by the garbage collector
    59  // until the timer fires. If efficiency is a concern, copy the body
    60  // instead and call timer.Stop() if the timer is no longer needed.
    61  func After(d protocol.Duration) <-chan struct{} {
    62  	var timer Timer
    63  	timer.Init(nil, nil)
    64  	timer.Start(d)
    65  	return timer.Signal()
    66  }
    67  
    68  // AfterFunc waits for the duration to elapse and then calls f
    69  // in its own goroutine. It returns a Timer that can
    70  // be used to cancel the call using its Stop method.
    71  func AfterFunc(d protocol.Duration, cb func(arg any), arg any) *Timer {
    72  	var timer Timer
    73  	timer.Init(callback(cb).concurrentRun, arg)
    74  	timer.Start(d)
    75  	return &timer
    76  }