mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 00:52:25 -06:00 
			
		
		
		
	
		
			
	
	
		
			98 lines
		
	
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			98 lines
		
	
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2012 The Go Authors. All rights reserved.
							 | 
						||
| 
								 | 
							
								// Use of this source code is governed by a BSD-style
							 | 
						||
| 
								 | 
							
								// license that can be found in the LICENSE file.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package ssh
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"io"
							 | 
						||
| 
								 | 
							
									"sync"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// buffer provides a linked list buffer for data exchange
							 | 
						||
| 
								 | 
							
								// between producer and consumer. Theoretically the buffer is
							 | 
						||
| 
								 | 
							
								// of unlimited capacity as it does no allocation of its own.
							 | 
						||
| 
								 | 
							
								type buffer struct {
							 | 
						||
| 
								 | 
							
									// protects concurrent access to head, tail and closed
							 | 
						||
| 
								 | 
							
									*sync.Cond
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									head *element // the buffer that will be read first
							 | 
						||
| 
								 | 
							
									tail *element // the buffer that will be read last
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									closed bool
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// An element represents a single link in a linked list.
							 | 
						||
| 
								 | 
							
								type element struct {
							 | 
						||
| 
								 | 
							
									buf  []byte
							 | 
						||
| 
								 | 
							
									next *element
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// newBuffer returns an empty buffer that is not closed.
							 | 
						||
| 
								 | 
							
								func newBuffer() *buffer {
							 | 
						||
| 
								 | 
							
									e := new(element)
							 | 
						||
| 
								 | 
							
									b := &buffer{
							 | 
						||
| 
								 | 
							
										Cond: newCond(),
							 | 
						||
| 
								 | 
							
										head: e,
							 | 
						||
| 
								 | 
							
										tail: e,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return b
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// write makes buf available for Read to receive.
							 | 
						||
| 
								 | 
							
								// buf must not be modified after the call to write.
							 | 
						||
| 
								 | 
							
								func (b *buffer) write(buf []byte) {
							 | 
						||
| 
								 | 
							
									b.Cond.L.Lock()
							 | 
						||
| 
								 | 
							
									e := &element{buf: buf}
							 | 
						||
| 
								 | 
							
									b.tail.next = e
							 | 
						||
| 
								 | 
							
									b.tail = e
							 | 
						||
| 
								 | 
							
									b.Cond.Signal()
							 | 
						||
| 
								 | 
							
									b.Cond.L.Unlock()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// eof closes the buffer. Reads from the buffer once all
							 | 
						||
| 
								 | 
							
								// the data has been consumed will receive io.EOF.
							 | 
						||
| 
								 | 
							
								func (b *buffer) eof() {
							 | 
						||
| 
								 | 
							
									b.Cond.L.Lock()
							 | 
						||
| 
								 | 
							
									b.closed = true
							 | 
						||
| 
								 | 
							
									b.Cond.Signal()
							 | 
						||
| 
								 | 
							
									b.Cond.L.Unlock()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Read reads data from the internal buffer in buf.  Reads will block
							 | 
						||
| 
								 | 
							
								// if no data is available, or until the buffer is closed.
							 | 
						||
| 
								 | 
							
								func (b *buffer) Read(buf []byte) (n int, err error) {
							 | 
						||
| 
								 | 
							
									b.Cond.L.Lock()
							 | 
						||
| 
								 | 
							
									defer b.Cond.L.Unlock()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for len(buf) > 0 {
							 | 
						||
| 
								 | 
							
										// if there is data in b.head, copy it
							 | 
						||
| 
								 | 
							
										if len(b.head.buf) > 0 {
							 | 
						||
| 
								 | 
							
											r := copy(buf, b.head.buf)
							 | 
						||
| 
								 | 
							
											buf, b.head.buf = buf[r:], b.head.buf[r:]
							 | 
						||
| 
								 | 
							
											n += r
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										// if there is a next buffer, make it the head
							 | 
						||
| 
								 | 
							
										if len(b.head.buf) == 0 && b.head != b.tail {
							 | 
						||
| 
								 | 
							
											b.head = b.head.next
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// if at least one byte has been copied, return
							 | 
						||
| 
								 | 
							
										if n > 0 {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// if nothing was read, and there is nothing outstanding
							 | 
						||
| 
								 | 
							
										// check to see if the buffer is closed.
							 | 
						||
| 
								 | 
							
										if b.closed {
							 | 
						||
| 
								 | 
							
											err = io.EOF
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										// out of buffers, wait for producer
							 | 
						||
| 
								 | 
							
										b.Cond.Wait()
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 |