github.com/golang-haiku/go-1.4.3@v0.0.0-20190609233734-1f5ae41cc308/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 type Value struct { 16 v interface{} 17 } 18 19 // ifaceWords is interface{} internal representation. 20 type ifaceWords struct { 21 typ unsafe.Pointer 22 data unsafe.Pointer 23 } 24 25 // Load returns the value set by the most recent Store. 26 // It returns nil if there has been no call to Store for this Value. 27 func (v *Value) Load() (x interface{}) { 28 vp := (*ifaceWords)(unsafe.Pointer(v)) 29 typ := LoadPointer(&vp.typ) 30 if typ == nil || uintptr(typ) == ^uintptr(0) { 31 // First store not yet completed. 32 return nil 33 } 34 data := LoadPointer(&vp.data) 35 xp := (*ifaceWords)(unsafe.Pointer(&x)) 36 xp.typ = typ 37 xp.data = data 38 return 39 } 40 41 // Store sets the value of the Value to x. 42 // All calls to Store for a given Value must use values of the same concrete type. 43 // Store of an inconsistent type panics, as does Store(nil). 44 func (v *Value) Store(x interface{}) { 45 if x == nil { 46 panic("sync/atomic: store of nil value into Value") 47 } 48 vp := (*ifaceWords)(unsafe.Pointer(v)) 49 xp := (*ifaceWords)(unsafe.Pointer(&x)) 50 for { 51 typ := LoadPointer(&vp.typ) 52 if typ == nil { 53 // Attempt to start first store. 54 // Disable preemption so that other goroutines can use 55 // active spin wait to wait for completion; and so that 56 // GC does not see the fake type accidentally. 57 runtime_procPin() 58 if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) { 59 runtime_procUnpin() 60 continue 61 } 62 // Complete first store. 63 StorePointer(&vp.data, xp.data) 64 StorePointer(&vp.typ, xp.typ) 65 runtime_procUnpin() 66 return 67 } 68 if uintptr(typ) == ^uintptr(0) { 69 // First store in progress. Wait. 70 // Since we disable preemption around the first store, 71 // we can wait with active spinning. 72 continue 73 } 74 // First store completed. Check type and overwrite data. 75 if typ != xp.typ { 76 panic("sync/atomic: store of inconsistently typed value into Value") 77 } 78 StorePointer(&vp.data, xp.data) 79 return 80 } 81 } 82 83 // Disable/enable preemption, implemented in runtime. 84 func runtime_procPin() 85 func runtime_procUnpin()