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 5package atomic 6 7import ( 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. 16type Value struct { 17 v interface{} 18} 19 20// ifaceWords is interface{} internal representation. 21type ifaceWords struct { 22 typ unsafe.Pointer 23 data unsafe.Pointer 24} 25 26// Load returns the value set by the most recent Store. 27// It returns nil if there has been no call to Store for this Value. 28func (v *Value) Load() (val interface{}) { 29 vp := (*ifaceWords)(unsafe.Pointer(v)) 30 typ := LoadPointer(&vp.typ) 31 if typ == nil || uintptr(typ) == ^uintptr(0) { 32 // First store not yet completed. 33 return nil 34 } 35 data := LoadPointer(&vp.data) 36 vlp := (*ifaceWords)(unsafe.Pointer(&val)) 37 vlp.typ = typ 38 vlp.data = data 39 return 40} 41 42// Store sets the value of the Value to x. 43// All calls to Store for a given Value must use values of the same concrete type. 44// Store of an inconsistent type panics, as does Store(nil). 45func (v *Value) Store(val interface{}) { 46 if val == nil { 47 panic("sync/atomic: store of nil value into Value") 48 } 49 vp := (*ifaceWords)(unsafe.Pointer(v)) 50 vlp := (*ifaceWords)(unsafe.Pointer(&val)) 51 for { 52 typ := LoadPointer(&vp.typ) 53 if typ == nil { 54 // Attempt to start first store. 55 // Disable preemption so that other goroutines can use 56 // active spin wait to wait for completion; and so that 57 // GC does not see the fake type accidentally. 58 runtime_procPin() 59 if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) { 60 runtime_procUnpin() 61 continue 62 } 63 // Complete first store. 64 StorePointer(&vp.data, vlp.data) 65 StorePointer(&vp.typ, vlp.typ) 66 runtime_procUnpin() 67 return 68 } 69 if uintptr(typ) == ^uintptr(0) { 70 // First store in progress. Wait. 71 // Since we disable preemption around the first store, 72 // we can wait with active spinning. 73 continue 74 } 75 // First store completed. Check type and overwrite data. 76 if typ != vlp.typ { 77 panic("sync/atomic: store of inconsistently typed value into Value") 78 } 79 StorePointer(&vp.data, vlp.data) 80 return 81 } 82} 83 84// Swap stores new into Value and returns the previous value. It returns nil if 85// the Value is empty. 86// 87// All calls to Swap for a given Value must use values of the same concrete 88// type. Swap of an inconsistent type panics, as does Swap(nil). 89func (v *Value) Swap(new interface{}) (old interface{}) { 90 if new == nil { 91 panic("sync/atomic: swap of nil value into Value") 92 } 93 vp := (*ifaceWords)(unsafe.Pointer(v)) 94 np := (*ifaceWords)(unsafe.Pointer(&new)) 95 for { 96 typ := LoadPointer(&vp.typ) 97 if typ == nil { 98 // Attempt to start first store. 99 // Disable preemption so that other goroutines can use 100 // active spin wait to wait for completion; and so that 101 // GC does not see the fake type accidentally. 102 runtime_procPin() 103 if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) { 104 runtime_procUnpin() 105 continue 106 } 107 // Complete first store. 108 StorePointer(&vp.data, np.data) 109 StorePointer(&vp.typ, np.typ) 110 runtime_procUnpin() 111 return nil 112 } 113 if uintptr(typ) == ^uintptr(0) { 114 // First store in progress. Wait. 115 // Since we disable preemption around the first store, 116 // we can wait with active spinning. 117 continue 118 } 119 // First store completed. Check type and overwrite data. 120 if typ != np.typ { 121 panic("sync/atomic: swap of inconsistently typed value into Value") 122 } 123 op := (*ifaceWords)(unsafe.Pointer(&old)) 124 op.typ, op.data = np.typ, SwapPointer(&vp.data, np.data) 125 return old 126 } 127} 128 129// CompareAndSwap executes the compare-and-swap operation for the Value. 130// 131// All calls to CompareAndSwap for a given Value must use values of the same 132// concrete type. CompareAndSwap of an inconsistent type panics, as does 133// CompareAndSwap(old, nil). 134func (v *Value) CompareAndSwap(old, new interface{}) (swapped bool) { 135 if new == nil { 136 panic("sync/atomic: compare and swap of nil value into Value") 137 } 138 vp := (*ifaceWords)(unsafe.Pointer(v)) 139 np := (*ifaceWords)(unsafe.Pointer(&new)) 140 op := (*ifaceWords)(unsafe.Pointer(&old)) 141 if op.typ != nil && np.typ != op.typ { 142 panic("sync/atomic: compare and swap of inconsistently typed values") 143 } 144 for { 145 typ := LoadPointer(&vp.typ) 146 if typ == nil { 147 if old != nil { 148 return false 149 } 150 // Attempt to start first store. 151 // Disable preemption so that other goroutines can use 152 // active spin wait to wait for completion; and so that 153 // GC does not see the fake type accidentally. 154 runtime_procPin() 155 if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) { 156 runtime_procUnpin() 157 continue 158 } 159 // Complete first store. 160 StorePointer(&vp.data, np.data) 161 StorePointer(&vp.typ, np.typ) 162 runtime_procUnpin() 163 return true 164 } 165 if uintptr(typ) == ^uintptr(0) { 166 // First store in progress. Wait. 167 // Since we disable preemption around the first store, 168 // we can wait with active spinning. 169 continue 170 } 171 // First store completed. Check type and overwrite data. 172 if typ != np.typ { 173 panic("sync/atomic: compare and swap of inconsistently typed value into Value") 174 } 175 // Compare old and current via runtime equality check. 176 // This allows value types to be compared, something 177 // not offered by the package functions. 178 // CompareAndSwapPointer below only ensures vp.data 179 // has not changed since LoadPointer. 180 data := LoadPointer(&vp.data) 181 var i interface{} 182 (*ifaceWords)(unsafe.Pointer(&i)).typ = typ 183 (*ifaceWords)(unsafe.Pointer(&i)).data = data 184 if i != old { 185 return false 186 } 187 return CompareAndSwapPointer(&vp.data, data, np.data) 188 } 189} 190 191// Disable/enable preemption, implemented in runtime. 192func runtime_procPin() 193func runtime_procUnpin() 194