Make atomicbitops.Bool savable.

Earlier the atomicbitops_state_autogen.go was not being built because it had
an impossible build condition: `(amd64 || arm64) && !amd64 && !arm64`.

This is a known deficiency in go_stateify tool. This was solved via having
two identical files like 32b_32bit.go and 32b_64bit.go. Just piggyback this.

This changes also enhances `atomicbitops.Bool` in the following ways:
- Added RacyLoad(), RacyStore() and CompareAndSwap() for Bool to bring it up to
  speed with the other types.
- Delegated the actual atomic operations work to the underlying Uint32.
- Cleaned up code with b32(); similar to what sync/atomic.Bool does.

PiperOrigin-RevId: 597607982
This commit is contained in:
Ayush Ranjan
2024-01-11 11:24:32 -08:00
committed by gVisor bot
parent 8053cd8f0b
commit d4861911c2
5 changed files with 159 additions and 79 deletions
+79 -3
View File
@@ -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)
+79 -3
View File
@@ -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)
-1
View File
@@ -18,7 +18,6 @@ go_library(
"atomicbitops_arm64.s",
"atomicbitops_float64.go",
"atomicbitops_noasm.go",
"bool.go",
],
visibility = ["//:sandbox"],
deps = [
-71
View File
@@ -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
}
+1 -1
View File
@@ -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{