blob: 15166a43ab5c5df23ac05c1dd1e2877b4e654249 [file] [log] [blame]
Roman Elizarovf16fd272017-02-07 11:26:00 +03001/*
2 * Copyright 2016-2017 JetBrains s.r.o.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Roman Elizarova5676592017-01-19 10:31:13 +030017package kotlinx.coroutines.experimental.internal
Roman Elizarov3754f952017-01-18 20:47:54 +030018
Roman Elizarov7eb41ef2017-08-10 21:09:26 +030019import kotlinx.atomicfu.atomic
20import kotlinx.atomicfu.loop
Roman Elizarov3754f952017-01-18 20:47:54 +030021
22private typealias Node = LockFreeLinkedListNode
23
Roman Elizarovf0246082017-02-10 18:02:38 +030024@PublishedApi
Roman Elizarov6c63aea2017-02-02 12:20:48 +030025internal const val UNDECIDED = 0
Roman Elizarovf0246082017-02-10 18:02:38 +030026
27@PublishedApi
Roman Elizarov6c63aea2017-02-02 12:20:48 +030028internal const val SUCCESS = 1
Roman Elizarovf0246082017-02-10 18:02:38 +030029
30@PublishedApi
Roman Elizarov6c63aea2017-02-02 12:20:48 +030031internal const val FAILURE = 2
32
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030033@PublishedApi
34internal val CONDITION_FALSE: Any = Symbol("CONDITION_FALSE")
35
36@PublishedApi
37internal val ALREADY_REMOVED: Any = Symbol("ALREADY_REMOVED")
38
39@PublishedApi
40internal val LIST_EMPTY: Any = Symbol("LIST_EMPTY")
41
42private val REMOVE_PREPARED: Any = Symbol("REMOVE_PREPARED")
43
Roman Elizarovaa461cf2018-04-11 13:20:29 +030044/** @suppress **This is unstable API and it is subject to change.** */
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +030045public actual typealias RemoveFirstDesc<T> = LockFreeLinkedListNode.RemoveFirstDesc<T>
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030046
Roman Elizarovaa461cf2018-04-11 13:20:29 +030047/** @suppress **This is unstable API and it is subject to change.** */
48public actual typealias AddLastDesc<T> = LockFreeLinkedListNode.AddLastDesc<T>
49
50/** @suppress **This is unstable API and it is subject to change.** */
51public actual typealias AbstractAtomicDesc = LockFreeLinkedListNode.AbstractAtomicDesc
Roman Elizarov1216e912017-02-22 09:57:06 +030052
53/**
Roman Elizarov3754f952017-01-18 20:47:54 +030054 * Doubly-linked concurrent list node with remove support.
55 * Based on paper
56 * ["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)
57 * by Sundell and Tsigas.
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030058 *
59 * Important notes:
60 * * The instance of this class serves both as list head/tail sentinel and as the list item.
61 * Sentinel node should be never removed.
62 * * There are no operations to add items to left side of the list, only to the end (right side), because we cannot
63 * efficiently linearize them with atomic multi-step head-removal operations. In short,
64 * support for [describeRemoveFirst] operation precludes ability to add items at the beginning.
Roman Elizarovf0246082017-02-10 18:02:38 +030065 *
66 * @suppress **This is unstable API and it is subject to change.**
Roman Elizarov3754f952017-01-18 20:47:54 +030067 */
68@Suppress("LeakingThis")
Roman Elizarovaa461cf2018-04-11 13:20:29 +030069public actual open class LockFreeLinkedListNode {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +030070 private val _next = atomic<Any>(this) // Node | Removed | OpDescriptor
71 private val _prev = atomic<Any>(this) // Node | Removed
72 private val _removedRef = atomic<Removed?>(null) // lazily cached removed ref to this
Roman Elizarov3754f952017-01-18 20:47:54 +030073
Roman Elizarov6f827832017-01-25 16:42:23 +030074 private fun removed(): Removed =
Roman Elizarov7eb41ef2017-08-10 21:09:26 +030075 _removedRef.value ?: Removed(this).also { _removedRef.lazySet(it) }
Roman Elizarov6f827832017-01-25 16:42:23 +030076
Roman Elizarovf0246082017-02-10 18:02:38 +030077 @PublishedApi
Roman Elizarov1216e912017-02-22 09:57:06 +030078 internal abstract class CondAddOp(
79 @JvmField val newNode: Node
Roman Elizarovd82b3a92017-06-23 21:52:08 +030080 ) : AtomicOp<Node>() {
Roman Elizarov1216e912017-02-22 09:57:06 +030081 @JvmField var oldNext: Node? = null
Roman Elizarov6c63aea2017-02-02 12:20:48 +030082
Roman Elizarovd82b3a92017-06-23 21:52:08 +030083 override fun complete(affected: Node, failure: Any?) {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030084 val success = failure == null
85 val update = if (success) newNode else oldNext
Roman Elizarov7eb41ef2017-08-10 21:09:26 +030086 if (update != null && affected._next.compareAndSet( this, update)) {
Roman Elizarov3754f952017-01-18 20:47:54 +030087 // only the thread the makes this update actually finishes add operation
Roman Elizarov1216e912017-02-22 09:57:06 +030088 if (success) newNode.finishAdd(oldNext!!)
Roman Elizarov3754f952017-01-18 20:47:54 +030089 }
Roman Elizarov3754f952017-01-18 20:47:54 +030090 }
91 }
92
Roman Elizarovf0246082017-02-10 18:02:38 +030093 @PublishedApi
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030094 internal inline fun makeCondAddOp(node: Node, crossinline condition: () -> Boolean): CondAddOp =
95 object : CondAddOp(node) {
Roman Elizarovd82b3a92017-06-23 21:52:08 +030096 override fun prepare(affected: Node): Any? = if (condition()) null else CONDITION_FALSE
Roman Elizarovee7c0eb2017-02-16 15:29:28 +030097 }
Roman Elizarov6c63aea2017-02-02 12:20:48 +030098
Roman Elizarov7eb41ef2017-08-10 21:09:26 +030099 public val isFresh: Boolean get() = _next.value === this
Roman Elizarov35d2c342017-07-20 14:54:39 +0300100
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300101 public actual val isRemoved: Boolean get() = next is Removed
Roman Elizarov3754f952017-01-18 20:47:54 +0300102
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300103 // LINEARIZABLE. Returns Node | Removed
Roman Elizarov0406a9b2018-04-26 12:35:43 +0300104 public val next: Any get() {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300105 _next.loop { next ->
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300106 if (next !is OpDescriptor) return next
107 next.perform(this)
Roman Elizarov3754f952017-01-18 20:47:54 +0300108 }
109 }
110
Roman Elizarov0406a9b2018-04-26 12:35:43 +0300111 // LINEARIZABLE. Returns next non-removed Node
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300112 public actual val nextNode: Node get() = next.unwrap()
113
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300114 // LINEARIZABLE. Returns Node | Removed
Roman Elizarov0406a9b2018-04-26 12:35:43 +0300115 public val prev: Any get() {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300116 _prev.loop { prev ->
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300117 if (prev is Removed) return prev
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300118 prev as Node // otherwise, it can be only node
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300119 if (prev.next === this) return prev
Roman Elizarovb78fa422017-07-05 09:54:03 +0300120 correctPrev(prev, null)
Roman Elizarov01934df2017-01-31 09:18:34 +0300121 }
122 }
123
Roman Elizarov0406a9b2018-04-26 12:35:43 +0300124 // LINEARIZABLE. Returns prev non-removed Node
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300125 public actual val prevNode: Node get() = prev.unwrap()
126
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300127 // ------ addOneIfEmpty ------
Roman Elizarov01934df2017-01-31 09:18:34 +0300128
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300129 public actual fun addOneIfEmpty(node: Node): Boolean {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300130 node._prev.lazySet(this)
131 node._next.lazySet(this)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300132 while (true) {
133 val next = next
134 if (next !== this) return false // this is not an empty list!
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300135 if (_next.compareAndSet(this, node)) {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300136 // added successfully (linearized add) -- fixup the list
137 node.finishAdd(this)
138 return true
139 }
140 }
Roman Elizarovdaa79222017-01-26 11:31:31 +0300141 }
142
Roman Elizarov01934df2017-01-31 09:18:34 +0300143 // ------ addLastXXX ------
144
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300145 /**
146 * Adds last item to this list.
147 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300148 public actual fun addLast(node: Node) {
Roman Elizarov3754f952017-01-18 20:47:54 +0300149 while (true) { // lock-free loop on prev.next
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300150 val prev = prev as Node // sentinel node is never removed, so prev is always defined
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300151 if (prev.addNext(node, this)) return
Roman Elizarov3754f952017-01-18 20:47:54 +0300152 }
153 }
154
Roman Elizarov174c6962017-02-28 17:36:51 +0300155 public fun <T : Node> describeAddLast(node: T): AddLastDesc<T> = AddLastDesc(this, node)
Roman Elizarov1216e912017-02-22 09:57:06 +0300156
Roman Elizarov01934df2017-01-31 09:18:34 +0300157 /**
Roman Elizarov01934df2017-01-31 09:18:34 +0300158 * Adds last item to this list atomically if the [condition] is true.
159 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300160 public actual inline fun addLastIf(node: Node, crossinline condition: () -> Boolean): Boolean {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300161 val condAdd = makeCondAddOp(node, condition)
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300162 while (true) { // lock-free loop on prev.next
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300163 val prev = prev as Node // sentinel node is never removed, so prev is always defined
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300164 when (prev.tryCondAddNext(node, this, condAdd)) {
165 SUCCESS -> return true
166 FAILURE -> return false
167 }
168 }
169 }
Roman Elizarov01934df2017-01-31 09:18:34 +0300170
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300171 public actual inline fun addLastIfPrev(node: Node, predicate: (Node) -> Boolean): Boolean {
Roman Elizarov01934df2017-01-31 09:18:34 +0300172 while (true) { // lock-free loop on prev.next
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300173 val prev = prev as Node // sentinel node is never removed, so prev is always defined
Roman Elizarov01934df2017-01-31 09:18:34 +0300174 if (!predicate(prev)) return false
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300175 if (prev.addNext(node, this)) return true
176 }
177 }
178
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300179 public actual inline fun addLastIfPrevAndIf(
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300180 node: Node,
181 predicate: (Node) -> Boolean, // prev node predicate
182 crossinline condition: () -> Boolean // atomically checked condition
183 ): Boolean {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300184 val condAdd = makeCondAddOp(node, condition)
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300185 while (true) { // lock-free loop on prev.next
Roman Elizarov3aed4ee2017-03-06 12:21:05 +0300186 val prev = prev as Node // sentinel node is never removed, so prev is always defined
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300187 if (!predicate(prev)) return false
188 when (prev.tryCondAddNext(node, this, condAdd)) {
189 SUCCESS -> return true
190 FAILURE -> return false
191 }
Roman Elizarov3754f952017-01-18 20:47:54 +0300192 }
193 }
194
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300195 // ------ addXXX util ------
196
Roman Elizarovdb0d4fc2018-01-29 10:50:20 +0300197 /**
198 * Given:
199 * ```
200 * +-----------------------+
201 * this | node V next
202 * +---+---+ +---+---+ +---+---+
203 * ... <-- | P | N | | P | N | | P | N | --> ....
204 * +---+---+ +---+---+ +---+---+
205 * ^ |
206 * +-----------------------+
207 * ```
208 * Produces:
209 * ```
210 * this node next
211 * +---+---+ +---+---+ +---+---+
212 * ... <-- | P | N | ==> | P | N | --> | P | N | --> ....
213 * +---+---+ +---+---+ +---+---+
214 * ^ | ^ |
215 * +---------+ +---------+
216 * ```
217 * Where `==>` denotes linearization point.
218 * Returns `false` if `next` was not following `this` node.
219 */
Roman Elizarovf0246082017-02-10 18:02:38 +0300220 @PublishedApi
221 internal fun addNext(node: Node, next: Node): Boolean {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300222 node._prev.lazySet(this)
223 node._next.lazySet(next)
224 if (!_next.compareAndSet(next, node)) return false
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300225 // added successfully (linearized add) -- fixup the list
226 node.finishAdd(next)
227 return true
228 }
229
230 // returns UNDECIDED, SUCCESS or FAILURE
Roman Elizarovf0246082017-02-10 18:02:38 +0300231 @PublishedApi
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300232 internal fun tryCondAddNext(node: Node, next: Node, condAdd: CondAddOp): Int {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300233 node._prev.lazySet(this)
234 node._next.lazySet(next)
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300235 condAdd.oldNext = next
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300236 if (!_next.compareAndSet(next, condAdd)) return UNDECIDED
Roman Elizarov6c63aea2017-02-02 12:20:48 +0300237 // added operation successfully (linearized) -- complete it & fixup the list
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300238 return if (condAdd.perform(this) == null) SUCCESS else FAILURE
Roman Elizarov01934df2017-01-31 09:18:34 +0300239 }
240
241 // ------ removeXXX ------
242
Roman Elizarov3754f952017-01-18 20:47:54 +0300243 /**
Roman Elizarove9f64492017-07-11 12:50:00 +0300244 * Removes this node from the list. Returns `true` when removed successfully, or `false` if the node was already
245 * removed or if it was not added to any list in the first place.
Roman Elizarov3754f952017-01-18 20:47:54 +0300246 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300247 public actual open fun remove(): Boolean {
Roman Elizarov3754f952017-01-18 20:47:54 +0300248 while (true) { // lock-free loop on next
249 val next = this.next
Roman Elizarov53a0a402017-01-19 20:21:57 +0300250 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 +0300251 if (next === this) return false // was not even added
Roman Elizarov1216e912017-02-22 09:57:06 +0300252 val removed = (next as Node).removed()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300253 if (_next.compareAndSet(next, removed)) {
Roman Elizarov3754f952017-01-18 20:47:54 +0300254 // was removed successfully (linearized remove) -- fixup the list
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300255 finishRemove(next)
Roman Elizarov53a0a402017-01-19 20:21:57 +0300256 return true
Roman Elizarov3754f952017-01-18 20:47:54 +0300257 }
258 }
259 }
260
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300261 public open fun describeRemove() : AtomicDesc? {
262 if (isRemoved) return null // fast path if was already removed
263 return object : AbstractAtomicDesc() {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300264 private val _originalNext = atomic<Node?>(null)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300265 override val affectedNode: Node? get() = this@LockFreeLinkedListNode
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300266 override val originalNext get() = _originalNext.value
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300267 override fun failure(affected: Node, next: Any): Any? =
268 if (next is Removed) ALREADY_REMOVED else null
Roman Elizarov1216e912017-02-22 09:57:06 +0300269 override fun onPrepare(affected: Node, next: Node): Any? {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300270 // Note: onPrepare must use CAS to make sure the stale invocation is not
271 // going to overwrite the previous decision on successful preparation.
272 // Result of CAS is irrelevant, but we must ensure that it is set when invoker completes
273 _originalNext.compareAndSet(null, next)
Roman Elizarov1216e912017-02-22 09:57:06 +0300274 return null // always success
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300275 }
Roman Elizarov1216e912017-02-22 09:57:06 +0300276 override fun updatedNext(affected: Node, next: Node) = next.removed()
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300277 override fun finishOnSuccess(affected: Node, next: Node) = finishRemove(next)
Roman Elizarov53a0a402017-01-19 20:21:57 +0300278 }
279 }
280
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300281 public actual fun removeFirstOrNull(): Node? {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300282 while (true) { // try to linearize
283 val first = next as Node
284 if (first === this) return null
285 if (first.remove()) return first
286 first.helpDelete() // must help delete, or loose lock-freedom
287 }
288 }
289
290 public fun describeRemoveFirst(): RemoveFirstDesc<Node> = RemoveFirstDesc(this)
291
Roman Elizarovf0246082017-02-10 18:02:38 +0300292 public inline fun <reified T> removeFirstIfIsInstanceOf(): T? {
Roman Elizarov01934df2017-01-31 09:18:34 +0300293 while (true) { // try to linearize
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300294 val first = next as Node
295 if (first === this) return null
Roman Elizarov01934df2017-01-31 09:18:34 +0300296 if (first !is T) return null
297 if (first.remove()) return first
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300298 first.helpDelete() // must help delete, or loose lock-freedom
Roman Elizarov01934df2017-01-31 09:18:34 +0300299 }
300 }
301
302 // just peek at item when predicate is true
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300303 public actual inline fun <reified T> removeFirstIfIsInstanceOfOrPeekIf(predicate: (T) -> Boolean): T? {
Roman Elizarov01934df2017-01-31 09:18:34 +0300304 while (true) { // try to linearize
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300305 val first = next as Node
306 if (first === this) return null
Roman Elizarov01934df2017-01-31 09:18:34 +0300307 if (first !is T) return null
308 if (predicate(first)) return first // just peek when predicate is true
309 if (first.remove()) return first
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300310 first.helpDelete() // must help delete, or loose lock-freedom
311 }
312 }
313
314 // ------ multi-word atomic operations helpers ------
315
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300316 public open class AddLastDesc<T : Node> constructor(
Roman Elizarov174c6962017-02-28 17:36:51 +0300317 @JvmField val queue: Node,
318 @JvmField val node: T
319 ) : AbstractAtomicDesc() {
Roman Elizarov1216e912017-02-22 09:57:06 +0300320 init {
321 // require freshly allocated node here
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300322 check(node._next.value === node && node._prev.value === node)
Roman Elizarov1216e912017-02-22 09:57:06 +0300323 }
324
325 final override fun takeAffectedNode(op: OpDescriptor): Node {
326 while (true) {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300327 val prev = queue._prev.value as Node // this sentinel node is never removed
328 val next = prev._next.value
Roman Elizarov1216e912017-02-22 09:57:06 +0300329 if (next === queue) return prev // all is good -> linked properly
330 if (next === op) return prev // all is good -> our operation descriptor is already there
331 if (next is OpDescriptor) { // some other operation descriptor -> help & retry
332 next.perform(prev)
333 continue
334 }
335 // linked improperly -- help insert
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300336 val affected = queue.correctPrev(prev, op)
337 // we can find node which this operation is already affecting while trying to correct prev
338 if (affected != null) return affected
Roman Elizarov1216e912017-02-22 09:57:06 +0300339 }
340 }
341
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300342 private val _affectedNode = atomic<Node?>(null)
343 final override val affectedNode: Node? get() = _affectedNode.value
Roman Elizarov1216e912017-02-22 09:57:06 +0300344 final override val originalNext: Node? get() = queue
345
346 override fun retry(affected: Node, next: Any): Boolean = next !== queue
347
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300348 protected override fun onPrepare(affected: Node, next: Node): Any? {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300349 // Note: onPrepare must use CAS to make sure the stale invocation is not
350 // going to overwrite the previous decision on successful preparation.
351 // Result of CAS is irrelevant, but we must ensure that it is set when invoker completes
352 _affectedNode.compareAndSet(null, affected)
Roman Elizarov1216e912017-02-22 09:57:06 +0300353 return null // always success
354 }
355
356 override fun updatedNext(affected: Node, next: Node): Any {
357 // it is invoked only on successfully completion of operation, but this invocation can be stale,
358 // so we must use CAS to set both prev & next pointers
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300359 node._prev.compareAndSet(node, affected)
360 node._next.compareAndSet(node, queue)
Roman Elizarov1216e912017-02-22 09:57:06 +0300361 return node
362 }
363
364 override fun finishOnSuccess(affected: Node, next: Node) {
365 node.finishAdd(queue)
366 }
367 }
368
Roman Elizarov174c6962017-02-28 17:36:51 +0300369 public open class RemoveFirstDesc<T>(
370 @JvmField val queue: Node
371 ) : AbstractAtomicDesc() {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300372 private val _affectedNode = atomic<Node?>(null)
373 private val _originalNext = atomic<Node?>(null)
374
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300375 @Suppress("UNCHECKED_CAST")
376 public val result: T get() = affectedNode!! as T
377
Roman Elizarov1216e912017-02-22 09:57:06 +0300378 final override fun takeAffectedNode(op: OpDescriptor): Node = queue.next as Node
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300379 final override val affectedNode: Node? get() = _affectedNode.value
380 final override val originalNext: Node? get() = _originalNext.value
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300381
382 // check node predicates here, must signal failure if affect is not of type T
383 protected override fun failure(affected: Node, next: Any): Any? =
384 if (affected === queue) LIST_EMPTY else null
Roman Elizarov1216e912017-02-22 09:57:06 +0300385
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300386 // validate the resulting node (return false if it should be deleted)
387 protected open fun validatePrepared(node: T): Boolean = true // false means remove node & retry
388
389 final override fun retry(affected: Node, next: Any): Boolean {
390 if (next !is Removed) return false
391 affected.helpDelete() // must help delete, or loose lock-freedom
392 return true
393 }
Roman Elizarov1216e912017-02-22 09:57:06 +0300394
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300395 @Suppress("UNCHECKED_CAST")
Roman Elizarov1216e912017-02-22 09:57:06 +0300396 final override fun onPrepare(affected: Node, next: Node): Any? {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300397 check(affected !is LockFreeLinkedListHead)
Roman Elizarov1216e912017-02-22 09:57:06 +0300398 if (!validatePrepared(affected as T)) return REMOVE_PREPARED
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300399 // Note: onPrepare must use CAS to make sure the stale invocation is not
400 // going to overwrite the previous decision on successful preparation.
401 // Result of CAS is irrelevant, but we must ensure that it is set when invoker completes
402 _affectedNode.compareAndSet(null, affected)
403 _originalNext.compareAndSet(null, next)
Roman Elizarov1216e912017-02-22 09:57:06 +0300404 return null // ok
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300405 }
Roman Elizarov1216e912017-02-22 09:57:06 +0300406
407 final override fun updatedNext(affected: Node, next: Node): Any = next.removed()
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300408 final override fun finishOnSuccess(affected: Node, next: Node) = affected.finishRemove(next)
409 }
410
411 public abstract class AbstractAtomicDesc : AtomicDesc() {
412 protected abstract val affectedNode: Node?
413 protected abstract val originalNext: Node?
Roman Elizarov1216e912017-02-22 09:57:06 +0300414 protected open fun takeAffectedNode(op: OpDescriptor): Node = affectedNode!!
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300415 protected open fun failure(affected: Node, next: Any): Any? = null // next: Node | Removed
416 protected open fun retry(affected: Node, next: Any): Boolean = false // next: Node | Removed
Roman Elizarov1216e912017-02-22 09:57:06 +0300417 protected abstract fun onPrepare(affected: Node, next: Node): Any? // non-null on failure
418 protected abstract fun updatedNext(affected: Node, next: Node): Any
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300419 protected abstract fun finishOnSuccess(affected: Node, next: Node)
420
421 // This is Harris's RDCSS (Restricted Double-Compare Single Swap) operation
422 // It inserts "op" descriptor of when "op" status is still undecided (rolls back otherwise)
423 private class PrepareOp(
Roman Elizarov1216e912017-02-22 09:57:06 +0300424 @JvmField val next: Node,
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300425 @JvmField val op: AtomicOp<Node>,
Roman Elizarov1216e912017-02-22 09:57:06 +0300426 @JvmField val desc: AbstractAtomicDesc
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300427 ) : OpDescriptor() {
428 override fun perform(affected: Any?): Any? {
429 affected as Node // type assertion
Roman Elizarov1216e912017-02-22 09:57:06 +0300430 val decision = desc.onPrepare(affected, next)
431 if (decision != null) {
432 if (decision === REMOVE_PREPARED) {
433 // remove element on failure
434 val removed = next.removed()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300435 if (affected._next.compareAndSet(this, removed)) {
Roman Elizarov1216e912017-02-22 09:57:06 +0300436 affected.helpDelete()
437 }
438 } else {
439 // some other failure -- mark as decided
440 op.tryDecide(decision)
441 // undo preparations
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300442 affected._next.compareAndSet(this, next)
Roman Elizarov1216e912017-02-22 09:57:06 +0300443 }
444 return decision
445 }
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300446 val update: Any = if (op.isDecided) next else op // restore if decision was already reached
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300447 affected._next.compareAndSet(this, update)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300448 return null // ok
449 }
450 }
451
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300452 @Suppress("UNCHECKED_CAST")
453 final override fun prepare(op: AtomicOp<*>): Any? {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300454 while (true) { // lock free loop on next
Roman Elizarov1216e912017-02-22 09:57:06 +0300455 val affected = takeAffectedNode(op)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300456 // read its original next pointer first
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300457 val next = affected._next.value
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300458 // then see if already reached consensus on overall operation
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300459 if (next === op) return null // already in process of operation -- all is good
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300460 if (op.isDecided) return null // already decided this operation -- go to next desc
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300461 if (next is OpDescriptor) {
462 // some other operation is in process -- help it
463 next.perform(affected)
464 continue // and retry
465 }
466 // next: Node | Removed
467 val failure = failure(affected, next)
468 if (failure != null) return failure // signal failure
469 if (retry(affected, next)) continue // retry operation
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300470 val prepareOp = PrepareOp(next as Node, op as AtomicOp<Node>, this)
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300471 if (affected._next.compareAndSet(next, prepareOp)) {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300472 // prepared -- complete preparations
Roman Elizarov1216e912017-02-22 09:57:06 +0300473 val prepFail = prepareOp.perform(affected)
474 if (prepFail === REMOVE_PREPARED) continue // retry
475 return prepFail
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300476 }
477 }
478 }
479
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300480 final override fun complete(op: AtomicOp<*>, failure: Any?) {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300481 val success = failure == null
Roman Elizarov1216e912017-02-22 09:57:06 +0300482 val affectedNode = affectedNode ?: run { check(!success); return }
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300483 val originalNext = originalNext ?: run { check(!success); return }
Roman Elizarov1216e912017-02-22 09:57:06 +0300484 val update = if (success) updatedNext(affectedNode, originalNext) else originalNext
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300485 if (affectedNode._next.compareAndSet(op, update)) {
Roman Elizarov1216e912017-02-22 09:57:06 +0300486 if (success) finishOnSuccess(affectedNode, originalNext)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300487 }
Roman Elizarov01934df2017-01-31 09:18:34 +0300488 }
489 }
490
491 // ------ other helpers ------
492
Roman Elizarovdb0d4fc2018-01-29 10:50:20 +0300493 /**
494 * Given:
495 * ```
496 *
497 * prev this next
498 * +---+---+ +---+---+ +---+---+
499 * ... <-- | P | N | --> | P | N | --> | P | N | --> ....
500 * +---+---+ +---+---+ +---+---+
501 * ^ ^ | |
502 * | +---------+ |
503 * +-------------------------+
504 * ```
505 * Produces:
506 * ```
507 * prev this next
508 * +---+---+ +---+---+ +---+---+
509 * ... <-- | P | N | --> | P | N | --> | P | N | --> ....
510 * +---+---+ +---+---+ +---+---+
511 * ^ | ^ |
512 * +---------+ +---------+
513 * ```
514 */
Roman Elizarov01934df2017-01-31 09:18:34 +0300515 private fun finishAdd(next: Node) {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300516 next._prev.loop { nextPrev ->
Roman Elizarov01934df2017-01-31 09:18:34 +0300517 if (nextPrev is Removed || this.next !== next) return // next was removed, remover fixes up links
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300518 if (next._prev.compareAndSet(nextPrev, this)) {
Roman Elizarov01934df2017-01-31 09:18:34 +0300519 if (this.next is Removed) {
520 // already removed
Roman Elizarovb78fa422017-07-05 09:54:03 +0300521 next.correctPrev(nextPrev as Node, null)
Roman Elizarov01934df2017-01-31 09:18:34 +0300522 }
523 return
524 }
525 }
526 }
527
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300528 private fun finishRemove(next: Node) {
529 helpDelete()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300530 next.correctPrev(_prev.value.unwrap(), null)
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300531 }
532
Roman Elizarov3754f952017-01-18 20:47:54 +0300533 private fun markPrev(): Node {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300534 _prev.loop { prev ->
Roman Elizarov3754f952017-01-18 20:47:54 +0300535 if (prev is Removed) return prev.ref
Roman Elizarov0aa6db02018-01-29 13:18:38 +0300536 // See detailed comment in findHead on why `prev === this` is a special case for which we know that
537 // the prev should have being pointing to the head of list but finishAdd that was supposed
538 // to do that is not complete yet.
539 val removedPrev = (if (prev === this) findHead() else (prev as Node)).removed()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300540 if (_prev.compareAndSet(prev, removedPrev)) return prev
Roman Elizarov3754f952017-01-18 20:47:54 +0300541 }
542 }
543
Roman Elizarov0aa6db02018-01-29 13:18:38 +0300544 /**
545 * Finds the head of the list (implementing [LockFreeLinkedListHead]) by following [next] pointers.
546 *
547 * The code in [kotlinx.coroutines.experimental.JobSupport] performs upgrade of a single node to a list.
548 * It uses [addOneIfEmpty] to add the list head to "empty list of a single node" once.
549 * During upgrade a transient state of the list looks like this:
550 *
551 * ```
552 * +-----------------+
553 * | |
554 * node V head |
555 * +---+---+ +---+---+ |
556 * +-> | P | N | --> | P | N |-+
557 * | +---+---+ +---+---+
558 * | | ^ |
559 * +---- + +---------+
560 * ```
561 *
562 * The [prev] pointer in `node` still points to itself when [finishAdd] (invoked inside [addOneIfEmpty])
563 * has not completed yet. If this state is observed, then we know that [prev] should have been pointing
564 * to the list head. This function is looking up the head by following consistent chain of [next] pointers.
565 */
566 private fun findHead(): Node {
567 var cur = this
568 while (true) {
569 if (cur is LockFreeLinkedListHead) return cur
Roman Elizarov0406a9b2018-04-26 12:35:43 +0300570 cur = cur.nextNode
Roman Elizarov0aa6db02018-01-29 13:18:38 +0300571 check(cur !== this) { "Cannot loop to this while looking for list head" }
572 }
573 }
574
Roman Elizarov3754f952017-01-18 20:47:54 +0300575 // fixes next links to the left of this node
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300576 @PublishedApi
577 internal fun helpDelete() {
Roman Elizarov3754f952017-01-18 20:47:54 +0300578 var last: Node? = null // will set to the node left of prev when found
579 var prev: Node = markPrev()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300580 var next: Node = (this._next.value as Removed).ref
Roman Elizarov3754f952017-01-18 20:47:54 +0300581 while (true) {
582 // move to the right until first non-removed node
583 val nextNext = next.next
584 if (nextNext is Removed) {
585 next.markPrev()
586 next = nextNext.ref
587 continue
588 }
589 // move the the left until first non-removed node
590 val prevNext = prev.next
591 if (prevNext is Removed) {
592 if (last != null) {
593 prev.markPrev()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300594 last._next.compareAndSet(prev, prevNext.ref)
Roman Elizarov3754f952017-01-18 20:47:54 +0300595 prev = last
596 last = null
597 } else {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300598 prev = prev._prev.value.unwrap()
Roman Elizarov3754f952017-01-18 20:47:54 +0300599 }
600 continue
601 }
602 if (prevNext !== this) {
603 // skipped over some removed nodes to the left -- setup to fixup the next links
604 last = prev
605 prev = prevNext as Node
606 if (prev === next) return // already done!!!
607 continue
608 }
609 // Now prev & next are Ok
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300610 if (prev._next.compareAndSet(this, next)) return // success!
Roman Elizarov3754f952017-01-18 20:47:54 +0300611 }
612 }
613
614 // fixes prev links from this node
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300615 // returns affected node by this operation when this op is in progress (and nothing can be corrected)
616 // returns null otherwise (prev was corrected)
617 private fun correctPrev(_prev: Node, op: OpDescriptor?): Node? {
Roman Elizarov3754f952017-01-18 20:47:54 +0300618 var prev: Node = _prev
619 var last: Node? = null // will be set so that last.next === prev
620 while (true) {
621 // move the the left until first non-removed node
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300622 val prevNext = prev._next.value
623 if (prevNext === op) return prev // part of the same op -- don't recurse, didn't correct prev
Roman Elizarov1216e912017-02-22 09:57:06 +0300624 if (prevNext is OpDescriptor) { // help & retry
625 prevNext.perform(prev)
626 continue
627 }
Roman Elizarov3754f952017-01-18 20:47:54 +0300628 if (prevNext is Removed) {
629 if (last !== null) {
630 prev.markPrev()
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300631 last._next.compareAndSet(prev, prevNext.ref)
Roman Elizarov3754f952017-01-18 20:47:54 +0300632 prev = last
633 last = null
634 } else {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300635 prev = prev._prev.value.unwrap()
Roman Elizarov3754f952017-01-18 20:47:54 +0300636 }
637 continue
638 }
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300639 val oldPrev = this._prev.value
640 if (oldPrev is Removed) return null // this node was removed, too -- its remover will take care
Roman Elizarov3754f952017-01-18 20:47:54 +0300641 if (prevNext !== this) {
642 // need to fixup next
643 last = prev
644 prev = prevNext as Node
645 continue
646 }
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300647 if (oldPrev === prev) return null // it is already linked as needed
648 if (this._prev.compareAndSet(oldPrev, prev)) {
649 if (prev._prev.value !is Removed) return null // finish only if prev was not concurrently removed
Roman Elizarov3754f952017-01-18 20:47:54 +0300650 }
651 }
652 }
653
Roman Elizarovf0246082017-02-10 18:02:38 +0300654 internal fun validateNode(prev: Node, next: Node) {
Roman Elizarov7eb41ef2017-08-10 21:09:26 +0300655 check(prev === this._prev.value)
656 check(next === this._next.value)
Roman Elizarov3754f952017-01-18 20:47:54 +0300657 }
Roman Elizarov1216e912017-02-22 09:57:06 +0300658
659 override fun toString(): String = "${this::class.java.simpleName}@${Integer.toHexString(System.identityHashCode(this))}"
Roman Elizarov3754f952017-01-18 20:47:54 +0300660}
661
Roman Elizarov1216e912017-02-22 09:57:06 +0300662private class Removed(@JvmField val ref: Node) {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300663 override fun toString(): String = "Removed[$ref]"
664}
665
666@PublishedApi
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300667internal fun Any.unwrap(): Node = (this as? Removed)?.ref ?: this as Node
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300668
Roman Elizarovf0246082017-02-10 18:02:38 +0300669/**
670 * Head (sentinel) item of the linked list that is never removed.
671 *
672 * @suppress **This is unstable API and it is subject to change.**
673 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300674public actual open class LockFreeLinkedListHead : LockFreeLinkedListNode() {
675 public actual val isEmpty: Boolean get() = next === this
Roman Elizarov53a0a402017-01-19 20:21:57 +0300676
Roman Elizarov3754f952017-01-18 20:47:54 +0300677 /**
678 * Iterates over all elements in this list of a specified type.
679 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300680 public actual inline fun <reified T : Node> forEach(block: (T) -> Unit) {
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300681 var cur: Node = next as Node
Roman Elizarov3754f952017-01-18 20:47:54 +0300682 while (cur != this) {
683 if (cur is T) block(cur)
Roman Elizarov0406a9b2018-04-26 12:35:43 +0300684 cur = cur.nextNode
Roman Elizarov3754f952017-01-18 20:47:54 +0300685 }
686 }
687
Roman Elizarov01934df2017-01-31 09:18:34 +0300688 // just a defensive programming -- makes sure that list head sentinel is never removed
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300689 public actual final override fun remove(): Nothing = throw UnsupportedOperationException()
690
691 public final override fun describeRemove(): Nothing = throw UnsupportedOperationException()
Roman Elizarov3754f952017-01-18 20:47:54 +0300692
Roman Elizarovf0246082017-02-10 18:02:38 +0300693 internal fun validate() {
Roman Elizarov3754f952017-01-18 20:47:54 +0300694 var prev: Node = this
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300695 var cur: Node = next as Node
Roman Elizarov3754f952017-01-18 20:47:54 +0300696 while (cur != this) {
Roman Elizarov0406a9b2018-04-26 12:35:43 +0300697 val next = cur.nextNode
Roman Elizarov3754f952017-01-18 20:47:54 +0300698 cur.validateNode(prev, next)
699 prev = cur
700 cur = next
701 }
Roman Elizarovee7c0eb2017-02-16 15:29:28 +0300702 validateNode(prev, next as Node)
Roman Elizarov3754f952017-01-18 20:47:54 +0300703 }
704}