Home | History | Annotate | Download | only in atomic
      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() {}
    100