| // 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 atomic |
| |
| import ( |
| "unsafe" |
| ) |
| |
| // A Value provides an atomic load and store of a consistently typed value. |
| // Values can be created as part of other data structures. |
| // The zero value for a Value returns nil from Load. |
| // Once Store has been called, a Value must not be copied. |
| // |
| // A Value must not be copied after first use. |
| type Value struct { |
| noCopy noCopy |
| |
| v interface{} |
| } |
| |
| // ifaceWords is interface{} internal representation. |
| type ifaceWords 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 (v *Value) Load() (x interface{}) { |
| vp := (*ifaceWords)(unsafe.Pointer(v)) |
| typ := LoadPointer(&vp.typ) |
| if typ == nil || uintptr(typ) == ^uintptr(0) { |
| // First store not yet completed. |
| return nil |
| } |
| data := LoadPointer(&vp.data) |
| xp := (*ifaceWords)(unsafe.Pointer(&x)) |
| xp.typ = typ |
| xp.data = data |
| return |
| } |
| |
| // Store sets the value of the Value to x. |
| // 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 (v *Value) Store(x interface{}) { |
| if x == nil { |
| panic("sync/atomic: store of nil value into Value") |
| } |
| vp := (*ifaceWords)(unsafe.Pointer(v)) |
| xp := (*ifaceWords)(unsafe.Pointer(&x)) |
| for { |
| typ := LoadPointer(&vp.typ) |
| if typ == 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(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) { |
| runtime_procUnpin() |
| continue |
| } |
| // Complete first store. |
| StorePointer(&vp.data, xp.data) |
| StorePointer(&vp.typ, xp.typ) |
| runtime_procUnpin() |
| return |
| } |
| if uintptr(typ) == ^uintptr(0) { |
| // 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 != xp.typ { |
| panic("sync/atomic: store of inconsistently typed value into Value") |
| } |
| StorePointer(&vp.data, xp.data) |
| return |
| } |
| } |
| |
| // Disable/enable preemption, implemented in runtime. |
| func runtime_procPin() |
| func runtime_procUnpin() |
| |
| // noCopy may be embedded into structs which must not be copied |
| // after the first use. |
| // |
| // See https://github.com/golang/go/issues/8005#issuecomment-190753527 |
| // for details. |
| type noCopy struct{} |
| |
| // Lock is a no-op used by -copylocks checker from `go vet`. |
| func (*noCopy) Lock() {} |