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