...

Source file src/sync/atomic/value.go

Documentation: sync/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() (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).
		45  func (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).
		89  func (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).
	 134  func (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.
	 192  func runtime_procPin()
	 193  func runtime_procUnpin()
	 194  

View as plain text