|
@@ -32,7 +32,7 @@ type Socket struct {
|
32
|
32
|
maxSendQBytes int
|
33
|
33
|
|
34
|
34
|
// this is a trylock enforcing that only one goroutine can write to `conn` at a time
|
35
|
|
- writerSlotOpen chan bool
|
|
35
|
+ writerSemaphore Semaphore
|
36
|
36
|
|
37
|
37
|
buffer []byte
|
38
|
38
|
closed bool
|
|
@@ -44,12 +44,11 @@ type Socket struct {
|
44
|
44
|
// NewSocket returns a new Socket.
|
45
|
45
|
func NewSocket(conn net.Conn, maxReadQBytes int, maxSendQBytes int) *Socket {
|
46
|
46
|
result := Socket{
|
47
|
|
- conn: conn,
|
48
|
|
- reader: bufio.NewReaderSize(conn, maxReadQBytes),
|
49
|
|
- maxSendQBytes: maxSendQBytes,
|
50
|
|
- writerSlotOpen: make(chan bool, 1),
|
|
47
|
+ conn: conn,
|
|
48
|
+ reader: bufio.NewReaderSize(conn, maxReadQBytes),
|
|
49
|
+ maxSendQBytes: maxSendQBytes,
|
51
|
50
|
}
|
52
|
|
- result.writerSlotOpen <- true
|
|
51
|
+ result.writerSemaphore.Initialize(1)
|
53
|
52
|
return &result
|
54
|
53
|
}
|
55
|
54
|
|
|
@@ -140,14 +139,11 @@ func (socket *Socket) Write(data string) (err error) {
|
140
|
139
|
|
141
|
140
|
// wakeWriter starts the goroutine that actually performs the write, without blocking
|
142
|
141
|
func (socket *Socket) wakeWriter() {
|
143
|
|
- // attempt to acquire the trylock
|
144
|
|
- select {
|
145
|
|
- case <-socket.writerSlotOpen:
|
|
142
|
+ if socket.writerSemaphore.TryAcquire() {
|
146
|
143
|
// acquired the trylock; send() will release it
|
147
|
144
|
go socket.send()
|
148
|
|
- default:
|
149
|
|
- // failed to acquire; the holder will check for more data after releasing it
|
150
|
145
|
}
|
|
146
|
+ // else: do nothing, the holder will check for more data after releasing it
|
151
|
147
|
}
|
152
|
148
|
|
153
|
149
|
// SetFinalData sets the final data to send when the SocketWriter closes.
|
|
@@ -179,19 +175,17 @@ func (socket *Socket) send() {
|
179
|
175
|
socket.performWrite()
|
180
|
176
|
// surrender the trylock, avoiding a race where a write comes in after we've
|
181
|
177
|
// checked readyToWrite() and it returned false, but while we still hold the trylock:
|
182
|
|
- socket.writerSlotOpen <- true
|
|
178
|
+ socket.writerSemaphore.Release()
|
183
|
179
|
// check if more data came in while we held the trylock:
|
184
|
180
|
if !socket.readyToWrite() {
|
185
|
181
|
return
|
186
|
182
|
}
|
187
|
|
- select {
|
188
|
|
- case <-socket.writerSlotOpen:
|
189
|
|
- // got the trylock, loop back around and write
|
190
|
|
- default:
|
|
183
|
+ if !socket.writerSemaphore.TryAcquire() {
|
191
|
184
|
// failed to acquire; exit and wait for the holder to observe readyToWrite()
|
192
|
185
|
// after releasing it
|
193
|
186
|
return
|
194
|
187
|
}
|
|
188
|
+ // got the lock again, loop back around and write
|
195
|
189
|
}
|
196
|
190
|
}
|
197
|
191
|
|