mirror of
https://github.com/tailscale/tailscale.git
synced 2025-01-10 18:13:41 +00:00
07aae18bca
Updates #14520 Updates #14517 (in that I pulled this out of there) Change-Id: Ibc28162816e083fcadf550586c06805c76e378fc Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
67 lines
1.2 KiB
Go
67 lines
1.2 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package goroutines
|
|
|
|
import (
|
|
"sync"
|
|
"sync/atomic"
|
|
|
|
"tailscale.com/util/set"
|
|
)
|
|
|
|
// Tracker tracks a set of goroutines.
|
|
type Tracker struct {
|
|
started atomic.Int64 // counter
|
|
running atomic.Int64 // gauge
|
|
|
|
mu sync.Mutex
|
|
onDone set.HandleSet[func()]
|
|
}
|
|
|
|
func (t *Tracker) Go(f func()) {
|
|
t.started.Add(1)
|
|
t.running.Add(1)
|
|
go t.goAndDecr(f)
|
|
}
|
|
|
|
func (t *Tracker) goAndDecr(f func()) {
|
|
defer t.decr()
|
|
f()
|
|
}
|
|
|
|
func (t *Tracker) decr() {
|
|
t.running.Add(-1)
|
|
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
for _, f := range t.onDone {
|
|
go f()
|
|
}
|
|
}
|
|
|
|
// AddDoneCallback adds a callback to be called in a new goroutine
|
|
// whenever a goroutine managed by t (excluding ones from this method)
|
|
// finishes. It returns a function to remove the callback.
|
|
func (t *Tracker) AddDoneCallback(f func()) (remove func()) {
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
if t.onDone == nil {
|
|
t.onDone = set.HandleSet[func()]{}
|
|
}
|
|
h := t.onDone.Add(f)
|
|
return func() {
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
delete(t.onDone, h)
|
|
}
|
|
}
|
|
|
|
func (t *Tracker) RunningGoroutines() int64 {
|
|
return t.running.Load()
|
|
}
|
|
|
|
func (t *Tracker) StartedGoroutines() int64 {
|
|
return t.started.Load()
|
|
}
|