@@ -8,18 +8,6 @@ import kotlin.jvm.*
8
8
9
9
private typealias Node = LockFreeLinkedListNode
10
10
11
- @PublishedApi
12
- internal const val UNDECIDED : Int = 0
13
-
14
- @PublishedApi
15
- internal const val SUCCESS : Int = 1
16
-
17
- @PublishedApi
18
- internal const val FAILURE : Int = 2
19
-
20
- @PublishedApi
21
- internal val CONDITION_FALSE : Any = Symbol (" CONDITION_FALSE" )
22
-
23
11
/* *
24
12
* Doubly-linked concurrent list node with remove support.
25
13
* Based on paper
@@ -49,37 +37,10 @@ public actual open class LockFreeLinkedListNode {
49
37
private fun removed (): Removed =
50
38
_removedRef .value ? : Removed (this ).also { _removedRef .lazySet(it) }
51
39
52
- @PublishedApi
53
- internal abstract class CondAddOp (
54
- @JvmField val newNode : Node
55
- ) : AtomicOp<Node>() {
56
- @JvmField var oldNext: Node ? = null
57
-
58
- override fun complete (affected : Node , failure : Any? ) {
59
- val success = failure == null
60
- val update = if (success) newNode else oldNext
61
- if (update != null && affected._next .compareAndSet( this , update)) {
62
- // only the thread the makes this update actually finishes add operation
63
- if (success) newNode.finishAdd(oldNext!! )
64
- }
65
- }
66
- }
67
-
68
- @PublishedApi
69
- internal inline fun makeCondAddOp (node : Node , crossinline condition : () -> Boolean ): CondAddOp =
70
- object : CondAddOp (node) {
71
- override fun prepare (affected : Node ): Any? = if (condition()) null else CONDITION_FALSE
72
- }
73
-
74
40
public actual open val isRemoved: Boolean get() = next is Removed
75
41
76
42
// LINEARIZABLE. Returns Node | Removed
77
- public val next: Any get() {
78
- _next .loop { next ->
79
- if (next !is OpDescriptor ) return next
80
- next.perform(this )
81
- }
82
- }
43
+ public val next: Any get() = _next .value
83
44
84
45
// LINEARIZABLE. Returns next non-removed Node
85
46
public actual val nextNode: Node get() =
@@ -117,29 +78,30 @@ public actual open class LockFreeLinkedListNode {
117
78
// ------ addLastXXX ------
118
79
119
80
/* *
120
- * Adds last item to this list.
81
+ * Adds last item to this list. Returns `false` if the list is closed.
121
82
*/
122
- public actual fun addLast (node : Node ) {
83
+ public actual fun addLast (node : Node , allowedAfterPartialClosing : Boolean ): Boolean {
123
84
while (true ) { // lock-free loop on prev.next
124
- if (prevNode.addNext(node, this )) return
85
+ val currentPrev = prevNode
86
+ return when {
87
+ currentPrev is LIST_CLOSED_FOR_ALL -> false
88
+ currentPrev is LIST_CLOSED_FOR_SOME ->
89
+ allowedAfterPartialClosing && currentPrev.addLast(node, allowedAfterPartialClosing)
90
+ currentPrev.addNext(node, this ) -> true
91
+ else -> continue
92
+ }
125
93
}
126
94
}
127
95
128
96
/* *
129
- * Adds last item to this list atomically if the [condition] is true .
97
+ * Forbids adding some of the new items to this list .
130
98
*/
131
- public actual inline fun addLastIf (node : Node , crossinline condition : () -> Boolean ): Boolean {
132
- val condAdd = makeCondAddOp(node, condition)
133
- while (true ) { // lock-free loop on prev.next
134
- val prev = prevNode // sentinel node is never removed, so prev is always defined
135
- when (prev.tryCondAddNext(node, this , condAdd)) {
136
- SUCCESS -> return true
137
- FAILURE -> return false
138
- }
139
- }
140
- }
99
+ public actual fun closeForSome () { addLast(LIST_CLOSED_FOR_SOME (), allowedAfterPartialClosing = false ) }
141
100
142
- // ------ addXXX util ------
101
+ /* *
102
+ * Forbids adding new items to this list.
103
+ */
104
+ public actual fun close () { addLast(LIST_CLOSED_FOR_ALL (), allowedAfterPartialClosing = true ) }
143
105
144
106
/* *
145
107
* Given:
@@ -174,17 +136,6 @@ public actual open class LockFreeLinkedListNode {
174
136
return true
175
137
}
176
138
177
- // returns UNDECIDED, SUCCESS or FAILURE
178
- @PublishedApi
179
- internal fun tryCondAddNext (node : Node , next : Node , condAdd : CondAddOp ): Int {
180
- node._prev .lazySet(this )
181
- node._next .lazySet(next)
182
- condAdd.oldNext = next
183
- if (! _next .compareAndSet(next, condAdd)) return UNDECIDED
184
- // added operation successfully (linearized) -- complete it & fixup the list
185
- return if (condAdd.perform(this ) == null ) SUCCESS else FAILURE
186
- }
187
-
188
139
// ------ removeXXX ------
189
140
190
141
/* *
@@ -284,10 +235,6 @@ public actual open class LockFreeLinkedListNode {
284
235
}
285
236
// slow path when we need to help remove operations
286
237
this .isRemoved -> return null // nothing to do, this node was removed, bail out asap to save time
287
- prevNext is OpDescriptor -> { // help & retry
288
- prevNext.perform(prev)
289
- return correctPrev() // retry from scratch
290
- }
291
238
prevNext is Removed -> {
292
239
if (last != = null ) {
293
240
// newly added (prev) node is already removed, correct last.next around it
@@ -347,3 +294,7 @@ public actual open class LockFreeLinkedListHead : LockFreeLinkedListNode() {
347
294
348
295
override fun nextIfRemoved (): Node ? = null
349
296
}
297
+
298
+ private class LIST_CLOSED_FOR_SOME : LockFreeLinkedListNode ()
299
+
300
+ private class LIST_CLOSED_FOR_ALL : LockFreeLinkedListNode ()
0 commit comments