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