Left: | ||
Right: |
LEFT | RIGHT |
---|---|
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 |
agl1
2012/05/14 15:21:31
s/eof/closed/?
dfc
2012/05/15 01:12:58
Done.
| |
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. |
agl1
2012/05/14 15:21:31
this refers to `buf' but the argument is called 'b
dfc
2012/05/15 01:12:58
Sorry, i'm not sure what you mean, the receiver is
agl1
2012/05/15 15:30:07
Sorry, my brain fart.
| |
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) { | 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 } | 51 } |
52 | 52 |
53 // eof closes the buffer. Reads from the buffer once all· | 53 // eof closes the buffer. Reads from the buffer once all· |
54 // the data has been consumed wiil receive os.EOF. | 54 // the data has been consumed will receive os.EOF. |
55 func (b *buffer) eof() error { | 55 func (b *buffer) eof() error { |
56 b.Cond.L.Lock() | 56 b.Cond.L.Lock() |
57 defer b.Cond.L.Unlock() | 57 defer b.Cond.L.Unlock() |
58 b.closed = true | 58 b.closed = true |
59 b.Cond.Signal() | 59 b.Cond.Signal() |
60 return nil | 60 return nil |
61 } | 61 } |
62 | 62 |
63 // Read reads data from the internal buffer in buf.· | 63 // Read reads data from the internal buffer in buf.· |
agl1
2012/05/14 15:21:31
ditto about buf/b.
dfc
2012/05/15 01:12:58
See above.
On 2012/05/14 15:21:31, agl1 wrote:
| |
64 // Reads will block if not data is available, or until | 64 // Reads will block if no data is available, or until |
agl1
2012/05/14 15:21:31
s/not/no/
dfc
2012/05/15 01:12:58
Done.
| |
65 // the buffer is closed. | 65 // the buffer is closed. |
66 func (b *buffer) Read(buf []byte) (n int, err error) { | 66 func (b *buffer) Read(buf []byte) (n int, err error) { |
67 b.Cond.L.Lock() | 67 b.Cond.L.Lock() |
68 defer b.Cond.L.Unlock() | 68 defer b.Cond.L.Unlock() |
69 » for { | 69 » for len(buf) > 0 { |
70 // if there is data in b.head, copy it | 70 // if there is data in b.head, copy it |
71 if len(b.head.buf) > 0 { | 71 if len(b.head.buf) > 0 { |
72 r := copy(buf, b.head.buf) | 72 r := copy(buf, b.head.buf) |
73 buf, b.head.buf = buf[r:], b.head.buf[r:] | 73 buf, b.head.buf = buf[r:], b.head.buf[r:] |
74 n += r | 74 n += r |
75 if len(buf) == 0 { | |
agl1
2012/05/14 15:21:31
I think it's very slightly nicer if the for loop h
dfc
2012/05/15 01:12:58
Thanks for the suggestion, it is nicer and the log
| |
76 // dest full | |
77 break | |
78 } | |
79 continue | 75 continue |
80 } | 76 } |
81 // if there is a next buffer, make it the head | 77 // if there is a next buffer, make it the head |
82 if len(b.head.buf) == 0 && b.head != b.tail { | 78 if len(b.head.buf) == 0 && b.head != b.tail { |
83 b.head = b.head.next | 79 b.head = b.head.next |
84 continue | 80 continue |
85 } | 81 } |
86 » » // if at least one byte has been copied return | 82 » » // if at least one byte has been copied, return |
87 if n > 0 { | 83 if n > 0 { |
88 break | 84 break |
89 } | 85 } |
90 » » // out of buffers, wait for producer | 86 » » // if nothing was read, and there is nothing outstanding |
agl1
2012/05/14 15:21:31
this comment should be moved down to the Wait()?
dfc
2012/05/15 01:12:58
Done.
| |
87 » » // check to see if the buffer is closed. | |
91 if b.closed { | 88 if b.closed { |
92 err = io.EOF | 89 err = io.EOF |
93 break | 90 break |
94 } | 91 } |
92 // out of buffers, wait for producer | |
95 b.Cond.Wait() | 93 b.Cond.Wait() |
96 } | 94 } |
97 return | 95 return |
98 } | 96 } |
LEFT | RIGHT |