// 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() {}