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 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()
     86