github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/shiny/driver/internal/pump/pump.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package pump provides an infinitely buffered event channel. 6 package pump 7 8 // Make returns a new Pump. Call Release to stop pumping events. 9 func Make() Pump { 10 p := Pump{ 11 in: make(chan interface{}), 12 out: make(chan interface{}), 13 release: make(chan struct{}), 14 } 15 go p.run() 16 return p 17 } 18 19 // Pump is an event pump, such that calling Send(e) will eventually send e on 20 // the event channel, in order, but Send will always complete soon, even if 21 // nothing is receiving on the event channel. It is effectively an infinitely 22 // buffered channel. 23 // 24 // In particular, goroutine A calling p.Send will not deadlock even if 25 // goroutine B that's responsible for receiving on p.Events() is currently 26 // blocked trying to send to A on a separate channel. 27 type Pump struct { 28 in chan interface{} 29 out chan interface{} 30 release chan struct{} 31 } 32 33 // Events returns the event channel. 34 func (p *Pump) Events() <-chan interface{} { 35 return p.out 36 } 37 38 // Send sends an event on the event channel. 39 func (p *Pump) Send(event interface{}) { 40 select { 41 case p.in <- event: 42 case <-p.release: 43 } 44 } 45 46 // Release stops the event pump. Pending events may or may not be delivered on 47 // the event channel. Calling Release will not close the event channel. 48 func (p *Pump) Release() { 49 close(p.release) 50 } 51 52 func (p *Pump) run() { 53 // initialSize is the initial size of the circular buffer. It must be a 54 // power of 2. 55 const initialSize = 16 56 i, j, buf, mask := 0, 0, make([]interface{}, initialSize), initialSize-1 57 for { 58 maybeOut := p.out 59 if i == j { 60 maybeOut = nil 61 } 62 select { 63 case maybeOut <- buf[i&mask]: 64 buf[i&mask] = nil 65 i++ 66 case e := <-p.in: 67 // Allocate a bigger buffer if necessary. 68 if i+len(buf) == j { 69 b := make([]interface{}, 2*len(buf)) 70 n := copy(b, buf[j&mask:]) 71 copy(b[n:], buf[:j&mask]) 72 i, j = 0, len(buf) 73 buf, mask = b, len(b)-1 74 } 75 buf[j&mask] = e 76 j++ 77 case <-p.release: 78 return 79 } 80 } 81 }