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  }