diff options
| author | Joe Tsai <joetsai@digital-static.net> | 2024-07-13 14:34:17 -0700 |
|---|---|---|
| committer | Joe Tsai <joetsai@digital-static.net> | 2024-07-13 14:40:04 -0700 |
| commit | 205720530036c12c913e4b3ddf8342879d32faf5 (patch) | |
| tree | 62f3427e26d1bbe2caa887a4b72acda8d9556c0b | |
| parent | c8f258a90427a80db831c3791742488fc8f9032a (diff) | |
| download | tailscale-dsnet/syncs-lock.tar.xz tailscale-dsnet/syncs-lock.zip | |
syncs: add LockFunc, LockValue, LockValues, and Mutexdsnet/syncs-lock
The first 3 functions are helpers for running functions
under the protection of a lock.
The Mutex type is a wrapper over sync.Mutex with a Do method
that runs a function under the protection of a lock.
Updates #11038
Updates #cleanup
Signed-off-by: Joe Tsai <joetsai@digital-static.net>
| -rw-r--r-- | syncs/lock_example_test.go | 37 | ||||
| -rw-r--r-- | syncs/syncs.go | 36 |
2 files changed, 73 insertions, 0 deletions
diff --git a/syncs/lock_example_test.go b/syncs/lock_example_test.go new file mode 100644 index 000000000..13184c7c0 --- /dev/null +++ b/syncs/lock_example_test.go @@ -0,0 +1,37 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +package syncs_test + +import ( + "encoding/hex" + "log" + "sync" + + "tailscale.com/syncs" +) + +func ExampleLockFunc() { + var nodesMu sync.Mutex + var nodes []string + syncs.LockFunc(&nodesMu, func() { nodes = append(nodes, "node123") }) +} + +func ExampleLockValue() { + var nodesMu sync.Mutex + var nodes []string + n := syncs.LockValue(&nodesMu, func() int { return len(nodes) }) + log.Printf("there are %d nodes", n) +} + +func ExampleLockValues() { + var bufferMu sync.Mutex + var buffer string + b, err := syncs.LockValues(&bufferMu, func() ([]byte, error) { + return hex.DecodeString(buffer) + }) + if err != nil { + log.Fatalf("Decode error: %v", err) + } + log.Printf("decoded %d bytes", len(b)) +} diff --git a/syncs/syncs.go b/syncs/syncs.go index c3f729a90..a32947c97 100644 --- a/syncs/syncs.go +++ b/syncs/syncs.go @@ -304,3 +304,39 @@ func (wg *WaitGroup) Go(f func()) { f() }() } + +// TODO(https://go.dev/issue/63941): LockFunc, LockValue, and LockValues +// are helper functions proposed upstream. Their naming and signature +// are based on the existing OnceFunc, OnceValue, and OnceValues +// helper functions already in the [sync] package. + +// LockFunc runs f while holding the lock. +func LockFunc(lock sync.Locker, f func()) { + lock.Lock() + defer lock.Unlock() + f() +} + +// LockValue runs f while holding the lock and returns the argument. +func LockValue[T any](lock sync.Locker, f func() T) T { + lock.Lock() + defer lock.Unlock() + return f() +} + +// LockValues runs f while holding the lock and returns the arguments. +func LockValues[T1, T2 any](lock sync.Locker, f func() (T1, T2)) (T1, T2) { + lock.Lock() + defer lock.Unlock() + return f() +} + +// Mutex is identical to [sync.Mutex], but with additional methods. +type Mutex struct{ sync.Mutex } + +// Do runs f while holding the lock. +func (m *Mutex) Do(f func()) { + m.Lock() + defer m.Unlock() + f() +} |
