9
9
"encoding/json"
10
10
"fmt"
11
11
"io"
12
+ "sync"
12
13
"sync/atomic"
13
14
14
15
"golang.org/x/tools/internal/event"
@@ -45,8 +46,11 @@ type ConnectionOptions struct {
45
46
// Connection is bidirectional; it does not have a designated server or client
46
47
// end.
47
48
type Connection struct {
48
- seq int64 // must only be accessed using atomic operations
49
- closer io.Closer
49
+ seq int64 // must only be accessed using atomic operations
50
+
51
+ closeOnce sync.Once
52
+ closer io.Closer
53
+
50
54
writerBox chan Writer
51
55
outgoingBox chan map [ID ]chan <- * Response
52
56
incomingBox chan map [ID ]* incoming
@@ -275,14 +279,13 @@ func (c *Connection) Wait() error {
275
279
// This does not cancel in flight requests, but waits for them to gracefully complete.
276
280
func (c * Connection ) Close () error {
277
281
// close the underlying stream
278
- if err := c .closer .Close (); err != nil && ! isClosingError (err ) {
279
- return err
280
- }
282
+ c .closeOnce .Do (func () {
283
+ if err := c .closer .Close (); err != nil {
284
+ c .async .setError (err )
285
+ }
286
+ })
281
287
// and then wait for it to cause the connection to close
282
- if err := c .Wait (); err != nil && ! isClosingError (err ) {
283
- return err
284
- }
285
- return nil
288
+ return c .Wait ()
286
289
}
287
290
288
291
// readIncoming collects inbound messages from the reader and delivers them, either responding
@@ -295,7 +298,9 @@ func (c *Connection) readIncoming(ctx context.Context, reader Reader, toQueue ch
295
298
msg , n , err := reader .Read (ctx )
296
299
if err != nil {
297
300
// The stream failed, we cannot continue
298
- c .async .setError (err )
301
+ if ! isClosingError (err ) {
302
+ c .async .setError (err )
303
+ }
299
304
return
300
305
}
301
306
switch msg := msg .(type ) {
@@ -395,7 +400,23 @@ func (c *Connection) manageQueue(ctx context.Context, preempter Preempter, fromR
395
400
}
396
401
397
402
func (c * Connection ) deliverMessages (ctx context.Context , handler Handler , fromQueue <- chan * incoming ) {
398
- defer c .async .done ()
403
+ defer func () {
404
+ // Close the underlying ReadWriteCloser if not already closed. We're about
405
+ // to mark the Connection as done, so we'd better actually be done! 😅
406
+ //
407
+ // TODO(bcmills): This is actually a bit premature, since we may have
408
+ // asynchronous handlers still in flight at this point, but it's at least no
409
+ // more premature than calling c.async.done at this point (which we were
410
+ // already doing). This will get a proper fix in https://go.dev/cl/388134.
411
+ c .closeOnce .Do (func () {
412
+ if err := c .closer .Close (); err != nil {
413
+ c .async .setError (err )
414
+ }
415
+ })
416
+
417
+ c .async .done ()
418
+ }()
419
+
399
420
for entry := range fromQueue {
400
421
// cancel any messages in the queue that we have a pending cancel for
401
422
var result interface {}
0 commit comments