github.com/cranelv/ethereum_mpc@v0.0.0-20191031014521-23aeb1415092/consensus_pbft/util/events/events.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 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 17 package events 18 19 import ( 20 "time" 21 "github.com/ethereum/go-ethereum/consensus_pbft/singletons" 22 ) 23 24 // Event is a type meant to clearly convey that the return type or parameter to a function will be supplied to/from an events.Manager 25 type Event interface{} 26 27 // Receiver is a consumer of events, ProcessEvent will be called serially 28 // as events arrive 29 type Receiver interface { 30 // ProcessEvent delivers an event to the Receiver, if it returns non-nil, the return is the next processed event 31 ProcessEvent(e Event) Event 32 } 33 34 // ------------------------------------------------------------ 35 // 36 // Threaded object 37 // 38 // ------------------------------------------------------------ 39 40 // threaded holds an exit channel to allow threads to break from a select 41 type threaded struct { 42 exit chan struct{} 43 } 44 45 // halt tells the threaded object's thread to exit 46 func (t *threaded) Halt() { 47 select { 48 case <-t.exit: 49 singletons.Log.Warn("Attempted to halt a threaded object twice") 50 default: 51 close(t.exit) 52 } 53 } 54 55 // ------------------------------------------------------------ 56 // 57 // Event Manager 58 // 59 // ------------------------------------------------------------ 60 61 // Manager provides a serialized interface for submitting events to 62 // a Receiver on the other side of the queue 63 type Manager interface { 64 Inject(Event) // A temporary interface to allow the event manager thread to skip the queue 65 Queue() chan<- Event // Get a write-only reference to the queue, to submit events 66 SetReceiver(Receiver) // Set the target to route events to 67 Start() // Starts the Manager thread TODO, these thread management things should probably go away 68 Halt() // Stops the Manager thread 69 } 70 71 // managerImpl is an implementation of Manger 72 type managerImpl struct { 73 threaded 74 receiver Receiver 75 events chan Event 76 } 77 78 // NewManagerImpl creates an instance of managerImpl 79 func NewManagerImpl() Manager { 80 return &managerImpl{ 81 events: make(chan Event), 82 threaded: threaded{make(chan struct{})}, 83 } 84 } 85 86 // SetReceiver sets the destination for events 87 func (em *managerImpl) SetReceiver(receiver Receiver) { 88 em.receiver = receiver 89 } 90 91 // Start creates the go routine necessary to deliver events 92 func (em *managerImpl) Start() { 93 go em.eventLoop() 94 } 95 96 // queue returns a write only reference to the event queue 97 func (em *managerImpl) Queue() chan<- Event { 98 return em.events 99 } 100 101 // SendEvent performs the event loop on a receiver to completion 102 func SendEvent(receiver Receiver, event Event) { 103 next := event 104 for { 105 // If an event returns something non-nil, then process it as a new event 106 next = receiver.ProcessEvent(next) 107 if next == nil { 108 break 109 } 110 } 111 } 112 113 // Inject can only safely be called by the managerImpl thread itself, it skips the queue 114 func (em *managerImpl) Inject(event Event) { 115 if em.receiver != nil { 116 SendEvent(em.receiver, event) 117 } 118 } 119 120 // eventLoop is where the event thread loops, delivering events 121 func (em *managerImpl) eventLoop() { 122 for { 123 select { 124 case next := <-em.events: 125 em.Inject(next) 126 case <-em.exit: 127 singletons.Log.Debug("eventLoop told to exit") 128 return 129 } 130 } 131 } 132 133 // ------------------------------------------------------------ 134 // 135 // Event Timer 136 // 137 // ------------------------------------------------------------ 138 139 // Timer is an interface for managing time driven events 140 // the special contract Timer gives which a traditional golang 141 // timer does not, is that if the event thread calls stop, or reset 142 // then even if the timer has already fired, the event will not be 143 // delivered to the event queue 144 type Timer interface { 145 SoftReset(duration time.Duration, event Event) // start a new countdown, only if one is not already started 146 Reset(duration time.Duration, event Event) // start a new countdown, clear any pending events 147 Stop() // stop the countdown, clear any pending events 148 Halt() // Stops the Timer thread 149 } 150 151 // TimerFactory abstracts the creation of Timers, as they may 152 // need to be mocked for testing 153 type TimerFactory interface { 154 CreateTimer() Timer // Creates an Timer which is stopped 155 } 156 157 // TimerFactoryImpl implements the TimerFactory 158 type timerFactoryImpl struct { 159 manager Manager // The Manager to use in constructing the event timers 160 } 161 162 // NewTimerFactoryImpl creates a new TimerFactory for the given Manager 163 func NewTimerFactoryImpl(manager Manager) TimerFactory { 164 return &timerFactoryImpl{manager} 165 } 166 167 // CreateTimer creates a new timer which deliver events to the Manager for this factory 168 func (etf *timerFactoryImpl) CreateTimer() Timer { 169 return newTimerImpl(etf.manager) 170 } 171 172 // timerStart is used to deliver the start request to the eventTimer thread 173 type timerStart struct { 174 hard bool // Whether to reset the timer if it is running 175 event Event // What event to push onto the event queue 176 duration time.Duration // How long to wait before sending the event 177 } 178 179 // timerImpl is an implementation of Timer 180 type timerImpl struct { 181 threaded // Gives us the exit chan 182 timerChan <-chan time.Time // When non-nil, counts down to preparing to do the event 183 startChan chan *timerStart // Channel to deliver the timer start events to the service go routine 184 stopChan chan struct{} // Channel to deliver the timer stop events to the service go routine 185 manager Manager // The event manager to deliver the event to after timer expiration 186 } 187 188 // newTimer creates a new instance of timerImpl 189 func newTimerImpl(manager Manager) Timer { 190 et := &timerImpl{ 191 startChan: make(chan *timerStart), 192 stopChan: make(chan struct{}), 193 threaded: threaded{make(chan struct{})}, 194 manager: manager, 195 } 196 go et.loop() 197 return et 198 } 199 200 // softReset tells the timer to start a new countdown, only if it is not currently counting down 201 // this will not clear any pending events 202 func (et *timerImpl) SoftReset(timeout time.Duration, event Event) { 203 et.startChan <- &timerStart{ 204 duration: timeout, 205 event: event, 206 hard: false, 207 } 208 } 209 210 // reset tells the timer to start counting down from a new timeout, this also clears any pending events 211 func (et *timerImpl) Reset(timeout time.Duration, event Event) { 212 et.startChan <- &timerStart{ 213 duration: timeout, 214 event: event, 215 hard: true, 216 } 217 } 218 219 // stop tells the timer to stop, and not to deliver any pending events 220 func (et *timerImpl) Stop() { 221 et.stopChan <- struct{}{} 222 } 223 224 // loop is where the timer thread lives, looping 225 func (et *timerImpl) loop() { 226 var eventDestChan chan<- Event 227 var event Event 228 229 for { 230 // A little state machine, relying on the fact that nil channels will block on read/write indefinitely 231 232 select { 233 case start := <-et.startChan: 234 if et.timerChan != nil { 235 if start.hard { 236 singletons.Log.Debug("Resetting a running timer") 237 } else { 238 continue 239 } 240 } 241 singletons.Log.Debug("Starting timer") 242 et.timerChan = time.After(start.duration) 243 if eventDestChan != nil { 244 singletons.Log.Debug("Timer cleared pending event") 245 } 246 event = start.event 247 eventDestChan = nil 248 case <-et.stopChan: 249 if et.timerChan == nil && eventDestChan == nil { 250 singletons.Log.Debug("Attempting to stop an unfired idle timer") 251 } 252 et.timerChan = nil 253 singletons.Log.Debug("Stopping timer") 254 if eventDestChan != nil { 255 singletons.Log.Debug("Timer cleared pending event") 256 } 257 eventDestChan = nil 258 event = nil 259 case <-et.timerChan: 260 singletons.Log.Debug("Event timer fired") 261 et.timerChan = nil 262 eventDestChan = et.manager.Queue() 263 case eventDestChan <- event: 264 singletons.Log.Debug("Timer event delivered") 265 eventDestChan = nil 266 case <-et.exit: 267 singletons.Log.Debug("Halting timer") 268 return 269 } 270 } 271 }