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  }