mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-04 20:57:36 +03:00
fix availability signaling of the send queue (#3597)
This commit is contained in:
parent
e496120c76
commit
af30cef57c
2 changed files with 49 additions and 0 deletions
|
@ -36,6 +36,13 @@ func newSendQueue(conn sendConn) sender {
|
||||||
func (h *sendQueue) Send(p *packetBuffer) {
|
func (h *sendQueue) Send(p *packetBuffer) {
|
||||||
select {
|
select {
|
||||||
case h.queue <- p:
|
case h.queue <- p:
|
||||||
|
// clear available channel if we've reached capacity
|
||||||
|
if len(h.queue) == sendQueueCapacity {
|
||||||
|
select {
|
||||||
|
case <-h.available:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
case <-h.runStopped:
|
case <-h.runStopped:
|
||||||
default:
|
default:
|
||||||
panic("sendQueue.Send would have blocked")
|
panic("sendQueue.Send would have blocked")
|
||||||
|
|
|
@ -73,6 +73,48 @@ var _ = Describe("Send Queue", func() {
|
||||||
Eventually(done).Should(BeClosed())
|
Eventually(done).Should(BeClosed())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("signals when sending is possible again, when the first write succeeded", func() {
|
||||||
|
write := make(chan struct{}, 1)
|
||||||
|
written := make(chan struct{}, 100)
|
||||||
|
// now start sending out packets. This should free up queue space.
|
||||||
|
c.EXPECT().Write(gomock.Any()).DoAndReturn(func(b []byte) error {
|
||||||
|
<-write
|
||||||
|
written <- struct{}{}
|
||||||
|
return nil
|
||||||
|
}).AnyTimes()
|
||||||
|
// allow the first packet to be sent immediately
|
||||||
|
write <- struct{}{}
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
q.Run()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
q.Send(getPacket([]byte("foobar")))
|
||||||
|
<-written
|
||||||
|
|
||||||
|
// now fill up the send queue
|
||||||
|
for i := 0; i < sendQueueCapacity+1; i++ {
|
||||||
|
Expect(q.WouldBlock()).To(BeFalse())
|
||||||
|
q.Send(getPacket([]byte("foobar")))
|
||||||
|
}
|
||||||
|
|
||||||
|
Expect(q.WouldBlock()).To(BeTrue())
|
||||||
|
Consistently(q.Available()).ShouldNot(Receive())
|
||||||
|
write <- struct{}{}
|
||||||
|
Eventually(q.Available()).Should(Receive())
|
||||||
|
|
||||||
|
// test shutdown
|
||||||
|
for i := 0; i < sendQueueCapacity; i++ {
|
||||||
|
write <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
q.Close()
|
||||||
|
Eventually(done).Should(BeClosed())
|
||||||
|
})
|
||||||
|
|
||||||
It("does not block pending send after the queue has stopped running", func() {
|
It("does not block pending send after the queue has stopped running", func() {
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue