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 }