The data race in the UDP Frontend seems to be because any combination of these:
we call (*sync.WaitGroup).Add from a different goroutine than the one calling (*sync.WaitGroup).Wait, e.g., here and here
we call (*sync.WaitGroup).Addafter a call to (*sync.WaitGroup).Wait has started, i.e., here. This seems more likely to me. We set the read deadline on the socket and call Wait, but serve() still has some packet data and launches a goroutine to process that.
I also noticed that (t *Frontend).Stop() is not thread-safe by my definition, because it could close t.closing multiple times, which would panic.
In general, that needs a small rework with
A mutex to govern write-access to closing
A signalling/synchronization mechanism that ensures we will never call (*sync.WaitGroup).Add after we set the socket read deadline (or some other useful point)
Probably moving this outside of the goroutine, because it really is a bit weird to have it in there.
The data race in the UDP Frontend seems to be because any combination of these:
(*sync.WaitGroup).Add
from a different goroutine than the one calling(*sync.WaitGroup).Wait
, e.g., here and here(*sync.WaitGroup).Add
after a call to(*sync.WaitGroup).Wait
has started, i.e., here. This seems more likely to me. We set the read deadline on the socket and callWait
, butserve()
still has some packet data and launches a goroutine to process that.I also noticed that
(t *Frontend).Stop()
is not thread-safe by my definition, because it could closet.closing
multiple times, which would panic.In general, that needs a small rework with
closing
(*sync.WaitGroup).Add
after we set the socket read deadline (or some other useful point)EDIT relevant links: https://pkg.go.dev/sync#WaitGroup.Add https://github.com/golang/go/issues/23842