Skip to content

Commit e55c2e9

Browse files
authored
Merge pull request #1438 from huynhquangtoan/master
Fix "panic: send on closed channel"
2 parents 4bf9f0b + 6ee5247 commit e55c2e9

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

pkg/core/track.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ func (s *Sender) Start() {
140140
s.done = make(chan struct{})
141141

142142
go func() {
143+
// for range on nil chan is OK
143144
for packet := range s.buf {
144145
s.Output(packet)
145146
}
@@ -148,7 +149,7 @@ func (s *Sender) Start() {
148149
}
149150

150151
func (s *Sender) Wait() {
151-
if done := s.done; s.done != nil {
152+
if done := s.done; done != nil {
152153
<-done
153154
}
154155
}
@@ -165,10 +166,12 @@ func (s *Sender) State() string {
165166

166167
func (s *Sender) Close() {
167168
// close buffer if exists
168-
if buf := s.buf; buf != nil {
169-
s.buf = nil
170-
defer close(buf)
169+
s.mu.Lock()
170+
if s.buf != nil {
171+
close(s.buf) // exit from for range loop
172+
s.buf = nil // prevent writing to closed chan
171173
}
174+
s.mu.Unlock()
172175

173176
s.Node.Close()
174177
}

pkg/core/track_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package core
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestSenser(t *testing.T) {
10+
recv := make(chan *Packet) // blocking receiver
11+
12+
sender := NewSender(nil, &Codec{})
13+
sender.Output = func(packet *Packet) {
14+
recv <- packet
15+
}
16+
require.Equal(t, "new", sender.State())
17+
18+
sender.Start()
19+
require.Equal(t, "connected", sender.State())
20+
21+
sender.Input(&Packet{})
22+
sender.Input(&Packet{})
23+
24+
require.Equal(t, 2, sender.Packets)
25+
require.Equal(t, 0, sender.Drops)
26+
27+
// important to read one before close
28+
// because goroutine in Start() can run with nil chan
29+
// it's OK in real life, but bad for test
30+
_, ok := <-recv
31+
require.True(t, ok)
32+
33+
sender.Close()
34+
require.Equal(t, "closed", sender.State())
35+
36+
sender.Input(&Packet{})
37+
38+
require.Equal(t, 2, sender.Packets)
39+
require.Equal(t, 1, sender.Drops)
40+
41+
// read 2nd
42+
_, ok = <-recv
43+
require.True(t, ok)
44+
45+
// read 3rd
46+
select {
47+
case <-recv:
48+
ok = true
49+
default:
50+
ok = false
51+
}
52+
require.False(t, ok)
53+
}

0 commit comments

Comments
 (0)