-
Notifications
You must be signed in to change notification settings - Fork 5
/
amr.go
74 lines (62 loc) · 1.66 KB
/
amr.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package dll
import (
"sync/atomic"
"unsafe"
)
type (
atomicMarkableReference struct {
pair *pair
}
pair struct {
reference *Element
mark bool
}
)
func newAtomicMarkableReference(initialRef *Element, initialMark bool) *atomicMarkableReference {
return &atomicMarkableReference{
&pair{
reference: initialRef,
mark: initialMark,
},
}
}
func (amr *atomicMarkableReference) getPair() *pair {
return (*pair)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&amr.pair))))
}
func (amr *atomicMarkableReference) getReference() *Element {
p := amr.getPair()
return p.reference
}
func (amr *atomicMarkableReference) isMarked() bool {
p := amr.getPair()
return p.mark
}
func (amr *atomicMarkableReference) get() (bool, *Element) {
p := amr.getPair()
return p.mark, p.reference
}
func (amr *atomicMarkableReference) compareAndSet(expectedReference *Element,
newReference *Element,
expectedMark bool,
newMark bool) bool {
current := amr.getPair()
val := &pair{newReference, newMark}
return expectedReference == current.reference &&
expectedMark == current.mark &&
((newReference == current.reference &&
newMark == current.mark) ||
amr.casPair(current, val))
}
func (amr *atomicMarkableReference) tryMark(expectedReference *Element, newMark bool) bool {
current := amr.getPair()
val := &pair{expectedReference, newMark}
return expectedReference == current.reference &&
(newMark == current.mark ||
amr.casPair(current, val))
}
func (amr *atomicMarkableReference) casPair(cmp *pair, val *pair) bool {
return atomic.CompareAndSwapPointer(
(*unsafe.Pointer)(unsafe.Pointer(&amr.pair)),
unsafe.Pointer(cmp),
unsafe.Pointer(val))
}