mirror of
https://github.com/tailscale/tailscale.git
synced 2025-06-12 18:58:36 +00:00

Also add additional tests to verify that the unchecked implementation is allocation-free. Updates #12614 Signed-off-by: Nick Khyl <nickk@tailscale.com>
54 lines
2.1 KiB
Go
54 lines
2.1 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
// This file exports default, unoptimized implementation of the [State] that includes runtime checks.
|
|
// It is used unless the build tag ts_omit_ctxlock_checks is set.
|
|
|
|
//go:build !ts_omit_ctxlock_checks
|
|
|
|
package ctxlock
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
)
|
|
|
|
// Checked indicates whether runtime checks are enabled for this package.
|
|
const Checked = true
|
|
|
|
// State carries the lock state of zero or more mutexes and an optional [context.Context].
|
|
// Its zero value is valid and represents an unlocked state and an empty context.
|
|
//
|
|
// Calling [Lock] returns a derived State with the specified mutex locked. The State is considered
|
|
// the owner of the lock if it wasn't already acquired by a parent State. Calling [State.Unlock]
|
|
// releases the lock owned by the state. It is a runtime error to call Unlock more than once,
|
|
// to use the State after it has been unlocked, or to unlock a parent State before its child.
|
|
type State struct {
|
|
*checked
|
|
}
|
|
|
|
// None returns a [State] that carries no lock state and an empty [context.Context].
|
|
func None() State {
|
|
return State{}
|
|
}
|
|
|
|
// FromContext returns a [State] that carries the same lock state as the provided [context.Context].
|
|
//
|
|
// It is typically used by methods that already accept a [context.Context] for cancellation or deadline
|
|
// management, and would like to use it for locking as well.
|
|
func FromContext(ctx context.Context) State {
|
|
return State{fromContextChecked(ctx)}
|
|
}
|
|
|
|
// Lock acquires the specified mutex and becomes its owner, unless it is already held by a parent.
|
|
// The parent can be either a [State] or a [context.Context]. A zero [State] is a valid parent.
|
|
// It returns a new [State] that augments the parent with the additional lock state.
|
|
//
|
|
// It is a runtime error to pass a nil mutex or to unlock the parent state before the returned one.
|
|
func Lock[T context.Context](parent T, mu *sync.Mutex) State {
|
|
if parent, ok := any(parent).(State); ok {
|
|
return State{lockChecked(parent.checked, mu)}
|
|
}
|
|
return State{lockChecked(fromContextChecked(parent), mu)}
|
|
}
|