wgengine,util/execqueue: wait for in-flight linkChange before closing
ExecQueue.Shutdown does not wait for a function that is already executing, so Close could tear down magicConn, dns, wgdev, and tundev while a queued linkChange was still using them, panicking during shutdown. Add ExecQueue.ShutdownAndWait, which discards queued functions that have not started and waits for the in-flight one, and use it in Close with a bounded context before tearing anything down. The eventbus client is closed first and is the queue's only producer, so no new work can arrive after the drain. Updates #17641 Change-Id: I0350bcb59c1ee4b0dcac88cf66b93828466c8c98 Signed-off-by: Adel-Ayoub <adelayoub.maaziz@gmail.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
3d52c3f03e
commit
2051c5f358
@@ -1222,9 +1222,14 @@ func (e *userspaceEngine) RequestStatus() {
|
||||
|
||||
func (e *userspaceEngine) Close() {
|
||||
e.eventClient.Close()
|
||||
// TODO(cmol): Should we wait for it too?
|
||||
// Same question raised in appconnector.go.
|
||||
e.linkChangeQueue.Shutdown()
|
||||
// eventClient.Close waited for the ChangeDelta subscriber, the sole
|
||||
// producer for linkChangeQueue, to return, so no new work can be
|
||||
// queued. Discard queued linkChanges and wait for an in-flight one
|
||||
// to finish before closing the subsystems it uses.
|
||||
// See tailscale/tailscale#17641.
|
||||
drainCtx, drainCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer drainCancel()
|
||||
e.linkChangeQueue.ShutdownAndWait(drainCtx)
|
||||
e.mu.Lock()
|
||||
if e.closing {
|
||||
e.mu.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user