github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/sync/atomic/value.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package atomic 6 7 import ( 8 "unsafe" 9 ) 10 11 // A Value provides an atomic load and store of a consistently typed value. 12 // Values can be created as part of other data structures. 13 // The zero value for a Value returns nil from Load. 14 // Once Store has been called, a Value must not be copied. 15 // 16 // A Value must not be copied after first use. 17 type Value struct { 18 noCopy noCopy 19 20 v interface{} 21 } 22 23 // ifaceWords is interface{} internal representation. 24 type ifaceWords struct { 25 typ unsafe.Pointer 26 data unsafe.Pointer 27 } 28 29 // Load returns the value set by the most recent Store. 30 // It returns nil if there has been no call to Store for this Value. 31 func (v *Value) Load() (x interface{}) { 32 vp := (*ifaceWords)(unsafe.Pointer(v)) 33 typ := LoadPointer(&vp.typ) 34 if typ == nil || uintptr(typ) == ^uintptr(0) { 35 // First store not yet completed. 36 return nil 37 } 38 data := LoadPointer(&vp.data) 39 xp := (*ifaceWords)(unsafe.Pointer(&x)) 40 xp.typ = typ 41 xp.data = data 42 return 43 } 44 45 // Store sets the value of the Value to x. 46 // All calls to Store for a given Value must use values of the same concrete type. 47 // Store of an inconsistent type panics, as does Store(nil). 48 func (v *Value) Store(x interface{}) { 49 if x == nil { 50 panic("sync/atomic: store of nil value into Value") 51 } 52 vp := (*ifaceWords)(unsafe.Pointer(v)) 53 xp := (*ifaceWords)(unsafe.Pointer(&x)) 54 for { 55 typ := LoadPointer(&vp.typ) 56 if typ == nil { 57 // Attempt to start first store. 58 // Disable preemption so that other goroutines can use 59 // active spin wait to wait for completion; and so that 60 // GC does not see the fake type accidentally. 61 runtime_procPin() 62 if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) { 63 runtime_procUnpin() 64 continue 65 } 66 // Complete first store. 67 StorePointer(&vp.data, xp.data) 68 StorePointer(&vp.typ, xp.typ) 69 runtime_procUnpin() 70 return 71 } 72 if uintptr(typ) == ^uintptr(0) { 73 // First store in progress. Wait. 74 // Since we disable preemption around the first store, 75 // we can wait with active spinning. 76 continue 77 } 78 // First store completed. Check type and overwrite data. 79 if typ != xp.typ { 80 panic("sync/atomic: store of inconsistently typed value into Value") 81 } 82 StorePointer(&vp.data, xp.data) 83 return 84 } 85 } 86 87 // Disable/enable preemption, implemented in runtime. 88 func runtime_procPin() 89 func runtime_procUnpin() 90 91 // noCopy may be embedded into structs which must not be copied 92 // after the first use. 93 // 94 // See https://github.com/golang/go/issues/8005#issuecomment-190753527 95 // for details. 96 type noCopy struct{} 97 98 // Lock is a no-op used by -copylocks checker from `go vet`. 99 func (*noCopy) Lock() {}