1 /* 2 Copyright 2017 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 16 Modified by Duncan Jones to remove the external dependency. 17 */ 18 19 // Package timer provides various enhanced timer functions. 20 package pool 21 22 import ( 23 "sync" 24 "time" 25 ) 26 27 // Out-of-band messages 28 type typeAction int 29 30 const ( 31 timerStop typeAction = iota 32 timerReset 33 timerTrigger 34 ) 35 36 /* 37 Timer provides timer functionality that can be controlled 38 by the user. You start the timer by providing it a callback function, 39 which it will call at the specified interval. 40 41 var t = timer.NewTimer(1e9) 42 t.Start(KeepHouse) 43 44 func KeepHouse() { 45 // do house keeping work 46 } 47 48 You can stop the timer by calling t.Stop, which is guaranteed to 49 wait if KeepHouse is being executed. 50 51 You can create an untimely trigger by calling t.Trigger. You can also 52 schedule an untimely trigger by calling t.TriggerAfter. 53 54 The timer interval can be changed on the fly by calling t.SetInterval. 55 A zero value interval will cause the timer to wait indefinitely, and it 56 will react only to an explicit Trigger or Stop. 57 */ 58 type Timer struct { 59 interval AtomicDuration 60 61 // state management 62 mu sync.Mutex 63 running bool 64 65 // msg is used for out-of-band messages 66 msg chan typeAction 67 } 68 69 // NewTimer creates a new Timer object 70 func NewTimer(interval time.Duration) *Timer { 71 tm := &Timer{ 72 msg: make(chan typeAction), 73 } 74 tm.interval.Set(interval) 75 return tm 76 } 77 78 // Start starts the timer. 79 func (tm *Timer) Start(keephouse func()) { 80 tm.mu.Lock() 81 defer tm.mu.Unlock() 82 if tm.running { 83 return 84 } 85 tm.running = true 86 go tm.run(keephouse) 87 } 88 89 func (tm *Timer) run(keephouse func()) { 90 var timer *time.Timer 91 for { 92 var ch <-chan time.Time 93 interval := tm.interval.Get() 94 if interval > 0 { 95 timer = time.NewTimer(interval) 96 ch = timer.C 97 } 98 select { 99 case action := <-tm.msg: 100 if timer != nil { 101 timer.Stop() 102 timer = nil 103 } 104 switch action { 105 case timerStop: 106 return 107 case timerReset: 108 continue 109 } 110 case <-ch: 111 } 112 keephouse() 113 } 114 } 115 116 // SetInterval changes the wait interval. 117 // It will cause the timer to restart the wait. 118 func (tm *Timer) SetInterval(ns time.Duration) { 119 tm.interval.Set(ns) 120 tm.mu.Lock() 121 defer tm.mu.Unlock() 122 if tm.running { 123 tm.msg <- timerReset 124 } 125 } 126 127 // Trigger will cause the timer to immediately execute the keephouse function. 128 // It will then cause the timer to restart the wait. 129 func (tm *Timer) Trigger() { 130 tm.mu.Lock() 131 defer tm.mu.Unlock() 132 if tm.running { 133 tm.msg <- timerTrigger 134 } 135 } 136 137 // TriggerAfter waits for the specified duration and triggers the next event. 138 func (tm *Timer) TriggerAfter(duration time.Duration) { 139 go func() { 140 time.Sleep(duration) 141 tm.Trigger() 142 }() 143 } 144 145 // Stop will stop the timer. It guarantees that the timer will not execute 146 // any more calls to keephouse once it has returned. 147 func (tm *Timer) Stop() { 148 tm.mu.Lock() 149 defer tm.mu.Unlock() 150 if tm.running { 151 tm.msg <- timerStop 152 tm.running = false 153 } 154 } 155 156 // Interval returns the current interval. 157 func (tm *Timer) Interval() time.Duration { 158 return tm.interval.Get() 159 } 160