@@ -57,8 +57,9 @@ public actual typealias PrepareOp = LockFreeLinkedListNode.PrepareOp
57
57
@Suppress(" LeakingThis" )
58
58
@InternalCoroutinesApi
59
59
public actual open class LockFreeLinkedListNode {
60
- private val _next = atomic<Any >(this ) // Node | Removed | OpDescriptor
61
- private val _prev = atomic<Any >(this ) // Node | Removed
60
+ // those _next & _prev refs can be null on Kotlin/Native when doubly-linked list is disposed
61
+ private val _next = atomic<Any ?>(this ) // Node | Removed | OpDescriptor
62
+ private val _prev = atomic<Any ?>(this ) // Node | Removed
62
63
private val _removedRef = atomic<Removed ?>(null ) // lazily cached removed ref to this
63
64
64
65
private fun removed (): Removed =
@@ -93,28 +94,30 @@ public actual open class LockFreeLinkedListNode {
93
94
public actual val isRemoved: Boolean get() = next is Removed
94
95
95
96
// LINEARIZABLE. Returns Node | Removed
96
- public val next: Any get() {
97
+ // Returns null for the disposed node on Kotlin/Native
98
+ public val next: Any? get() {
97
99
_next .loop { next ->
98
100
if (next !is OpDescriptor ) return next
99
101
next.perform(this )
100
102
}
101
103
}
102
104
103
105
// LINEARIZABLE. Returns next non-removed Node
104
- public actual val nextNode: Node get() = next.unwrap()
106
+ public actual val nextNode: Node get() = next!! .unwrap()
105
107
106
108
// LINEARIZABLE. Returns Node | Removed
107
- public val prev: Any get() {
109
+ // Returns null for the disposed node on Kotlin/Native
110
+ public val prev: Any? get() {
108
111
_prev .loop { prev ->
109
- if (prev is Removed ) return prev
112
+ if (prev is Removed ? ) return prev
110
113
prev as Node // otherwise, it can be only node
111
114
if (prev.next == = this ) return prev
112
115
correctPrev(prev, null )
113
116
}
114
117
}
115
118
116
119
// LINEARIZABLE. Returns prev non-removed Node
117
- public actual val prevNode: Node get() = prev.unwrap()
120
+ public actual val prevNode: Node get() = prev!! .unwrap()
118
121
119
122
// ------ addOneIfEmpty ------
120
123
@@ -152,7 +155,8 @@ public actual open class LockFreeLinkedListNode {
152
155
public actual inline fun addLastIf (node : Node , crossinline condition : () -> Boolean ): Boolean {
153
156
val condAdd = makeCondAddOp(node, condition)
154
157
while (true ) { // lock-free loop on prev.next
155
- val prev = prev as Node // sentinel node is never removed, so prev is always defined
158
+ // sentinel node is never removed, so prev is always defined, but can be concurrently disposed on Kotlin/Native
159
+ val prev = prev as Node ? ? : return false
156
160
when (prev.tryCondAddNext(node, this , condAdd)) {
157
161
SUCCESS -> return true
158
162
FAILURE -> return false
@@ -243,7 +247,7 @@ public actual open class LockFreeLinkedListNode {
243
247
public actual open fun remove (): Boolean {
244
248
while (true ) { // lock-free loop on next
245
249
val next = this .next
246
- if (next is Removed ) return false // was already removed -- don't try to help (original thread will take care)
250
+ if (next is Removed ? ) return false // was already removed -- don't try to help (original thread will take care)
247
251
if (next == = this ) return false // was not even added
248
252
val removed = (next as Node ).removed()
249
253
if (_next .compareAndSet(next, removed)) {
@@ -469,6 +473,7 @@ public actual open class LockFreeLinkedListNode {
469
473
continue // and retry
470
474
}
471
475
// next: Node | Removed
476
+ next as Any
472
477
val failure = failure(affected)
473
478
if (failure != null ) return failure // signal failure
474
479
if (retry(affected, next)) continue // retry operation
@@ -539,7 +544,8 @@ public actual open class LockFreeLinkedListNode {
539
544
540
545
private fun finishRemove (next : Node ) {
541
546
helpDelete()
542
- next.correctPrev(_prev .value.unwrap(), null )
547
+ val prev = _prev .value ? : return
548
+ next.correctPrev(prev.unwrap(), null )
543
549
}
544
550
545
551
private fun markPrev (): Node {
@@ -592,22 +598,22 @@ public actual open class LockFreeLinkedListNode {
592
598
var next: Node = (this ._next .value as Removed ).ref
593
599
while (true ) {
594
600
// move to the right until first non-removed node
595
- val nextNext = next.next
601
+ val nextNext = next.next ? : return
596
602
if (nextNext is Removed ) {
597
603
next.markPrev()
598
604
next = nextNext.ref
599
605
continue
600
606
}
601
607
// move the the left until first non-removed node
602
- val prevNext = prev.next
608
+ val prevNext = prev.next ? : return
603
609
if (prevNext is Removed ) {
604
610
if (last != null ) {
605
611
prev.markPrev()
606
612
last._next .compareAndSet(prev, prevNext.ref)
607
613
prev = last
608
614
last = null
609
615
} else {
610
- prev = prev._prev .value.unwrap()
616
+ prev = ( prev._prev .value ? : return ) .unwrap()
611
617
}
612
618
continue
613
619
}
@@ -644,11 +650,11 @@ public actual open class LockFreeLinkedListNode {
644
650
prev = last
645
651
last = null
646
652
} else {
647
- prev = prev._prev .value.unwrap()
653
+ prev = ( prev._prev .value ? : return null ) .unwrap()
648
654
}
649
655
continue
650
656
}
651
- val oldPrev = this ._prev .value
657
+ val oldPrev = this ._prev .value ? : return null
652
658
if (oldPrev is Removed ) return null // this node was removed, too -- its remover will take care
653
659
if (prevNext != = this ) {
654
660
// need to fixup next
@@ -671,17 +677,12 @@ public actual open class LockFreeLinkedListNode {
671
677
/* *
672
678
* Only needed on Kotlin/Native. See [disposeLockFreeLinkedList].
673
679
*/
674
- internal fun unlinkRefs (nullRef : Node ) {
675
- _next .value = nullRef
676
- _prev .value = nullRef
677
- _removedRef .value = nullRef.removed()
680
+ internal fun unlinkRefs (last : Boolean ) {
681
+ if (last) _next .value = null
682
+ _prev .value = null
683
+ _removedRef .value = null
678
684
}
679
685
680
- /* *
681
- * Only needed on Kotlin/Native. See [disposeLockFreeLinkedList].
682
- */
683
- internal fun initRemoved () { removed() }
684
-
685
686
override fun toString (): String = " $classSimpleName @$hexAddress "
686
687
}
687
688
@@ -704,10 +705,10 @@ public actual open class LockFreeLinkedListHead : LockFreeLinkedListNode() {
704
705
* Iterates over all elements in this list of a specified type.
705
706
*/
706
707
public actual inline fun <reified T : Node > forEach (block : (T ) -> Unit ) {
707
- var cur: Node = next as Node
708
- while (cur != this ) {
708
+ var cur: Node ? = next as Node ?
709
+ while (cur != this && cur != null ) {
709
710
if (cur is T ) block(cur)
710
- cur = cur.nextNode
711
+ cur = cur.next?.unwrap()
711
712
}
712
713
}
713
714
0 commit comments