From 7cbcc10eb10cdea7cc42511f7d5c4f584c8ead7a Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Fri, 29 Aug 2025 10:33:14 -0700 Subject: [PATCH] syncs: add Semaphore.Len (#16981) The Len reports the number of acquired tokens for metrics. Updates tailscale/corp#31252 Signed-off-by: Joe Tsai --- syncs/syncs.go | 7 +++++++ syncs/syncs_test.go | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/syncs/syncs.go b/syncs/syncs.go index e85b474c9..3b37bca08 100644 --- a/syncs/syncs.go +++ b/syncs/syncs.go @@ -201,6 +201,13 @@ func NewSemaphore(n int) Semaphore { return Semaphore{c: make(chan struct{}, n)} } +// Len reports the number of in-flight acquisitions. +// It is incremented whenever the semaphore is acquired. +// It is decremented whenever the semaphore is released. +func (s Semaphore) Len() int { + return len(s.c) +} + // Acquire blocks until a resource is acquired. func (s Semaphore) Acquire() { s.c <- struct{}{} diff --git a/syncs/syncs_test.go b/syncs/syncs_test.go index d99c3d1a9..a546b8d0a 100644 --- a/syncs/syncs_test.go +++ b/syncs/syncs_test.go @@ -162,10 +162,20 @@ func TestClosedChan(t *testing.T) { func TestSemaphore(t *testing.T) { s := NewSemaphore(2) + assertLen := func(want int) { + t.Helper() + if got := s.Len(); got != want { + t.Fatalf("Len = %d, want %d", got, want) + } + } + + assertLen(0) s.Acquire() + assertLen(1) if !s.TryAcquire() { t.Fatal("want true") } + assertLen(2) if s.TryAcquire() { t.Fatal("want false") } @@ -175,11 +185,15 @@ func TestSemaphore(t *testing.T) { t.Fatal("want false") } s.Release() + assertLen(1) if !s.AcquireContext(context.Background()) { t.Fatal("want true") } + assertLen(2) s.Release() + assertLen(1) s.Release() + assertLen(0) } func TestMap(t *testing.T) {