File tree Expand file tree Collapse file tree 2 files changed +22
-13
lines changed Expand file tree Collapse file tree 2 files changed +22
-13
lines changed Original file line number Diff line number Diff line change @@ -381,38 +381,42 @@ func (c *Connection) shutdown(err *Error) {
381
381
382
382
c .destructor .Do (func () {
383
383
c .m .Lock ()
384
- closes := make ([]chan * Error , len (c .closes ))
385
- copy (closes , c .closes )
386
- c .m .Unlock ()
384
+ defer c .m .Unlock ()
385
+
387
386
if err != nil {
388
- for _ , c := range closes {
387
+ for _ , c := range c . closes {
389
388
c <- err
390
389
}
391
390
}
392
391
393
- for _ , ch := range c .channels {
394
- c .closeChannel (ch , err )
395
- }
396
-
397
392
if err != nil {
398
393
c .errors <- err
399
394
}
400
395
// Shutdown handler goroutine can still receive the result.
401
396
close (c .errors )
402
397
403
- c .conn .Close ()
404
-
405
- for _ , c := range closes {
398
+ for _ , c := range c .closes {
406
399
close (c )
407
400
}
408
401
409
402
for _ , c := range c .blocks {
410
403
close (c )
411
404
}
412
405
413
- c .m .Lock ()
406
+ // Shutdown the channel, but do not use closeChannel() as it calls
407
+ // releaseChannel() which requires the connection lock.
408
+ //
409
+ // Ranging over c.channels and calling releaseChannel() that mutates
410
+ // c.channels is racy - see commit 6063341 for an example.
411
+ for _ , ch := range c .channels {
412
+ ch .shutdown (err )
413
+ }
414
+
415
+ c .conn .Close ()
416
+
417
+ c .channels = map [uint16 ]* Channel {}
418
+ c .allocator = newAllocator (1 , c .Config .ChannelMax )
414
419
c .noNotify = true
415
- c .m .Unlock ()
416
420
})
417
421
}
418
422
Original file line number Diff line number Diff line change @@ -12,6 +12,7 @@ import (
12
12
"net"
13
13
"sync"
14
14
"testing"
15
+ "time"
15
16
)
16
17
17
18
func TestRequiredServerLocale (t * testing.T ) {
@@ -68,6 +69,8 @@ func TestChannelOpenOnAClosedConnectionFails_ReleasesAllocatedChannel(t *testing
68
69
// See https://github.com/streadway/amqp/issues/251 - thanks to jmalloc for the
69
70
// test case.
70
71
func TestRaceBetweenChannelAndConnectionClose (t * testing.T ) {
72
+ defer time .AfterFunc (10 * time .Second , func () { panic ("Close deadlock" ) }).Stop ()
73
+
71
74
conn := integrationConnection (t , "allocation/shutdown race" )
72
75
73
76
go conn .Close ()
@@ -88,6 +91,8 @@ func TestRaceBetweenChannelAndConnectionClose(t *testing.T) {
88
91
// See https://github.com/streadway/amqp/pull/253#issuecomment-292464811 for
89
92
// more details - thanks to jmalloc again.
90
93
func TestRaceBetweenChannelShutdownAndSend (t * testing.T ) {
94
+ defer time .AfterFunc (10 * time .Second , func () { panic ("Close deadlock" ) }).Stop ()
95
+
91
96
conn := integrationConnection (t , "channel close/send race" )
92
97
defer conn .Close ()
93
98
You can’t perform that action at this time.
0 commit comments