blob: 846ddaaf7d280b180ce23dfb1820ade5a228eae9 [file] [log] [blame]
Roman Elizarovf16fd272017-02-07 11:26:00 +03001/*
Roman Elizarov1f74a2d2018-06-29 19:19:45 +03002 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
Roman Elizarovf16fd272017-02-07 11:26:00 +03003 */
4
Roman Elizarova5676592017-01-19 10:31:13 +03005package kotlinx.coroutines.experimental.internal
Roman Elizarov3754f952017-01-18 20:47:54 +03006
Roman Elizarov7eb41ef2017-08-10 21:09:26 +03007import kotlinx.atomicfu.atomic
8import kotlinx.atomicfu.loop
Roman Elizarov3754f952017-01-18 20:47:54 +03009
10private typealias Node = LockFreeLinkedListNode
11
Roman Elizarovf0246082017-02-10 18:02:38 +030012@PublishedApi
Roman Elizarov6c63aea2017-02-02 12:20:48 +030013internal const val UNDECIDED = 0
Roman Elizarovf0246082017-02-10 18:02:38 +030014
15@PublishedApi
Roman Elizarov6c63aea2017-02-02 12:20:48 +030016internal const val SUCCESS = 1
Roman Elizarovf0246082017-02-10 18:02:38 +030017
18@PublishedApi
Roman Elizarov6c63aea2017-02-02 12:20:48 +030019internal const val FAILURE = 2
20
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030021@PublishedApi
22internal val CONDITION_FALSE: Any = Symbol("CONDITION_FALSE")
23
24@PublishedApi
25internal val ALREADY_REMOVED: Any = Symbol("ALREADY_REMOVED")
26
27@PublishedApi
28internal val LIST_EMPTY: Any = Symbol("LIST_EMPTY")
29
30private val REMOVE_PREPARED: Any = Symbol("REMOVE_PREPARED")
31
Roman Elizarovaa461cf2018-04-11 13:20:29 +030032/** @suppress **This is unstable API and it is subject to change.** */
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +030033public actual typealias RemoveFirstDesc<T> = LockFreeLinkedListNode.RemoveFirstDesc<T>
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030034
Roman Elizarovaa461cf2018-04-11 13:20:29 +030035/** @suppress **This is unstable API and it is subject to change.** */
36public actual typealias AddLastDesc<T> = LockFreeLinkedListNode.AddLastDesc<T>
37
38/** @suppress **This is unstable API and it is subject to change.** */
39public actual typealias AbstractAtomicDesc = LockFreeLinkedListNode.AbstractAtomicDesc
Roman Elizarov1216e912017-02-22 09:57:06 +030040
41/**
Roman Elizarov3754f952017-01-18 20:47:54 +030042 * Doubly-linked concurrent list node with remove support.
43 * Based on paper
44 * ["Lock-Free and Practical Doubly Linked List-Based Deques Using Single-Word Compare-and-Swap"](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.140.4693&rep=rep1&type=pdf)
45 * by Sundell and Tsigas.
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030046 *
47 * Important notes:
48 * * The instance of this class serves both as list head/tail sentinel and as the list item.
49 * Sentinel node should be never removed.
50 * * There are no operations to add items to left side of the list, only to the end (right side), because we cannot
51 * efficiently linearize them with atomic multi-step head-removal operations. In short,
52 * support for [describeRemoveFirst] operation precludes ability to add items at the beginning.
Roman Elizarovf0246082017-02-10 18:02:38 +030053 *
54 * @suppress **This is unstable API and it is subject to change.**
Roman Elizarov3754f952017-01-18 20:47:54 +030055 */
56@Suppress("LeakingThis")
Roman Elizarovaa461cf2018-04-11 13:20:29 +030057public actual open class LockFreeLinkedListNode {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +030058 private val _next = atomic<Any>(this) // Node | Removed | OpDescriptor
59 private val _prev = atomic<Any>(this) // Node | Removed
60 private val _removedRef = atomic<Removed?>(null) // lazily cached removed ref to this
Roman Elizarov3754f952017-01-18 20:47:54 +030061
Roman Elizarov6f827832017-01-25 16:42:23 +030062 private fun removed(): Removed =
Roman Elizarov7eb41ef2017-08-10 21:09:26 +030063 _removedRef.value ?: Removed(this).also { _removedRef.lazySet(it) }
Roman Elizarov6f827832017-01-25 16:42:23 +030064
Roman Elizarovf0246082017-02-10 18:02:38 +030065 @PublishedApi
Roman Elizarov1216e912017-02-22 09:57:06 +030066 internal abstract class CondAddOp(
67 @JvmField val newNode: Node
Roman Elizarovd82b3a92017-06-23 21:52:08 +030068 ) : AtomicOp<Node>() {
Roman Elizarov1216e912017-02-22 09:57:06 +030069 @JvmField var oldNext: Node? = null
Roman Elizarov6c63aea2017-02-02 12:20:48 +030070
Roman Elizarovd82b3a92017-06-23 21:52:08 +030071 override fun complete(affected: Node, failure: Any?) {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030072 val success = failure == null
73 val update = if (success) newNode else oldNext
Roman Elizarov7eb41ef2017-08-10 21:09:26 +030074 if (update != null && affected._next.compareAndSet( this, update)) {
Roman Elizarov3754f952017-01-18 20:47:54 +030075 // only the thread the makes this update actually finishes add operation
Roman Elizarov1216e912017-02-22 09:57:06 +030076 if (success) newNode.finishAdd(oldNext!!)
Roman Elizarov3754f952017-01-18 20:47:54 +030077 }
Roman Elizarov3754f952017-01-18 20:47:54 +030078 }
79 }
80
Roman Elizarovf0246082017-02-10 18:02:38 +030081 @PublishedApi
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030082 internal inline fun makeCondAddOp(node: Node, crossinline condition: () -> Boolean): CondAddOp =
83 object : CondAddOp(node) {
Roman Elizarovd82b3a92017-06-23 21:52:08 +030084 override fun prepare(affected: Node): Any? = if (condition()) null else CONDITION_FALSE
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030085 }
Roman Elizarov6c63aea2017-02-02 12:20:48 +030086
Roman Elizarov7eb41ef2017-08-10 21:09:26 +030087 public val isFresh: Boolean get() = _next.value === this
Roman Elizarov35d2c342017-07-20 14:54:39 +030088
Roman Elizarovaa461cf2018-04-11 13:20:29 +030089 public actual val isRemoved: Boolean get() = next is Removed
Roman Elizarov3754f952017-01-18 20:47:54 +030090
Roman Elizarov3aed4ee2017-03-06 12:21:05 +030091 // LINEARIZABLE. Returns Node | Removed
Roman Elizarov0406a9b2018-04-26 12:35:43 +030092 public val next: Any get() {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +030093 _next.loop { next ->
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030094 if (next !is OpDescriptor) return next
95 next.perform(this)
Roman Elizarov3754f952017-01-18 20:47:54 +030096 }
97 }
98
Roman Elizarov0406a9b2018-04-26 12:35:43 +030099 // LINEARIZABLE. Returns next non-removed Node
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300100 public actual val nextNode: Node get() = next.unwrap()
101
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300102 // LINEARIZABLE. Returns Node | Removed
Roman Elizarov0406a9b2018-04-26 12:35:43 +0300103 public val prev: Any get() {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300104 _prev.loop { prev ->
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300105 if (prev is Removed) return prev
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300106 prev as Node // otherwise, it can be only node
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300107 if (prev.next === this) return prev
Roman Elizarovb78fa422017-07-05 09:54:03 +0300108 correctPrev(prev, null)
Roman Elizarov01934df2017-01-31 09:18:34 +0300109 }
110 }
111
Roman Elizarov0406a9b2018-04-26 12:35:43 +0300112 // LINEARIZABLE. Returns prev non-removed Node
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300113 public actual val prevNode: Node get() = prev.unwrap()
114
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300115 // ------ addOneIfEmpty ------
Roman Elizarov01934df2017-01-31 09:18:34 +0300116
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300117 public actual fun addOneIfEmpty(node: Node): Boolean {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300118 node._prev.lazySet(this)
119 node._next.lazySet(this)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300120 while (true) {
121 val next = next
122 if (next !== this) return false // this is not an empty list!
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300123 if (_next.compareAndSet(this, node)) {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300124 // added successfully (linearized add) -- fixup the list
125 node.finishAdd(this)
126 return true
127 }
128 }
Roman Elizarovdaa79222017-01-26 11:31:31 +0300129 }
130
Roman Elizarov01934df2017-01-31 09:18:34 +0300131 // ------ addLastXXX ------
132
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300133 /**
134 * Adds last item to this list.
135 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300136 public actual fun addLast(node: Node) {
Roman Elizarov3754f952017-01-18 20:47:54 +0300137 while (true) { // lock-free loop on prev.next
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300138 val prev = prev as Node // sentinel node is never removed, so prev is always defined
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300139 if (prev.addNext(node, this)) return
Roman Elizarov3754f952017-01-18 20:47:54 +0300140 }
141 }
142
Roman Elizarov174c6962017-02-28 17:36:51 +0300143 public fun <T : Node> describeAddLast(node: T): AddLastDesc<T> = AddLastDesc(this, node)
Roman Elizarov1216e912017-02-22 09:57:06 +0300144
Roman Elizarov01934df2017-01-31 09:18:34 +0300145 /**
Roman Elizarov01934df2017-01-31 09:18:34 +0300146 * Adds last item to this list atomically if the [condition] is true.
147 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300148 public actual inline fun addLastIf(node: Node, crossinline condition: () -> Boolean): Boolean {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300149 val condAdd = makeCondAddOp(node, condition)
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300150 while (true) { // lock-free loop on prev.next
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300151 val prev = prev as Node // sentinel node is never removed, so prev is always defined
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300152 when (prev.tryCondAddNext(node, this, condAdd)) {
153 SUCCESS -> return true
154 FAILURE -> return false
155 }
156 }
157 }
Roman Elizarov01934df2017-01-31 09:18:34 +0300158
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300159 public actual inline fun addLastIfPrev(node: Node, predicate: (Node) -> Boolean): Boolean {
Roman Elizarov01934df2017-01-31 09:18:34 +0300160 while (true) { // lock-free loop on prev.next
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300161 val prev = prev as Node // sentinel node is never removed, so prev is always defined
Roman Elizarov01934df2017-01-31 09:18:34 +0300162 if (!predicate(prev)) return false
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300163 if (prev.addNext(node, this)) return true
164 }
165 }
166
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300167 public actual inline fun addLastIfPrevAndIf(
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300168 node: Node,
169 predicate: (Node) -> Boolean, // prev node predicate
170 crossinline condition: () -> Boolean // atomically checked condition
171 ): Boolean {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300172 val condAdd = makeCondAddOp(node, condition)
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300173 while (true) { // lock-free loop on prev.next
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300174 val prev = prev as Node // sentinel node is never removed, so prev is always defined
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300175 if (!predicate(prev)) return false
176 when (prev.tryCondAddNext(node, this, condAdd)) {
177 SUCCESS -> return true
178 FAILURE -> return false
179 }
Roman Elizarov3754f952017-01-18 20:47:54 +0300180 }
181 }
182
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300183 // ------ addXXX util ------
184
Roman Elizarovdb0d4fc2018-01-29 10:50:20 +0300185 /**
186 * Given:
187 * ```
188 * +-----------------------+
189 * this | node V next
190 * +---+---+ +---+---+ +---+---+
191 * ... <-- | P | N | | P | N | | P | N | --> ....
192 * +---+---+ +---+---+ +---+---+
193 * ^ |
194 * +-----------------------+
195 * ```
196 * Produces:
197 * ```
198 * this node next
199 * +---+---+ +---+---+ +---+---+
200 * ... <-- | P | N | ==> | P | N | --> | P | N | --> ....
201 * +---+---+ +---+---+ +---+---+
202 * ^ | ^ |
203 * +---------+ +---------+
204 * ```
205 * Where `==>` denotes linearization point.
206 * Returns `false` if `next` was not following `this` node.
207 */
Roman Elizarovf0246082017-02-10 18:02:38 +0300208 @PublishedApi
209 internal fun addNext(node: Node, next: Node): Boolean {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300210 node._prev.lazySet(this)
211 node._next.lazySet(next)
212 if (!_next.compareAndSet(next, node)) return false
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300213 // added successfully (linearized add) -- fixup the list
214 node.finishAdd(next)
215 return true
216 }
217
218 // returns UNDECIDED, SUCCESS or FAILURE
Roman Elizarovf0246082017-02-10 18:02:38 +0300219 @PublishedApi
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300220 internal fun tryCondAddNext(node: Node, next: Node, condAdd: CondAddOp): Int {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300221 node._prev.lazySet(this)
222 node._next.lazySet(next)
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300223 condAdd.oldNext = next
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300224 if (!_next.compareAndSet(next, condAdd)) return UNDECIDED
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300225 // added operation successfully (linearized) -- complete it & fixup the list
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300226 return if (condAdd.perform(this) == null) SUCCESS else FAILURE
Roman Elizarov01934df2017-01-31 09:18:34 +0300227 }
228
229 // ------ removeXXX ------
230
Roman Elizarov3754f952017-01-18 20:47:54 +0300231 /**
Roman Elizarove9f64492017-07-11 12:50:00 +0300232 * Removes this node from the list. Returns `true` when removed successfully, or `false` if the node was already
233 * removed or if it was not added to any list in the first place.
Roman Elizarov3754f952017-01-18 20:47:54 +0300234 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300235 public actual open fun remove(): Boolean {
Roman Elizarov3754f952017-01-18 20:47:54 +0300236 while (true) { // lock-free loop on next
237 val next = this.next
Roman Elizarov53a0a402017-01-19 20:21:57 +0300238 if (next is Removed) return false // was already removed -- don't try to help (original thread will take care)
Roman Elizarove9f64492017-07-11 12:50:00 +0300239 if (next === this) return false // was not even added
Roman Elizarov1216e912017-02-22 09:57:06 +0300240 val removed = (next as Node).removed()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300241 if (_next.compareAndSet(next, removed)) {
Roman Elizarov3754f952017-01-18 20:47:54 +0300242 // was removed successfully (linearized remove) -- fixup the list
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300243 finishRemove(next)
Roman Elizarov53a0a402017-01-19 20:21:57 +0300244 return true
Roman Elizarov3754f952017-01-18 20:47:54 +0300245 }
246 }
247 }
248
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300249 public open fun describeRemove() : AtomicDesc? {
250 if (isRemoved) return null // fast path if was already removed
251 return object : AbstractAtomicDesc() {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300252 private val _originalNext = atomic<Node?>(null)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300253 override val affectedNode: Node? get() = this@LockFreeLinkedListNode
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300254 override val originalNext get() = _originalNext.value
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300255 override fun failure(affected: Node, next: Any): Any? =
256 if (next is Removed) ALREADY_REMOVED else null
Roman Elizarov1216e912017-02-22 09:57:06 +0300257 override fun onPrepare(affected: Node, next: Node): Any? {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300258 // Note: onPrepare must use CAS to make sure the stale invocation is not
259 // going to overwrite the previous decision on successful preparation.
260 // Result of CAS is irrelevant, but we must ensure that it is set when invoker completes
261 _originalNext.compareAndSet(null, next)
Roman Elizarov1216e912017-02-22 09:57:06 +0300262 return null // always success
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300263 }
Roman Elizarov1216e912017-02-22 09:57:06 +0300264 override fun updatedNext(affected: Node, next: Node) = next.removed()
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300265 override fun finishOnSuccess(affected: Node, next: Node) = finishRemove(next)
Roman Elizarov53a0a402017-01-19 20:21:57 +0300266 }
267 }
268
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300269 public actual fun removeFirstOrNull(): Node? {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300270 while (true) { // try to linearize
271 val first = next as Node
272 if (first === this) return null
273 if (first.remove()) return first
274 first.helpDelete() // must help delete, or loose lock-freedom
275 }
276 }
277
278 public fun describeRemoveFirst(): RemoveFirstDesc<Node> = RemoveFirstDesc(this)
279
Roman Elizarovf0246082017-02-10 18:02:38 +0300280 public inline fun <reified T> removeFirstIfIsInstanceOf(): T? {
Roman Elizarov01934df2017-01-31 09:18:34 +0300281 while (true) { // try to linearize
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300282 val first = next as Node
283 if (first === this) return null
Roman Elizarov01934df2017-01-31 09:18:34 +0300284 if (first !is T) return null
285 if (first.remove()) return first
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300286 first.helpDelete() // must help delete, or loose lock-freedom
Roman Elizarov01934df2017-01-31 09:18:34 +0300287 }
288 }
289
290 // just peek at item when predicate is true
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300291 public actual inline fun <reified T> removeFirstIfIsInstanceOfOrPeekIf(predicate: (T) -> Boolean): T? {
Roman Elizarov01934df2017-01-31 09:18:34 +0300292 while (true) { // try to linearize
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300293 val first = next as Node
294 if (first === this) return null
Roman Elizarov01934df2017-01-31 09:18:34 +0300295 if (first !is T) return null
296 if (predicate(first)) return first // just peek when predicate is true
297 if (first.remove()) return first
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300298 first.helpDelete() // must help delete, or loose lock-freedom
299 }
300 }
301
302 // ------ multi-word atomic operations helpers ------
303
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300304 public open class AddLastDesc<T : Node> constructor(
Roman Elizarov174c6962017-02-28 17:36:51 +0300305 @JvmField val queue: Node,
306 @JvmField val node: T
307 ) : AbstractAtomicDesc() {
Roman Elizarov1216e912017-02-22 09:57:06 +0300308 init {
309 // require freshly allocated node here
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300310 check(node._next.value === node && node._prev.value === node)
Roman Elizarov1216e912017-02-22 09:57:06 +0300311 }
312
313 final override fun takeAffectedNode(op: OpDescriptor): Node {
314 while (true) {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300315 val prev = queue._prev.value as Node // this sentinel node is never removed
316 val next = prev._next.value
Roman Elizarov1216e912017-02-22 09:57:06 +0300317 if (next === queue) return prev // all is good -> linked properly
318 if (next === op) return prev // all is good -> our operation descriptor is already there
319 if (next is OpDescriptor) { // some other operation descriptor -> help & retry
320 next.perform(prev)
321 continue
322 }
323 // linked improperly -- help insert
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300324 val affected = queue.correctPrev(prev, op)
325 // we can find node which this operation is already affecting while trying to correct prev
326 if (affected != null) return affected
Roman Elizarov1216e912017-02-22 09:57:06 +0300327 }
328 }
329
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300330 private val _affectedNode = atomic<Node?>(null)
331 final override val affectedNode: Node? get() = _affectedNode.value
Roman Elizarov1216e912017-02-22 09:57:06 +0300332 final override val originalNext: Node? get() = queue
333
334 override fun retry(affected: Node, next: Any): Boolean = next !== queue
335
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300336 protected override fun onPrepare(affected: Node, next: Node): Any? {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300337 // Note: onPrepare must use CAS to make sure the stale invocation is not
338 // going to overwrite the previous decision on successful preparation.
339 // Result of CAS is irrelevant, but we must ensure that it is set when invoker completes
340 _affectedNode.compareAndSet(null, affected)
Roman Elizarov1216e912017-02-22 09:57:06 +0300341 return null // always success
342 }
343
344 override fun updatedNext(affected: Node, next: Node): Any {
345 // it is invoked only on successfully completion of operation, but this invocation can be stale,
346 // so we must use CAS to set both prev & next pointers
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300347 node._prev.compareAndSet(node, affected)
348 node._next.compareAndSet(node, queue)
Roman Elizarov1216e912017-02-22 09:57:06 +0300349 return node
350 }
351
352 override fun finishOnSuccess(affected: Node, next: Node) {
353 node.finishAdd(queue)
354 }
355 }
356
Roman Elizarov174c6962017-02-28 17:36:51 +0300357 public open class RemoveFirstDesc<T>(
358 @JvmField val queue: Node
359 ) : AbstractAtomicDesc() {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300360 private val _affectedNode = atomic<Node?>(null)
361 private val _originalNext = atomic<Node?>(null)
362
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300363 @Suppress("UNCHECKED_CAST")
364 public val result: T get() = affectedNode!! as T
365
Roman Elizarov1216e912017-02-22 09:57:06 +0300366 final override fun takeAffectedNode(op: OpDescriptor): Node = queue.next as Node
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300367 final override val affectedNode: Node? get() = _affectedNode.value
368 final override val originalNext: Node? get() = _originalNext.value
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300369
370 // check node predicates here, must signal failure if affect is not of type T
371 protected override fun failure(affected: Node, next: Any): Any? =
372 if (affected === queue) LIST_EMPTY else null
Roman Elizarov1216e912017-02-22 09:57:06 +0300373
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300374 // validate the resulting node (return false if it should be deleted)
375 protected open fun validatePrepared(node: T): Boolean = true // false means remove node & retry
376
377 final override fun retry(affected: Node, next: Any): Boolean {
378 if (next !is Removed) return false
379 affected.helpDelete() // must help delete, or loose lock-freedom
380 return true
381 }
Roman Elizarov1216e912017-02-22 09:57:06 +0300382
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300383 @Suppress("UNCHECKED_CAST")
Roman Elizarov1216e912017-02-22 09:57:06 +0300384 final override fun onPrepare(affected: Node, next: Node): Any? {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300385 check(affected !is LockFreeLinkedListHead)
Roman Elizarov1216e912017-02-22 09:57:06 +0300386 if (!validatePrepared(affected as T)) return REMOVE_PREPARED
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300387 // Note: onPrepare must use CAS to make sure the stale invocation is not
388 // going to overwrite the previous decision on successful preparation.
389 // Result of CAS is irrelevant, but we must ensure that it is set when invoker completes
390 _affectedNode.compareAndSet(null, affected)
391 _originalNext.compareAndSet(null, next)
Roman Elizarov1216e912017-02-22 09:57:06 +0300392 return null // ok
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300393 }
Roman Elizarov1216e912017-02-22 09:57:06 +0300394
395 final override fun updatedNext(affected: Node, next: Node): Any = next.removed()
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300396 final override fun finishOnSuccess(affected: Node, next: Node) = affected.finishRemove(next)
397 }
398
399 public abstract class AbstractAtomicDesc : AtomicDesc() {
400 protected abstract val affectedNode: Node?
401 protected abstract val originalNext: Node?
Roman Elizarov1216e912017-02-22 09:57:06 +0300402 protected open fun takeAffectedNode(op: OpDescriptor): Node = affectedNode!!
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300403 protected open fun failure(affected: Node, next: Any): Any? = null // next: Node | Removed
404 protected open fun retry(affected: Node, next: Any): Boolean = false // next: Node | Removed
Roman Elizarov1216e912017-02-22 09:57:06 +0300405 protected abstract fun onPrepare(affected: Node, next: Node): Any? // non-null on failure
406 protected abstract fun updatedNext(affected: Node, next: Node): Any
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300407 protected abstract fun finishOnSuccess(affected: Node, next: Node)
408
409 // This is Harris's RDCSS (Restricted Double-Compare Single Swap) operation
410 // It inserts "op" descriptor of when "op" status is still undecided (rolls back otherwise)
411 private class PrepareOp(
Roman Elizarov1216e912017-02-22 09:57:06 +0300412 @JvmField val next: Node,
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300413 @JvmField val op: AtomicOp<Node>,
Roman Elizarov1216e912017-02-22 09:57:06 +0300414 @JvmField val desc: AbstractAtomicDesc
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300415 ) : OpDescriptor() {
416 override fun perform(affected: Any?): Any? {
417 affected as Node // type assertion
Roman Elizarov1216e912017-02-22 09:57:06 +0300418 val decision = desc.onPrepare(affected, next)
419 if (decision != null) {
420 if (decision === REMOVE_PREPARED) {
421 // remove element on failure
422 val removed = next.removed()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300423 if (affected._next.compareAndSet(this, removed)) {
Roman Elizarov1216e912017-02-22 09:57:06 +0300424 affected.helpDelete()
425 }
426 } else {
427 // some other failure -- mark as decided
428 op.tryDecide(decision)
429 // undo preparations
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300430 affected._next.compareAndSet(this, next)
Roman Elizarov1216e912017-02-22 09:57:06 +0300431 }
432 return decision
433 }
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300434 val update: Any = if (op.isDecided) next else op // restore if decision was already reached
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300435 affected._next.compareAndSet(this, update)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300436 return null // ok
437 }
438 }
439
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300440 @Suppress("UNCHECKED_CAST")
441 final override fun prepare(op: AtomicOp<*>): Any? {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300442 while (true) { // lock free loop on next
Roman Elizarov1216e912017-02-22 09:57:06 +0300443 val affected = takeAffectedNode(op)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300444 // read its original next pointer first
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300445 val next = affected._next.value
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300446 // then see if already reached consensus on overall operation
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300447 if (next === op) return null // already in process of operation -- all is good
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300448 if (op.isDecided) return null // already decided this operation -- go to next desc
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300449 if (next is OpDescriptor) {
450 // some other operation is in process -- help it
451 next.perform(affected)
452 continue // and retry
453 }
454 // next: Node | Removed
455 val failure = failure(affected, next)
456 if (failure != null) return failure // signal failure
457 if (retry(affected, next)) continue // retry operation
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300458 val prepareOp = PrepareOp(next as Node, op as AtomicOp<Node>, this)
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300459 if (affected._next.compareAndSet(next, prepareOp)) {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300460 // prepared -- complete preparations
Roman Elizarov1216e912017-02-22 09:57:06 +0300461 val prepFail = prepareOp.perform(affected)
462 if (prepFail === REMOVE_PREPARED) continue // retry
463 return prepFail
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300464 }
465 }
466 }
467
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300468 final override fun complete(op: AtomicOp<*>, failure: Any?) {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300469 val success = failure == null
Roman Elizarov1216e912017-02-22 09:57:06 +0300470 val affectedNode = affectedNode ?: run { check(!success); return }
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300471 val originalNext = originalNext ?: run { check(!success); return }
Roman Elizarov1216e912017-02-22 09:57:06 +0300472 val update = if (success) updatedNext(affectedNode, originalNext) else originalNext
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300473 if (affectedNode._next.compareAndSet(op, update)) {
Roman Elizarov1216e912017-02-22 09:57:06 +0300474 if (success) finishOnSuccess(affectedNode, originalNext)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300475 }
Roman Elizarov01934df2017-01-31 09:18:34 +0300476 }
477 }
478
479 // ------ other helpers ------
480
Roman Elizarovdb0d4fc2018-01-29 10:50:20 +0300481 /**
482 * Given:
483 * ```
484 *
485 * prev this next
486 * +---+---+ +---+---+ +---+---+
487 * ... <-- | P | N | --> | P | N | --> | P | N | --> ....
488 * +---+---+ +---+---+ +---+---+
489 * ^ ^ | |
490 * | +---------+ |
491 * +-------------------------+
492 * ```
493 * Produces:
494 * ```
495 * prev this next
496 * +---+---+ +---+---+ +---+---+
497 * ... <-- | P | N | --> | P | N | --> | P | N | --> ....
498 * +---+---+ +---+---+ +---+---+
499 * ^ | ^ |
500 * +---------+ +---------+
501 * ```
502 */
Roman Elizarov01934df2017-01-31 09:18:34 +0300503 private fun finishAdd(next: Node) {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300504 next._prev.loop { nextPrev ->
Roman Elizarov01934df2017-01-31 09:18:34 +0300505 if (nextPrev is Removed || this.next !== next) return // next was removed, remover fixes up links
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300506 if (next._prev.compareAndSet(nextPrev, this)) {
Roman Elizarov01934df2017-01-31 09:18:34 +0300507 if (this.next is Removed) {
508 // already removed
Roman Elizarovb78fa422017-07-05 09:54:03 +0300509 next.correctPrev(nextPrev as Node, null)
Roman Elizarov01934df2017-01-31 09:18:34 +0300510 }
511 return
512 }
513 }
514 }
515
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300516 private fun finishRemove(next: Node) {
517 helpDelete()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300518 next.correctPrev(_prev.value.unwrap(), null)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300519 }
520
Roman Elizarov3754f952017-01-18 20:47:54 +0300521 private fun markPrev(): Node {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300522 _prev.loop { prev ->
Roman Elizarov3754f952017-01-18 20:47:54 +0300523 if (prev is Removed) return prev.ref
Roman Elizarov0aa6db02018-01-29 13:18:38 +0300524 // See detailed comment in findHead on why `prev === this` is a special case for which we know that
525 // the prev should have being pointing to the head of list but finishAdd that was supposed
526 // to do that is not complete yet.
527 val removedPrev = (if (prev === this) findHead() else (prev as Node)).removed()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300528 if (_prev.compareAndSet(prev, removedPrev)) return prev
Roman Elizarov3754f952017-01-18 20:47:54 +0300529 }
530 }
531
Roman Elizarov0aa6db02018-01-29 13:18:38 +0300532 /**
533 * Finds the head of the list (implementing [LockFreeLinkedListHead]) by following [next] pointers.
534 *
535 * The code in [kotlinx.coroutines.experimental.JobSupport] performs upgrade of a single node to a list.
536 * It uses [addOneIfEmpty] to add the list head to "empty list of a single node" once.
537 * During upgrade a transient state of the list looks like this:
538 *
539 * ```
540 * +-----------------+
541 * | |
542 * node V head |
543 * +---+---+ +---+---+ |
544 * +-> | P | N | --> | P | N |-+
545 * | +---+---+ +---+---+
546 * | | ^ |
547 * +---- + +---------+
548 * ```
549 *
550 * The [prev] pointer in `node` still points to itself when [finishAdd] (invoked inside [addOneIfEmpty])
551 * has not completed yet. If this state is observed, then we know that [prev] should have been pointing
552 * to the list head. This function is looking up the head by following consistent chain of [next] pointers.
553 */
554 private fun findHead(): Node {
555 var cur = this
556 while (true) {
557 if (cur is LockFreeLinkedListHead) return cur
Roman Elizarov0406a9b2018-04-26 12:35:43 +0300558 cur = cur.nextNode
Roman Elizarov0aa6db02018-01-29 13:18:38 +0300559 check(cur !== this) { "Cannot loop to this while looking for list head" }
560 }
561 }
562
Roman Elizarov3754f952017-01-18 20:47:54 +0300563 // fixes next links to the left of this node
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300564 @PublishedApi
565 internal fun helpDelete() {
Roman Elizarov3754f952017-01-18 20:47:54 +0300566 var last: Node? = null // will set to the node left of prev when found
567 var prev: Node = markPrev()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300568 var next: Node = (this._next.value as Removed).ref
Roman Elizarov3754f952017-01-18 20:47:54 +0300569 while (true) {
570 // move to the right until first non-removed node
571 val nextNext = next.next
572 if (nextNext is Removed) {
573 next.markPrev()
574 next = nextNext.ref
575 continue
576 }
577 // move the the left until first non-removed node
578 val prevNext = prev.next
579 if (prevNext is Removed) {
580 if (last != null) {
581 prev.markPrev()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300582 last._next.compareAndSet(prev, prevNext.ref)
Roman Elizarov3754f952017-01-18 20:47:54 +0300583 prev = last
584 last = null
585 } else {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300586 prev = prev._prev.value.unwrap()
Roman Elizarov3754f952017-01-18 20:47:54 +0300587 }
588 continue
589 }
590 if (prevNext !== this) {
591 // skipped over some removed nodes to the left -- setup to fixup the next links
592 last = prev
593 prev = prevNext as Node
594 if (prev === next) return // already done!!!
595 continue
596 }
597 // Now prev & next are Ok
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300598 if (prev._next.compareAndSet(this, next)) return // success!
Roman Elizarov3754f952017-01-18 20:47:54 +0300599 }
600 }
601
602 // fixes prev links from this node
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300603 // returns affected node by this operation when this op is in progress (and nothing can be corrected)
604 // returns null otherwise (prev was corrected)
605 private fun correctPrev(_prev: Node, op: OpDescriptor?): Node? {
Roman Elizarov3754f952017-01-18 20:47:54 +0300606 var prev: Node = _prev
607 var last: Node? = null // will be set so that last.next === prev
608 while (true) {
609 // move the the left until first non-removed node
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300610 val prevNext = prev._next.value
611 if (prevNext === op) return prev // part of the same op -- don't recurse, didn't correct prev
Roman Elizarov1216e912017-02-22 09:57:06 +0300612 if (prevNext is OpDescriptor) { // help & retry
613 prevNext.perform(prev)
614 continue
615 }
Roman Elizarov3754f952017-01-18 20:47:54 +0300616 if (prevNext is Removed) {
617 if (last !== null) {
618 prev.markPrev()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300619 last._next.compareAndSet(prev, prevNext.ref)
Roman Elizarov3754f952017-01-18 20:47:54 +0300620 prev = last
621 last = null
622 } else {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300623 prev = prev._prev.value.unwrap()
Roman Elizarov3754f952017-01-18 20:47:54 +0300624 }
625 continue
626 }
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300627 val oldPrev = this._prev.value
628 if (oldPrev is Removed) return null // this node was removed, too -- its remover will take care
Roman Elizarov3754f952017-01-18 20:47:54 +0300629 if (prevNext !== this) {
630 // need to fixup next
631 last = prev
632 prev = prevNext as Node
633 continue
634 }
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300635 if (oldPrev === prev) return null // it is already linked as needed
636 if (this._prev.compareAndSet(oldPrev, prev)) {
637 if (prev._prev.value !is Removed) return null // finish only if prev was not concurrently removed
Roman Elizarov3754f952017-01-18 20:47:54 +0300638 }
639 }
640 }
641
Roman Elizarovf0246082017-02-10 18:02:38 +0300642 internal fun validateNode(prev: Node, next: Node) {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300643 check(prev === this._prev.value)
644 check(next === this._next.value)
Roman Elizarov3754f952017-01-18 20:47:54 +0300645 }
Roman Elizarov1216e912017-02-22 09:57:06 +0300646
647 override fun toString(): String = "${this::class.java.simpleName}@${Integer.toHexString(System.identityHashCode(this))}"
Roman Elizarov3754f952017-01-18 20:47:54 +0300648}
649
Roman Elizarov1216e912017-02-22 09:57:06 +0300650private class Removed(@JvmField val ref: Node) {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300651 override fun toString(): String = "Removed[$ref]"
652}
653
654@PublishedApi
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300655internal fun Any.unwrap(): Node = (this as? Removed)?.ref ?: this as Node
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300656
Roman Elizarovf0246082017-02-10 18:02:38 +0300657/**
658 * Head (sentinel) item of the linked list that is never removed.
659 *
660 * @suppress **This is unstable API and it is subject to change.**
661 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300662public actual open class LockFreeLinkedListHead : LockFreeLinkedListNode() {
663 public actual val isEmpty: Boolean get() = next === this
Roman Elizarov53a0a402017-01-19 20:21:57 +0300664
Roman Elizarov3754f952017-01-18 20:47:54 +0300665 /**
666 * Iterates over all elements in this list of a specified type.
667 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300668 public actual inline fun <reified T : Node> forEach(block: (T) -> Unit) {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300669 var cur: Node = next as Node
Roman Elizarov3754f952017-01-18 20:47:54 +0300670 while (cur != this) {
671 if (cur is T) block(cur)
Roman Elizarov0406a9b2018-04-26 12:35:43 +0300672 cur = cur.nextNode
Roman Elizarov3754f952017-01-18 20:47:54 +0300673 }
674 }
675
Roman Elizarov01934df2017-01-31 09:18:34 +0300676 // just a defensive programming -- makes sure that list head sentinel is never removed
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300677 public actual final override fun remove(): Nothing = throw UnsupportedOperationException()
678
679 public final override fun describeRemove(): Nothing = throw UnsupportedOperationException()
Roman Elizarov3754f952017-01-18 20:47:54 +0300680
Roman Elizarovf0246082017-02-10 18:02:38 +0300681 internal fun validate() {
Roman Elizarov3754f952017-01-18 20:47:54 +0300682 var prev: Node = this
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300683 var cur: Node = next as Node
Roman Elizarov3754f952017-01-18 20:47:54 +0300684 while (cur != this) {
Roman Elizarov0406a9b2018-04-26 12:35:43 +0300685 val next = cur.nextNode
Roman Elizarov3754f952017-01-18 20:47:54 +0300686 cur.validateNode(prev, next)
687 prev = cur
688 cur = next
689 }
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300690 validateNode(prev, next as Node)
Roman Elizarov3754f952017-01-18 20:47:54 +0300691 }
692}