Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1629)

Delta Between Two Patch Sets: ssh/buffer.go

Issue 6207051: code review 6207051: go.crypto/ssh: introduce a circular buffer for chanReader (Closed)
Left Patch Set: diff -r d59e35c8940f https://code.google.com/p/go.crypto Created 12 years, 10 months ago
Right Patch Set: diff -r d59e35c8940f https://code.google.com/p/go.crypto Created 12 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | ssh/buffer_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // Copyright 2012 The Go Authors. All rights reserved. 1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package ssh 5 package ssh
6 6
7 import ( 7 import (
8 "io" 8 "io"
9 "sync" 9 "sync"
10 ) 10 )
11 11
12 // buffer provides a linked list buffer for data exchange 12 // buffer provides a linked list buffer for data exchange
13 // between producer and consumer. Theoretically the buffer is 13 // between producer and consumer. Theoretically the buffer is
14 // of unlimited capacity as it does no allocation of its own. 14 // of unlimited capacity as it does no allocation of its own.
15 type buffer struct { 15 type buffer struct {
16 » // protects concurrent access to head, tail and eof 16 » // protects concurrent access to head, tail and closed
17 *sync.Cond 17 *sync.Cond
18 18
19 head *element // the buffer that will be read first 19 head *element // the buffer that will be read first
20 tail *element // the buffer that will be read last 20 tail *element // the buffer that will be read last
21 21
22 closed bool 22 closed bool
23 } 23 }
24 24
25 // An element represents a single link in a linked list. 25 // An element represents a single link in a linked list.
26 type element struct { 26 type element struct {
27 buf []byte 27 buf []byte
28 next *element 28 next *element
29 } 29 }
30 30
31 // newBuffer returns an empty buffer that is not closed. 31 // newBuffer returns an empty buffer that is not closed.
32 func newBuffer() *buffer { 32 func newBuffer() *buffer {
33 e := new(element) 33 e := new(element)
34 b := &buffer{ 34 b := &buffer{
35 Cond: newCond(), 35 Cond: newCond(),
36 head: e, 36 head: e,
37 tail: e, 37 tail: e,
38 } 38 }
39 return b 39 return b
40 } 40 }
41 41
42 // Write makes buf available for Read to receive. 42 // write makes buf available for Read to receive.
43 // buf must not be modified after the call to Write. 43 // buf must not be modified after the call to write.
44 func (b *buffer) Write(buf []byte) (int, error) { 44 func (b *buffer) write(buf []byte) {
45 b.Cond.L.Lock() 45 b.Cond.L.Lock()
46 defer b.Cond.L.Unlock() 46 defer b.Cond.L.Unlock()
47 e := &element{buf: buf} 47 e := &element{buf: buf}
48 b.tail.next = e 48 b.tail.next = e
49 b.tail = e 49 b.tail = e
50 b.Cond.Signal() 50 b.Cond.Signal()
51 return len(buf), nil
52 } 51 }
53 52
54 // eof closes the buffer. Reads from the buffer once all· 53 // eof closes the buffer. Reads from the buffer once all·
55 // the data has been consumed wiil receive os.EOF. 54 // the data has been consumed will receive os.EOF.
56 func (b *buffer) eof() error { 55 func (b *buffer) eof() error {
57 b.Cond.L.Lock() 56 b.Cond.L.Lock()
58 defer b.Cond.L.Unlock() 57 defer b.Cond.L.Unlock()
59 b.closed = true 58 b.closed = true
60 b.Cond.Signal() 59 b.Cond.Signal()
61 return nil 60 return nil
62 } 61 }
63 62
64 // Read reads data from the internal buffer in buf.· 63 // Read reads data from the internal buffer in buf.·
65 // Reads will block if not data is available, or until 64 // Reads will block if no data is available, or until
66 // the buffer is closed. 65 // the buffer is closed.
67 func (b *buffer) Read(buf []byte) (n int, err error) { 66 func (b *buffer) Read(buf []byte) (n int, err error) {
68 b.Cond.L.Lock() 67 b.Cond.L.Lock()
69 defer b.Cond.L.Unlock() 68 defer b.Cond.L.Unlock()
70 » for { 69 » for len(buf) > 0 {
71 // if there is data in b.head, copy it 70 // if there is data in b.head, copy it
72 if len(b.head.buf) > 0 { 71 if len(b.head.buf) > 0 {
73 r := copy(buf, b.head.buf) 72 r := copy(buf, b.head.buf)
74 buf, b.head.buf = buf[r:], b.head.buf[r:] 73 buf, b.head.buf = buf[r:], b.head.buf[r:]
75 n += r 74 n += r
76 if len(buf) == 0 {
77 // dest full
78 break
79 }
80 continue 75 continue
81 } 76 }
82 // if there is a next buffer, make it the head 77 // if there is a next buffer, make it the head
83 if len(b.head.buf) == 0 && b.head != b.tail { 78 if len(b.head.buf) == 0 && b.head != b.tail {
84 b.head = b.head.next 79 b.head = b.head.next
85 continue 80 continue
86 } 81 }
87 » » // if at least one byte has been copied return 82 » » // if at least one byte has been copied, return
88 if n > 0 { 83 if n > 0 {
89 break 84 break
90 } 85 }
91 » » // out of buffers, wait for producer 86 » » // if nothing was read, and there is nothing outstanding
87 » » // check to see if the buffer is closed.
92 if b.closed { 88 if b.closed {
93 err = io.EOF 89 err = io.EOF
94 break 90 break
95 } 91 }
92 // out of buffers, wait for producer
96 b.Cond.Wait() 93 b.Cond.Wait()
97 } 94 }
98 return 95 return
99 } 96 }
LEFTRIGHT
« no previous file | ssh/buffer_test.go » ('j') | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b