mirror of https://github.com/golang/go.git
runtime/internal/atomic: add atomic types for all functions
Change-Id: I74f365316484feb819c31c77fbffd78fadfe32a9 Reviewed-on: https://go-review.googlesource.com/c/go/+/356169 Trust: Michael Knyszek <mknyszek@google.com> Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
3ff39c5eda
commit
3ec8d4b5ed
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package atomic provides atomic operations, independent of sync/atomic,
|
||||
to the runtime.
|
||||
|
||||
On most platforms, the compiler is aware of the functions defined
|
||||
in this package, and they're replaced with platform-specific intrinsics.
|
||||
On other platforms, generic implementations are made available.
|
||||
|
||||
Unless otherwise noted, operations defined in this package are sequentially
|
||||
consistent across threads with respect to the values they manipulate. More
|
||||
specifically, operations that happen in a specific order on one thread,
|
||||
will always be observed to happen in exactly that order by another thread.
|
||||
*/
|
||||
package atomic
|
||||
|
|
@ -0,0 +1,395 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package atomic
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// Int32 is an atomically accessed int32 value.
|
||||
//
|
||||
// An Int32 must not be copied.
|
||||
type Int32 struct {
|
||||
noCopy noCopy
|
||||
value int32
|
||||
}
|
||||
|
||||
// Load accesses and returns the value atomically.
|
||||
func (i *Int32) Load() int32 {
|
||||
return Loadint32(&i.value)
|
||||
}
|
||||
|
||||
// Store updates the value atomically.
|
||||
func (i *Int32) Store(value int32) {
|
||||
Storeint32(&i.value, value)
|
||||
}
|
||||
|
||||
// CompareAndSwap atomically compares i's value with old,
|
||||
// and if they're equal, swaps i's value with new.
|
||||
//
|
||||
// Returns true if the operation succeeded.
|
||||
func (i *Int32) CompareAndSwap(old, new int32) bool {
|
||||
return Casint32(&i.value, old, new)
|
||||
}
|
||||
|
||||
// Swap replaces i's value with new, returning
|
||||
// i's value before the replacement.
|
||||
func (i *Int32) Swap(new int32) int32 {
|
||||
return Xchgint32(&i.value, new)
|
||||
}
|
||||
|
||||
// Add adds delta to i atomically, returning
|
||||
// the new updated value.
|
||||
//
|
||||
// This operation wraps around in the usual
|
||||
// two's-complement way.
|
||||
func (i *Int32) Add(delta int32) int32 {
|
||||
return Xaddint32(&i.value, delta)
|
||||
}
|
||||
|
||||
// Int64 is an atomically accessed int64 value.
|
||||
//
|
||||
// An Int64 must not be copied.
|
||||
type Int64 struct {
|
||||
noCopy noCopy
|
||||
value int64
|
||||
}
|
||||
|
||||
// Load accesses and returns the value atomically.
|
||||
func (i *Int64) Load() int64 {
|
||||
return Loadint64(&i.value)
|
||||
}
|
||||
|
||||
// Store updates the value atomically.
|
||||
func (i *Int64) Store(value int64) {
|
||||
Storeint64(&i.value, value)
|
||||
}
|
||||
|
||||
// CompareAndSwap atomically compares i's value with old,
|
||||
// and if they're equal, swaps i's value with new.
|
||||
//
|
||||
// Returns true if the operation succeeded.
|
||||
func (i *Int64) CompareAndSwap(old, new int64) bool {
|
||||
return Casint64(&i.value, old, new)
|
||||
}
|
||||
|
||||
// Swap replaces i's value with new, returning
|
||||
// i's value before the replacement.
|
||||
func (i *Int64) Swap(new int64) int64 {
|
||||
return Xchgint64(&i.value, new)
|
||||
}
|
||||
|
||||
// Add adds delta to i atomically, returning
|
||||
// the new updated value.
|
||||
//
|
||||
// This operation wraps around in the usual
|
||||
// two's-complement way.
|
||||
func (i *Int64) Add(delta int64) int64 {
|
||||
return Xaddint64(&i.value, delta)
|
||||
}
|
||||
|
||||
// Uint8 is an atomically accessed uint8 value.
|
||||
//
|
||||
// A Uint8 must not be copied.
|
||||
type Uint8 struct {
|
||||
noCopy noCopy
|
||||
value uint8
|
||||
}
|
||||
|
||||
// Load accesses and returns the value atomically.
|
||||
func (u *Uint8) Load() uint8 {
|
||||
return Load8(&u.value)
|
||||
}
|
||||
|
||||
// Store updates the value atomically.
|
||||
func (u *Uint8) Store(value uint8) {
|
||||
Store8(&u.value, value)
|
||||
}
|
||||
|
||||
// And takes value and performs a bit-wise
|
||||
// "and" operation with the value of u, storing
|
||||
// the result into u.
|
||||
//
|
||||
// The full process is performed atomically.
|
||||
func (u *Uint8) And(value uint8) {
|
||||
And8(&u.value, value)
|
||||
}
|
||||
|
||||
// Or takes value and performs a bit-wise
|
||||
// "or" operation with the value of u, storing
|
||||
// the result into u.
|
||||
//
|
||||
// The full process is performed atomically.
|
||||
func (u *Uint8) Or(value uint8) {
|
||||
Or8(&u.value, value)
|
||||
}
|
||||
|
||||
// Uint32 is an atomically accessed uint32 value.
|
||||
//
|
||||
// A Uint32 must not be copied.
|
||||
type Uint32 struct {
|
||||
noCopy noCopy
|
||||
value uint32
|
||||
}
|
||||
|
||||
// Load accesses and returns the value atomically.
|
||||
func (u *Uint32) Load() uint32 {
|
||||
return Load(&u.value)
|
||||
}
|
||||
|
||||
// LoadAcquire is a partially unsynchronized version
|
||||
// of Load that relaxes ordering constraints. Other threads
|
||||
// may observe operations that precede this operation to
|
||||
// occur after it, but no operation that occurs after it
|
||||
// on this thread can be observed to occur before it.
|
||||
//
|
||||
// WARNING: Use sparingly and with great care.
|
||||
func (u *Uint32) LoadAcquire() uint32 {
|
||||
return LoadAcq(&u.value)
|
||||
}
|
||||
|
||||
// Store updates the value atomically.
|
||||
func (u *Uint32) Store(value uint32) {
|
||||
Store(&u.value, value)
|
||||
}
|
||||
|
||||
// StoreRelease is a partially unsynchronized version
|
||||
// of Store that relaxes ordering constraints. Other threads
|
||||
// may observe operations that occur after this operation to
|
||||
// precede it, but no operation that precedes it
|
||||
// on this thread can be observed to occur after it.
|
||||
//
|
||||
// WARNING: Use sparingly and with great care.
|
||||
func (u *Uint32) StoreRelease(value uint32) {
|
||||
StoreRel(&u.value, value)
|
||||
}
|
||||
|
||||
// CompareAndSwap atomically compares u's value with old,
|
||||
// and if they're equal, swaps u's value with new.
|
||||
//
|
||||
// Returns true if the operation succeeded.
|
||||
func (u *Uint32) CompareAndSwap(old, new uint32) bool {
|
||||
return Cas(&u.value, old, new)
|
||||
}
|
||||
|
||||
// CompareAndSwapRelease is a partially unsynchronized version
|
||||
// of Cas that relaxes ordering constraints. Other threads
|
||||
// may observe operations that occur after this operation to
|
||||
// precede it, but no operation that precedes it
|
||||
// on this thread can be observed to occur after it.
|
||||
//
|
||||
// Returns true if the operation succeeded.
|
||||
//
|
||||
// WARNING: Use sparingly and with great care.
|
||||
func (u *Uint32) CompareAndSwapRelease(old, new uint32) bool {
|
||||
return CasRel(&u.value, old, new)
|
||||
}
|
||||
|
||||
// Swap replaces u's value with new, returning
|
||||
// u's value before the replacement.
|
||||
func (u *Uint32) Swap(value uint32) uint32 {
|
||||
return Xchg(&u.value, value)
|
||||
}
|
||||
|
||||
// And takes value and performs a bit-wise
|
||||
// "and" operation with the value of u, storing
|
||||
// the result into u.
|
||||
//
|
||||
// The full process is performed atomically.
|
||||
func (u *Uint32) And(value uint32) {
|
||||
And(&u.value, value)
|
||||
}
|
||||
|
||||
// Or takes value and performs a bit-wise
|
||||
// "or" operation with the value of u, storing
|
||||
// the result into u.
|
||||
//
|
||||
// The full process is performed atomically.
|
||||
func (u *Uint32) Or(value uint32) {
|
||||
Or(&u.value, value)
|
||||
}
|
||||
|
||||
// Add adds delta to u atomically, returning
|
||||
// the new updated value.
|
||||
//
|
||||
// This operation wraps around in the usual
|
||||
// two's-complement way.
|
||||
func (u *Uint32) Add(delta int32) uint32 {
|
||||
return Xadd(&u.value, delta)
|
||||
}
|
||||
|
||||
// Uint64 is an atomically accessed uint64 value.
|
||||
//
|
||||
// A Uint64 must not be copied.
|
||||
type Uint64 struct {
|
||||
noCopy noCopy
|
||||
value uint64
|
||||
}
|
||||
|
||||
// Load accesses and returns the value atomically.
|
||||
func (u *Uint64) Load() uint64 {
|
||||
return Load64(&u.value)
|
||||
}
|
||||
|
||||
// Store updates the value atomically.
|
||||
func (u *Uint64) Store(value uint64) {
|
||||
Store64(&u.value, value)
|
||||
}
|
||||
|
||||
// CompareAndSwap atomically compares u's value with old,
|
||||
// and if they're equal, swaps u's value with new.
|
||||
//
|
||||
// Returns true if the operation succeeded.
|
||||
func (u *Uint64) CompareAndSwap(old, new uint64) bool {
|
||||
return Cas64(&u.value, old, new)
|
||||
}
|
||||
|
||||
// Swap replaces u's value with new, returning
|
||||
// u's value before the replacement.
|
||||
func (u *Uint64) Swap(value uint64) uint64 {
|
||||
return Xchg64(&u.value, value)
|
||||
}
|
||||
|
||||
// Add adds delta to u atomically, returning
|
||||
// the new updated value.
|
||||
//
|
||||
// This operation wraps around in the usual
|
||||
// two's-complement way.
|
||||
func (u *Uint64) Add(delta int64) uint64 {
|
||||
return Xadd64(&u.value, delta)
|
||||
}
|
||||
|
||||
// Uintptr is an atomically accessed uintptr value.
|
||||
//
|
||||
// A Uintptr must not be copied.
|
||||
type Uintptr struct {
|
||||
noCopy noCopy
|
||||
value uintptr
|
||||
}
|
||||
|
||||
// Load accesses and returns the value atomically.
|
||||
func (u *Uintptr) Load() uintptr {
|
||||
return Loaduintptr(&u.value)
|
||||
}
|
||||
|
||||
// LoadAcquire is a partially unsynchronized version
|
||||
// of Load that relaxes ordering constraints. Other threads
|
||||
// may observe operations that precede this operation to
|
||||
// occur after it, but no operation that occurs after it
|
||||
// on this thread can be observed to occur before it.
|
||||
//
|
||||
// WARNING: Use sparingly and with great care.
|
||||
func (u *Uintptr) LoadAcquire() uintptr {
|
||||
return LoadAcquintptr(&u.value)
|
||||
}
|
||||
|
||||
// Store updates the value atomically.
|
||||
func (u *Uintptr) Store(value uintptr) {
|
||||
Storeuintptr(&u.value, value)
|
||||
}
|
||||
|
||||
// StoreRelease is a partially unsynchronized version
|
||||
// of Store that relaxes ordering constraints. Other threads
|
||||
// may observe operations that occur after this operation to
|
||||
// precede it, but no operation that precedes it
|
||||
// on this thread can be observed to occur after it.
|
||||
//
|
||||
// WARNING: Use sparingly and with great care.
|
||||
func (u *Uintptr) StoreRelease(value uintptr) {
|
||||
StoreReluintptr(&u.value, value)
|
||||
}
|
||||
|
||||
// CompareAndSwap atomically compares u's value with old,
|
||||
// and if they're equal, swaps u's value with new.
|
||||
//
|
||||
// Returns true if the operation succeeded.
|
||||
func (u *Uintptr) CompareAndSwap(old, new uintptr) bool {
|
||||
return Casuintptr(&u.value, old, new)
|
||||
}
|
||||
|
||||
// Swap replaces u's value with new, returning
|
||||
// u's value before the replacement.
|
||||
func (u *Uintptr) Swap(value uintptr) uintptr {
|
||||
return Xchguintptr(&u.value, value)
|
||||
}
|
||||
|
||||
// Add adds delta to u atomically, returning
|
||||
// the new updated value.
|
||||
//
|
||||
// This operation wraps around in the usual
|
||||
// two's-complement way.
|
||||
func (u *Uintptr) Add(delta uintptr) uintptr {
|
||||
return Xadduintptr(&u.value, delta)
|
||||
}
|
||||
|
||||
// Float64 is an atomically accessed float64 value.
|
||||
//
|
||||
// A Float64 must not be copied.
|
||||
type Float64 struct {
|
||||
u Uint64
|
||||
}
|
||||
|
||||
// Load accesses and returns the value atomically.
|
||||
func (f *Float64) Load() float64 {
|
||||
r := f.u.Load()
|
||||
return *(*float64)(unsafe.Pointer(&r))
|
||||
}
|
||||
|
||||
// Store updates the value atomically.
|
||||
func (f *Float64) Store(value float64) {
|
||||
f.u.Store(*(*uint64)(unsafe.Pointer(&value)))
|
||||
}
|
||||
|
||||
// UnsafePointer is an atomically accessed unsafe.Pointer value.
|
||||
//
|
||||
// Note that because of the atomicity guarantees, stores to values
|
||||
// of this type never trigger a write barrier, and the relevant
|
||||
// methods are suffixed with "NoWB" to indicate that explicitly.
|
||||
// As a result, this type should be used carefully, and sparingly,
|
||||
// mostly with values that do not live in the Go heap anyway.
|
||||
//
|
||||
// An UnsafePointer must not be copied.
|
||||
type UnsafePointer struct {
|
||||
noCopy noCopy
|
||||
value unsafe.Pointer
|
||||
}
|
||||
|
||||
// Load accesses and returns the value atomically.
|
||||
func (u *UnsafePointer) Load() unsafe.Pointer {
|
||||
return Loadp(unsafe.Pointer(&u.value))
|
||||
}
|
||||
|
||||
// StoreNoWB updates the value atomically.
|
||||
//
|
||||
// WARNING: As the name implies this operation does *not*
|
||||
// perform a write barrier on value, and so this operation may
|
||||
// hide pointers from the GC. Use with care and sparingly.
|
||||
// It is safe to use with values not found in the Go heap.
|
||||
func (u *UnsafePointer) StoreNoWB(value unsafe.Pointer) {
|
||||
StorepNoWB(unsafe.Pointer(&u.value), value)
|
||||
}
|
||||
|
||||
// CompareAndSwapNoWB atomically (with respect to other methods)
|
||||
// compares u's value with old, and if they're equal,
|
||||
// swaps u's value with new.
|
||||
//
|
||||
// Returns true if the operation succeeded.
|
||||
//
|
||||
// WARNING: As the name implies this operation does *not*
|
||||
// perform a write barrier on value, and so this operation may
|
||||
// hide pointers from the GC. Use with care and sparingly.
|
||||
// It is safe to use with values not found in the Go heap.
|
||||
func (u *UnsafePointer) CompareAndSwapNoWB(old, new unsafe.Pointer) bool {
|
||||
return Casp1(&u.value, old, new)
|
||||
}
|
||||
|
||||
// noCopy may be embedded into structs which must not be copied
|
||||
// after the first use.
|
||||
//
|
||||
// See https://golang.org/issues/8005#issuecomment-190753527
|
||||
// for details.
|
||||
type noCopy struct{}
|
||||
|
||||
// Lock is a no-op used by -copylocks checker from `go vet`.
|
||||
func (*noCopy) Lock() {}
|
||||
func (*noCopy) Unlock() {}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build amd64 || arm64 || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x || wasm
|
||||
// +build amd64 arm64 mips64 mips64le ppc64 ppc64le riscv64 s390x wasm
|
||||
|
||||
package atomic
|
||||
|
||||
// LoadAcquire is a partially unsynchronized version
|
||||
// of Load that relaxes ordering constraints. Other threads
|
||||
// may observe operations that precede this operation to
|
||||
// occur after it, but no operation that occurs after it
|
||||
// on this thread can be observed to occur before it.
|
||||
//
|
||||
// WARNING: Use sparingly and with great care.
|
||||
func (u *Uint64) LoadAcquire() uint64 {
|
||||
return LoadAcq64(&u.value)
|
||||
}
|
||||
|
||||
// StoreRelease is a partially unsynchronized version
|
||||
// of Store that relaxes ordering constraints. Other threads
|
||||
// may observe operations that occur after this operation to
|
||||
// precede it, but no operation that precedes it
|
||||
// on this thread can be observed to occur after it.
|
||||
//
|
||||
// WARNING: Use sparingly and with great care.
|
||||
func (u *Uint64) StoreRelease(value uint64) {
|
||||
StoreRel64(&u.value, value)
|
||||
}
|
||||
Loading…
Reference in New Issue