// threadedSendUpdates sends updates to a specific subscriber as they become // available. One thread is needed per subscriber. A separate function was // needed due to race conditions; subscribers must receive updates in the // correct order. Furthermore, a deadlocked subscriber should not interfere // with consensus; updates cannot make blocking calls from any thread that is // holding a lock on consensus. The result is a construction where all updates // are added to a list of updates in the consensus set while the consensus set // is locked. Then, a separate thread for each subscriber will be notified (via // the update chan) that there are new updates. The thread will lock the // consensus set for long enough to get the updates, and then will unlock the // consensus set while it makes a blocking call to the subscriber. If the // subscriber deadlocks or has problems, the thread will stall indefinitely, // but the rest of consensus will not be disrupted. func (s *State) threadedSendUpdates(update chan struct{}, subscriber modules.ConsensusSetSubscriber) { i := 0 for { id := s.mu.RLock() updateCount := len(s.consensusChanges) s.mu.RUnlock(id) for i < updateCount { // Get the set of blocks that changed since the previous update. id := s.mu.RLock() cc := s.consensusChanges[i] s.mu.RUnlock(id) // Update the subscriber with the changes. subscriber.ReceiveConsensusSetUpdate(cc) i++ } // Wait until there has been another update. <-update } }