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
5package atomic
6
7import (
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.
16type Value struct {
17	v interface{}
18}
19
20// ifaceWords is interface{} internal representation.
21type 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.
28func (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).
45func (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.
85func runtime_procPin()
86func runtime_procUnpin()
87