mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 20:27:35 +03:00
fix deadlock when concurrently closing server and transport (#4332)
* server: fix deadlock when closing concurrently with transport * add test for checking no deadlock
This commit is contained in:
parent
ba1fbbe964
commit
d6269b71af
2 changed files with 34 additions and 9 deletions
22
server.go
22
server.go
|
@ -98,7 +98,7 @@ type baseServer struct {
|
||||||
protocol.Version,
|
protocol.Version,
|
||||||
) quicConn
|
) quicConn
|
||||||
|
|
||||||
closeOnce sync.Once
|
closeMx sync.Mutex
|
||||||
errorChan chan struct{} // is closed when the server is closed
|
errorChan chan struct{} // is closed when the server is closed
|
||||||
closeErr error
|
closeErr error
|
||||||
running chan struct{} // closed as soon as run() returns
|
running chan struct{} // closed as soon as run() returns
|
||||||
|
@ -338,15 +338,19 @@ func (s *baseServer) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *baseServer) close(e error, notifyOnClose bool) {
|
func (s *baseServer) close(e error, notifyOnClose bool) {
|
||||||
s.closeOnce.Do(func() {
|
s.closeMx.Lock()
|
||||||
s.closeErr = e
|
if s.closeErr != nil {
|
||||||
close(s.errorChan)
|
s.closeMx.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.closeErr = e
|
||||||
|
close(s.errorChan)
|
||||||
|
<-s.running
|
||||||
|
s.closeMx.Unlock()
|
||||||
|
|
||||||
<-s.running
|
if notifyOnClose {
|
||||||
if notifyOnClose {
|
s.onClose()
|
||||||
s.onClose()
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Addr returns the server's network address
|
// Addr returns the server's network address
|
||||||
|
|
|
@ -122,6 +122,27 @@ var _ = Describe("Transport", func() {
|
||||||
tr.Close()
|
tr.Close()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("closes transport concurrently with listener", func() {
|
||||||
|
// try 10 times to trigger race conditions
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
packetChan := make(chan packetToRead)
|
||||||
|
tr := &Transport{Conn: newMockPacketConn(packetChan)}
|
||||||
|
ln, err := tr.Listen(&tls.Config{}, nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
ch := make(chan bool)
|
||||||
|
// Close transport and listener concurrently.
|
||||||
|
go func() {
|
||||||
|
ch <- true
|
||||||
|
Expect(ln.Close()).To(Succeed())
|
||||||
|
ch <- true
|
||||||
|
}()
|
||||||
|
<-ch
|
||||||
|
close(packetChan)
|
||||||
|
Expect(tr.Close()).To(Succeed())
|
||||||
|
<-ch
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
It("drops unparseable QUIC packets", func() {
|
It("drops unparseable QUIC packets", func() {
|
||||||
addr := &net.UDPAddr{IP: net.IPv4(9, 8, 7, 6), Port: 1234}
|
addr := &net.UDPAddr{IP: net.IPv4(9, 8, 7, 6), Port: 1234}
|
||||||
packetChan := make(chan packetToRead)
|
packetChan := make(chan packetToRead)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue