-
Notifications
You must be signed in to change notification settings - Fork 1
/
MemoryLocation.scala
148 lines (110 loc) · 4.41 KB
/
MemoryLocation.scala
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright 2016-2024 Daniel Urban and contributors listed in NOTICE.txt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.tauri.choam
package internal
package mcas
import java.lang.ref.WeakReference
import scala.math.Ordering
import cats.kernel.Order
/**
* Extension point for MCAS: an MCAS operation
* can be executed on any number of objects
* which conform to this interface.
*
* However, the methods of this interface should
* only ever be called by the MCAS implementation.
* An MCAS operation is only safe and atomic if
* ALL reads and writes go through the MCAS
* implementation.
*
* These are the low-level, primitive operations
* required by the MCAS implementation. They are
* easily implemented by, e.g., having an
* `AtomicReference` or similar. (For implementations
* of this interface, see `SimpleMemoryLocation` or
* the various `Ref`s in the `choam-core` module.)
*
* Some method names are prefixed by `unsafe` because
* these are necessarily side-effecting methods,
* and they're also very low-level. Other methods are
* not "unsafe", since they're mostly harmless.
*
* Generally, this interface should not be used
* directly. Instead, use MCAS, or an even higher
* level abstraction.
*/
trait MemoryLocation[A] {
// contents:
def unsafeGetVolatile(): A
def unsafeGetPlain(): A
def unsafeSetVolatile(nv: A): Unit
def unsafeSetPlain(nv: A): Unit
def unsafeCasVolatile(ov: A, nv: A): Boolean
def unsafeCmpxchgVolatile(ov: A, nv: A): A
// version:
def unsafeGetVersionVolatile(): Long
def unsafeCmpxchgVersionVolatile(ov: Long, nv: Long): Long
// marker:
/** Used by EMCAS */ // TODO: this is JVM-only
def unsafeGetMarkerVolatile(): WeakReference[AnyRef]
/** Used by EMCAS */ // TODO: this is JVM-only
def unsafeCasMarkerVolatile(ov: WeakReference[AnyRef], nv: WeakReference[AnyRef]): Boolean
// ID:
def id: Long
// private utilities:
private[mcas] final def cast[B]: MemoryLocation[B] =
this.asInstanceOf[MemoryLocation[B]]
}
object MemoryLocation extends MemoryLocationInstances0 {
def unsafe[A](initial: A): MemoryLocation[A] = // TODO: remove this
unsafeUnpadded[A](initial)
def unsafeUnpadded[A](initial: A): MemoryLocation[A] =
this.unsafeUnpadded(initial, RefIdGen.global)
def unsafeUnpadded[A](initial: A, rig: RefIdGen): MemoryLocation[A] = {
unsafeUnpaddedWithId(initial)(rig.nextId())
}
def unsafePadded[A](initial: A): MemoryLocation[A] =
this.unsafePadded(initial, RefIdGen.global)
def unsafePadded[A](initial: A, rig: RefIdGen): MemoryLocation[A] = {
unsafePaddedWithId(initial)(rig.nextId())
}
private[mcas] def unsafeWithId[A](initial: A)(i0: Long): MemoryLocation[A] =
unsafeUnpaddedWithId(initial)(i0)
private[this] def unsafeUnpaddedWithId[A](initial: A)(i0: Long): MemoryLocation[A] = {
new SimpleMemoryLocation[A](initial)(i0)
}
private[this] def unsafePaddedWithId[A](initial: A)(id: Long): MemoryLocation[A] = {
new PaddedMemoryLocation[A](initial, id)
}
final def globalCompare(a: MemoryLocation[_], b: MemoryLocation[_]): Int = {
this.orderingInstance.compare(a.cast[Any], b.cast[Any])
}
}
private[mcas] sealed abstract class MemoryLocationInstances0 extends MemoryLocationInstances1 { self: MemoryLocation.type =>
private[mcas] val memoryLocationOrdering =
new MemoryLocationOrdering[Any]
implicit def orderingInstance[A]: Ordering[MemoryLocation[A]] =
memoryLocationOrdering.asInstanceOf[Ordering[MemoryLocation[A]]]
}
private[mcas] sealed abstract class MemoryLocationInstances1 { self: MemoryLocation.type =>
private[this] val _orderInstance = new Order[MemoryLocation[Any]] {
final override def compare(x: MemoryLocation[Any], y: MemoryLocation[Any]): Int =
self.globalCompare(x, y)
}
implicit def orderInstance[A]: Order[MemoryLocation[A]] =
_orderInstance.asInstanceOf[Order[MemoryLocation[A]]]
}