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 // 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 	v interface{}
     18 }
     19 
     20 // ifaceWords is interface{} internal representation.
     21 type 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.
     28 func (v *Value) Load() (x 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 	xp := (*ifaceWords)(unsafe.Pointer(&x))
     37 	xp.typ = typ
     38 	xp.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).
     45 func (v *Value) Store(x interface{}) {
     46 	if x == nil {
     47 		panic("sync/atomic: store of nil value into Value")
     48 	}
     49 	vp := (*ifaceWords)(unsafe.Pointer(v))
     50 	xp := (*ifaceWords)(unsafe.Pointer(&x))
     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, xp.data)
     65 			StorePointer(&vp.typ, xp.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 != xp.typ {
     77 			panic("sync/atomic: store of inconsistently typed value into Value")
     78 		}
     79 		StorePointer(&vp.data, xp.data)
     80 		return
     81 	}
     82 }
     83 
     84 // Disable/enable preemption, implemented in runtime.
     85 func runtime_procPin()
     86 func runtime_procUnpin()
     87