diff --git a/pkg/atomicbitops/32b_32bit.go b/pkg/atomicbitops/32b_32bit.go index c44610dbf..d2ab60ec7 100644 --- a/pkg/atomicbitops/32b_32bit.go +++ b/pkg/atomicbitops/32b_32bit.go @@ -77,9 +77,6 @@ func (i *Int32) Store(v int32) { // // It may be helpful to document why a racy operation is permitted. // -// Don't add fields to this struct. It is important that it remain the same -// size as its builtin analogue. -// //go:nosplit func (i *Int32) RacyStore(v int32) { i.value = v @@ -124,6 +121,9 @@ func (i *Int32) ptr() *int32 { // Uint32 is an atomic uint32. // +// Don't add fields to this struct. It is important that it remain the same +// size as its builtin analogue. +// // See aligned_unsafe.go in this directory for justification. // // +stateify savable @@ -210,4 +210,80 @@ func (u *Uint32) ptr() *uint32 { return &u.value } +// Bool is an atomic Boolean. +// +// It is implemented by a Uint32, with value 0 indicating false, and 1 +// indicating true. +// +// +stateify savable +type Bool struct { + Uint32 +} + +// b32 returns a uint32 0 or 1 representing b. +func b32(b bool) uint32 { + if b { + return 1 + } + return 0 +} + +// FromBool returns a Bool initialized to value val. +// +//go:nosplit +func FromBool(val bool) Bool { + return Bool{ + Uint32: FromUint32(b32(val)), + } +} + +// Load is analogous to atomic.LoadBool, if such a thing existed. +// +//go:nosplit +func (b *Bool) Load() bool { + return b.Uint32.Load() != 0 +} + +// RacyLoad is analogous to reading an atomic value without using +// synchronization. +// +// It may be helpful to document why a racy operation is permitted. +// +//go:nosplit +func (b *Bool) RacyLoad() bool { + return b.Uint32.RacyLoad() != 0 +} + +// Store is analogous to atomic.StoreBool, if such a thing existed. +// +//go:nosplit +func (b *Bool) Store(val bool) { + b.Uint32.Store(b32(val)) +} + +// RacyStore is analogous to setting an atomic value without using +// synchronization. +// +// It may be helpful to document why a racy operation is permitted. +// +//go:nosplit +func (b *Bool) RacyStore(val bool) { + b.Uint32.RacyStore(b32(val)) +} + +// Swap is analogous to atomic.SwapBool, if such a thing existed. +// +//go:nosplit +func (b *Bool) Swap(val bool) bool { + return b.Uint32.Swap(b32(val)) != 0 +} + +// CompareAndSwap is analogous to atomic.CompareAndSwapBool, if such a thing +// existed. +// +//go:nosplit +func (b *Bool) CompareAndSwap(oldVal, newVal bool) bool { + return b.Uint32.CompareAndSwap(b32(oldVal), b32(newVal)) +} + // LINT.ThenChange(32b_64bit.go) diff --git a/pkg/atomicbitops/32b_64bit.go b/pkg/atomicbitops/32b_64bit.go index 18aa96303..af926eb42 100644 --- a/pkg/atomicbitops/32b_64bit.go +++ b/pkg/atomicbitops/32b_64bit.go @@ -77,9 +77,6 @@ func (i *Int32) Store(v int32) { // // It may be helpful to document why a racy operation is permitted. // -// Don't add fields to this struct. It is important that it remain the same -// size as its builtin analogue. -// //go:nosplit func (i *Int32) RacyStore(v int32) { i.value = v @@ -124,6 +121,9 @@ func (i *Int32) ptr() *int32 { // Uint32 is an atomic uint32. // +// Don't add fields to this struct. It is important that it remain the same +// size as its builtin analogue. +// // See aligned_unsafe.go in this directory for justification. // // +stateify savable @@ -210,4 +210,80 @@ func (u *Uint32) ptr() *uint32 { return &u.value } +// Bool is an atomic Boolean. +// +// It is implemented by a Uint32, with value 0 indicating false, and 1 +// indicating true. +// +// +stateify savable +type Bool struct { + Uint32 +} + +// b32 returns a uint32 0 or 1 representing b. +func b32(b bool) uint32 { + if b { + return 1 + } + return 0 +} + +// FromBool returns a Bool initialized to value val. +// +//go:nosplit +func FromBool(val bool) Bool { + return Bool{ + Uint32: FromUint32(b32(val)), + } +} + +// Load is analogous to atomic.LoadBool, if such a thing existed. +// +//go:nosplit +func (b *Bool) Load() bool { + return b.Uint32.Load() != 0 +} + +// RacyLoad is analogous to reading an atomic value without using +// synchronization. +// +// It may be helpful to document why a racy operation is permitted. +// +//go:nosplit +func (b *Bool) RacyLoad() bool { + return b.Uint32.RacyLoad() != 0 +} + +// Store is analogous to atomic.StoreBool, if such a thing existed. +// +//go:nosplit +func (b *Bool) Store(val bool) { + b.Uint32.Store(b32(val)) +} + +// RacyStore is analogous to setting an atomic value without using +// synchronization. +// +// It may be helpful to document why a racy operation is permitted. +// +//go:nosplit +func (b *Bool) RacyStore(val bool) { + b.Uint32.RacyStore(b32(val)) +} + +// Swap is analogous to atomic.SwapBool, if such a thing existed. +// +//go:nosplit +func (b *Bool) Swap(val bool) bool { + return b.Uint32.Swap(b32(val)) != 0 +} + +// CompareAndSwap is analogous to atomic.CompareAndSwapBool, if such a thing +// existed. +// +//go:nosplit +func (b *Bool) CompareAndSwap(oldVal, newVal bool) bool { + return b.Uint32.CompareAndSwap(b32(oldVal), b32(newVal)) +} + // LINT.ThenChange(32b_32bit.go) diff --git a/pkg/atomicbitops/BUILD b/pkg/atomicbitops/BUILD index b2fc7e15d..9da02eb5f 100644 --- a/pkg/atomicbitops/BUILD +++ b/pkg/atomicbitops/BUILD @@ -18,7 +18,6 @@ go_library( "atomicbitops_arm64.s", "atomicbitops_float64.go", "atomicbitops_noasm.go", - "bool.go", ], visibility = ["//:sandbox"], deps = [ diff --git a/pkg/atomicbitops/bool.go b/pkg/atomicbitops/bool.go deleted file mode 100644 index 60e646e8e..000000000 --- a/pkg/atomicbitops/bool.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2022 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package atomicbitops - -import "sync/atomic" - -// Bool is an atomic Boolean. -// -// It is implemented by a Uint32, with value 0 indicating false, and 1 -// indicating true. -// -// +stateify savable -type Bool struct { - Uint32 -} - -// FromBool returns an Bool initialized to value val. -// -//go:nosplit -func FromBool(val bool) Bool { - var u uint32 - if val { - u = 1 - } - return Bool{ - Uint32{ - value: u, - }, - } -} - -// Load is analogous to atomic.LoadBool, if such a thing existed. -// -//go:nosplit -func (b *Bool) Load() bool { - return atomic.LoadUint32(&b.value) == 1 -} - -// Store is analogous to atomic.StoreBool, if such a thing existed. -// -//go:nosplit -func (b *Bool) Store(val bool) { - var u uint32 - if val { - u = 1 - } - atomic.StoreUint32(&b.value, u) -} - -// Swap is analogous to atomic.SwapBool, if such a thing existed. -// -//go:nosplit -func (b *Bool) Swap(val bool) bool { - var u uint32 - if val { - u = 1 - } - return atomic.SwapUint32(&b.value, u) == 1 -} diff --git a/pkg/metric/profiling_metric.go b/pkg/metric/profiling_metric.go index 3ec11140d..ae5b0d5d0 100644 --- a/pkg/metric/profiling_metric.go +++ b/pkg/metric/profiling_metric.go @@ -116,7 +116,7 @@ func StartProfilingMetrics(profilingMetrics string, profilingRate time.Duration) return fmt.Errorf("a value for --profiling-metrics was not specified; also no conditionally compiled metrics found, consider compiling runsc with --go_tag=condmetric_profiling") } - if !profilingMetricsStarted.CompareAndSwap(0, 1) { + if !profilingMetricsStarted.CompareAndSwap(false, true) { return errors.New("profiling metrics have already been started") } s := snapshots{