github.com/theQRL/go-zond@v0.1.1/event/feedof.go (about) 1 // Copyright 2022 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package event 18 19 import ( 20 "reflect" 21 "sync" 22 ) 23 24 // FeedOf implements one-to-many subscriptions where the carrier of events is a channel. 25 // Values sent to a Feed are delivered to all subscribed channels simultaneously. 26 // 27 // The zero value is ready to use. 28 type FeedOf[T any] struct { 29 once sync.Once // ensures that init only runs once 30 sendLock chan struct{} // sendLock has a one-element buffer and is empty when held.It protects sendCases. 31 removeSub chan chan<- T // interrupts Send 32 sendCases caseList // the active set of select cases used by Send 33 34 // The inbox holds newly subscribed channels until they are added to sendCases. 35 mu sync.Mutex 36 inbox caseList 37 } 38 39 func (f *FeedOf[T]) init() { 40 f.removeSub = make(chan chan<- T) 41 f.sendLock = make(chan struct{}, 1) 42 f.sendLock <- struct{}{} 43 f.sendCases = caseList{{Chan: reflect.ValueOf(f.removeSub), Dir: reflect.SelectRecv}} 44 } 45 46 // Subscribe adds a channel to the feed. Future sends will be delivered on the channel 47 // until the subscription is canceled. 48 // 49 // The channel should have ample buffer space to avoid blocking other subscribers. Slow 50 // subscribers are not dropped. 51 func (f *FeedOf[T]) Subscribe(channel chan<- T) Subscription { 52 f.once.Do(f.init) 53 54 chanval := reflect.ValueOf(channel) 55 sub := &feedOfSub[T]{feed: f, channel: channel, err: make(chan error, 1)} 56 57 // Add the select case to the inbox. 58 // The next Send will add it to f.sendCases. 59 f.mu.Lock() 60 defer f.mu.Unlock() 61 cas := reflect.SelectCase{Dir: reflect.SelectSend, Chan: chanval} 62 f.inbox = append(f.inbox, cas) 63 return sub 64 } 65 66 func (f *FeedOf[T]) remove(sub *feedOfSub[T]) { 67 // Delete from inbox first, which covers channels 68 // that have not been added to f.sendCases yet. 69 f.mu.Lock() 70 index := f.inbox.find(sub.channel) 71 if index != -1 { 72 f.inbox = f.inbox.delete(index) 73 f.mu.Unlock() 74 return 75 } 76 f.mu.Unlock() 77 78 select { 79 case f.removeSub <- sub.channel: 80 // Send will remove the channel from f.sendCases. 81 case <-f.sendLock: 82 // No Send is in progress, delete the channel now that we have the send lock. 83 f.sendCases = f.sendCases.delete(f.sendCases.find(sub.channel)) 84 f.sendLock <- struct{}{} 85 } 86 } 87 88 // Send delivers to all subscribed channels simultaneously. 89 // It returns the number of subscribers that the value was sent to. 90 func (f *FeedOf[T]) Send(value T) (nsent int) { 91 rvalue := reflect.ValueOf(value) 92 93 f.once.Do(f.init) 94 <-f.sendLock 95 96 // Add new cases from the inbox after taking the send lock. 97 f.mu.Lock() 98 f.sendCases = append(f.sendCases, f.inbox...) 99 f.inbox = nil 100 f.mu.Unlock() 101 102 // Set the sent value on all channels. 103 for i := firstSubSendCase; i < len(f.sendCases); i++ { 104 f.sendCases[i].Send = rvalue 105 } 106 107 // Send until all channels except removeSub have been chosen. 'cases' tracks a prefix 108 // of sendCases. When a send succeeds, the corresponding case moves to the end of 109 // 'cases' and it shrinks by one element. 110 cases := f.sendCases 111 for { 112 // Fast path: try sending without blocking before adding to the select set. 113 // This should usually succeed if subscribers are fast enough and have free 114 // buffer space. 115 for i := firstSubSendCase; i < len(cases); i++ { 116 if cases[i].Chan.TrySend(rvalue) { 117 nsent++ 118 cases = cases.deactivate(i) 119 i-- 120 } 121 } 122 if len(cases) == firstSubSendCase { 123 break 124 } 125 // Select on all the receivers, waiting for them to unblock. 126 chosen, recv, _ := reflect.Select(cases) 127 if chosen == 0 /* <-f.removeSub */ { 128 index := f.sendCases.find(recv.Interface()) 129 f.sendCases = f.sendCases.delete(index) 130 if index >= 0 && index < len(cases) { 131 // Shrink 'cases' too because the removed case was still active. 132 cases = f.sendCases[:len(cases)-1] 133 } 134 } else { 135 cases = cases.deactivate(chosen) 136 nsent++ 137 } 138 } 139 140 // Forget about the sent value and hand off the send lock. 141 for i := firstSubSendCase; i < len(f.sendCases); i++ { 142 f.sendCases[i].Send = reflect.Value{} 143 } 144 f.sendLock <- struct{}{} 145 return nsent 146 } 147 148 type feedOfSub[T any] struct { 149 feed *FeedOf[T] 150 channel chan<- T 151 errOnce sync.Once 152 err chan error 153 } 154 155 func (sub *feedOfSub[T]) Unsubscribe() { 156 sub.errOnce.Do(func() { 157 sub.feed.remove(sub) 158 close(sub.err) 159 }) 160 } 161 162 func (sub *feedOfSub[T]) Err() <-chan error { 163 return sub.err 164 }