// Copyright 2014 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 atomicimport ()// A Value provides an atomic load and store of a consistently typed value.// The zero value for a Value returns nil from [Value.Load].// Once [Value.Store] has been called, a Value must not be copied.//// A Value must not be copied after first use.typeValuestruct { v any}// efaceWords is interface{} internal representation.type efaceWords struct { typ unsafe.Pointer data unsafe.Pointer}// Load returns the value set by the most recent Store.// It returns nil if there has been no call to Store for this Value.func ( *Value) () ( any) { := (*efaceWords)(unsafe.Pointer()) := LoadPointer(&.typ)if == nil || == unsafe.Pointer(&firstStoreInProgress) {// First store not yet completed.returnnil } := LoadPointer(&.data) := (*efaceWords)(unsafe.Pointer(&)) .typ = .data = return}var firstStoreInProgress byte// Store sets the value of the [Value] v to val.// All calls to Store for a given Value must use values of the same concrete type.// Store of an inconsistent type panics, as does Store(nil).func ( *Value) ( any) {if == nil {panic("sync/atomic: store of nil value into Value") } := (*efaceWords)(unsafe.Pointer()) := (*efaceWords)(unsafe.Pointer(&))for { := LoadPointer(&.typ)if == nil {// Attempt to start first store. // Disable preemption so that other goroutines can use // active spin wait to wait for completion.runtime_procPin()if !CompareAndSwapPointer(&.typ, nil, unsafe.Pointer(&firstStoreInProgress)) {runtime_procUnpin()continue }// Complete first store.StorePointer(&.data, .data)StorePointer(&.typ, .typ)runtime_procUnpin()return }if == unsafe.Pointer(&firstStoreInProgress) {// First store in progress. Wait. // Since we disable preemption around the first store, // we can wait with active spinning.continue }// First store completed. Check type and overwrite data.if != .typ {panic("sync/atomic: store of inconsistently typed value into Value") }StorePointer(&.data, .data)return }}// Swap stores new into Value and returns the previous value. It returns nil if// the Value is empty.//// All calls to Swap for a given Value must use values of the same concrete// type. Swap of an inconsistent type panics, as does Swap(nil).func ( *Value) ( any) ( any) {if == nil {panic("sync/atomic: swap of nil value into Value") } := (*efaceWords)(unsafe.Pointer()) := (*efaceWords)(unsafe.Pointer(&))for { := LoadPointer(&.typ)if == nil {// Attempt to start first store. // Disable preemption so that other goroutines can use // active spin wait to wait for completion; and so that // GC does not see the fake type accidentally.runtime_procPin()if !CompareAndSwapPointer(&.typ, nil, unsafe.Pointer(&firstStoreInProgress)) {runtime_procUnpin()continue }// Complete first store.StorePointer(&.data, .data)StorePointer(&.typ, .typ)runtime_procUnpin()returnnil }if == unsafe.Pointer(&firstStoreInProgress) {// First store in progress. Wait. // Since we disable preemption around the first store, // we can wait with active spinning.continue }// First store completed. Check type and overwrite data.if != .typ {panic("sync/atomic: swap of inconsistently typed value into Value") } := (*efaceWords)(unsafe.Pointer(&)) .typ, .data = .typ, SwapPointer(&.data, .data)return }}// CompareAndSwap executes the compare-and-swap operation for the [Value].//// All calls to CompareAndSwap for a given Value must use values of the same// concrete type. CompareAndSwap of an inconsistent type panics, as does// CompareAndSwap(old, nil).func ( *Value) (, any) ( bool) {if == nil {panic("sync/atomic: compare and swap of nil value into Value") } := (*efaceWords)(unsafe.Pointer()) := (*efaceWords)(unsafe.Pointer(&)) := (*efaceWords)(unsafe.Pointer(&))if .typ != nil && .typ != .typ {panic("sync/atomic: compare and swap of inconsistently typed values") }for { := LoadPointer(&.typ)if == nil {if != nil {returnfalse }// Attempt to start first store. // Disable preemption so that other goroutines can use // active spin wait to wait for completion; and so that // GC does not see the fake type accidentally.runtime_procPin()if !CompareAndSwapPointer(&.typ, nil, unsafe.Pointer(&firstStoreInProgress)) {runtime_procUnpin()continue }// Complete first store.StorePointer(&.data, .data)StorePointer(&.typ, .typ)runtime_procUnpin()returntrue }if == unsafe.Pointer(&firstStoreInProgress) {// First store in progress. Wait. // Since we disable preemption around the first store, // we can wait with active spinning.continue }// First store completed. Check type and overwrite data.if != .typ {panic("sync/atomic: compare and swap of inconsistently typed value into Value") }// Compare old and current via runtime equality check. // This allows value types to be compared, something // not offered by the package functions. // CompareAndSwapPointer below only ensures vp.data // has not changed since LoadPointer. := LoadPointer(&.data)varany (*efaceWords)(unsafe.Pointer(&)).typ = (*efaceWords)(unsafe.Pointer(&)).data = if != {returnfalse }returnCompareAndSwapPointer(&.data, , .data) }}// Disable/enable preemption, implemented in runtime.func runtime_procPin() intfunc runtime_procUnpin()
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.