github.com/aergoio/aergo@v1.3.1/p2p/p2putil/mutexpipe.go (about) 1 /* 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package p2putil 7 8 import ( 9 "sync" 10 "sync/atomic" 11 ) 12 13 type mutexPipe struct { 14 mutex *sync.Mutex 15 16 out chan interface{} 17 18 queue *PressableQueue 19 stop int32 20 21 listener PipeEventListener 22 } 23 24 // newMutexPipe create pipe to output channel out 25 func newMutexPipe(bufSize int, listener PipeEventListener) *mutexPipe { 26 if listener == nil { 27 listener = &StatListener{} 28 } 29 c := &mutexPipe{ 30 mutex: new(sync.Mutex), 31 out: make(chan interface{}, 1), 32 33 queue: NewPressableQueue(bufSize), 34 35 listener: listener, 36 } 37 38 return c 39 } 40 41 func (c *mutexPipe) Put(mo interface{}) bool { 42 // stop is set after this pipe is closed 43 if atomic.LoadInt32(&c.stop) != 0 { 44 return false 45 } 46 c.mutex.Lock() 47 defer c.mutex.Unlock() 48 c.listener.OnIn(mo) 49 if len(c.out) == 0 { 50 if c.queue.Empty() { 51 c.pushToOut(mo) 52 } else { 53 c.pushToOut(c.queue.Poll()) 54 c.queue.Offer(mo) // this offer always return true 55 } 56 } else { 57 if dropped := c.queue.Press(mo); dropped != nil { 58 c.listener.OnDrop(dropped) 59 } 60 } 61 return true 62 } 63 64 func (c *mutexPipe) Out() <-chan interface{} { 65 return c.out 66 } 67 68 func (c *mutexPipe) Done() { 69 c.mutex.Lock() 70 defer c.mutex.Unlock() 71 if len(c.out) == 0 && !c.queue.Empty() { 72 c.pushToOut(c.queue.Poll()) 73 } 74 } 75 76 func (c *mutexPipe) Open() { 77 atomic.StoreInt32(&c.stop, 0) 78 } 79 func (c *mutexPipe) Close() { 80 atomic.StoreInt32(&c.stop, 1) 81 } 82 83 func (c *mutexPipe) pushToOut(e interface{}) { 84 c.out <- e 85 c.listener.OnOut(e) 86 }