@@ -357,7 +357,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
357
357
358
358
private fun notifyHandlers (list : NodeList , permissionBitmask : Byte , cause : Throwable ? , predicate : (JobNode ) -> Boolean ) {
359
359
var exception: Throwable ? = null
360
- list.forEach(forbidBitmask = permissionBitmask) { node ->
360
+ list.forEach(forbidBitmask = permissionBitmask) { node, _, _ ->
361
361
if (node is JobNode && predicate(node)) {
362
362
try {
363
363
node.invoke(cause)
@@ -558,7 +558,10 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
558
558
559
559
private fun promoteSingleToNodeList (state : JobNode ) {
560
560
// try to promote it to list (SINGLE+ state)
561
- _state .compareAndSet(state, state.attachToList(NodeList ()))
561
+ val list = NodeList ()
562
+ val address = list.addLastWithoutModifying(state, permissionsBitmask = 0 )
563
+ assert { address == 0L }
564
+ _state .compareAndSet(state, list)
562
565
}
563
566
564
567
public final override suspend fun join () {
@@ -621,7 +624,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
621
624
}
622
625
is Incomplete -> { // may have a list of completion handlers
623
626
// remove node from the list if there is a list
624
- if ( state.list != null ) node .remove()
627
+ state.list? .remove(node )
625
628
return
626
629
}
627
630
else -> return // it is complete and does not have any completion handlers
@@ -932,39 +935,52 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
932
935
private val Any? .exceptionOrNull: Throwable ?
933
936
get() = (this as ? CompletedExceptionally )?.cause
934
937
935
- private fun shouldWaitForChildren (state : Finishing , proposedUpdate : Any? , suggestedStart : ChildHandleNode ? = null): Boolean {
938
+ private fun shouldWaitForChildren (
939
+ state : Finishing ,
940
+ proposedUpdate : Any? ,
941
+ suggestedStartSegment : LockFreeLinkedListSegment ? = null,
942
+ suggestedStartIndex : Int? = null
943
+ ): Boolean {
936
944
val list = state.list
937
- fun tryFindChildren (suggestedStart : ChildHandleNode ? , closeList : Boolean ): Boolean {
938
- var startAfter: ChildHandleNode ? = suggestedStart
945
+ fun tryFindChildren (
946
+ closeList : Boolean ,
947
+ suggestedStartSegment : LockFreeLinkedListSegment ? = null,
948
+ suggestedStartIndex : Int? = null,
949
+ ): Boolean {
950
+ var startSegment = suggestedStartSegment
951
+ var startIndex = suggestedStartIndex
939
952
while (true ) {
940
953
val child = run {
941
- list.forEach(forbidBitmask = if (closeList) LIST_CHILD_PERMISSION else 0 , startAfter = startAfter) {
942
- if (it is ChildHandleNode ) return @run it
954
+ list.forEach(forbidBitmask = if (closeList) LIST_CHILD_PERMISSION else 0 , startInSegment = startSegment, startAfterIndex = startIndex) { node, segment, indexInSegment ->
955
+ if (node is ChildHandleNode ) {
956
+ startSegment = segment
957
+ startIndex = indexInSegment
958
+ return @run node
959
+ }
943
960
}
944
961
null
945
962
} ? : break
946
963
val handle = child.childJob.invokeOnCompletion(
947
964
invokeImmediately = false ,
948
- handler = ChildCompletion (this , state, child , proposedUpdate)
965
+ handler = ChildCompletion (this , state, startSegment !! , startIndex !! , proposedUpdate)
949
966
)
950
967
if (handle != = NonDisposableHandle ) return true // child is not complete and we've started waiting for it
951
- startAfter = child
952
968
}
953
969
return false
954
970
}
955
971
// Look for children that are currently in the list after the suggested start node.
956
- if (tryFindChildren(suggestedStart = suggestedStart , closeList = false )) return true
972
+ if (tryFindChildren(suggestedStartSegment = suggestedStartSegment, suggestedStartIndex = suggestedStartIndex , closeList = false )) return true
957
973
// We didn't find anyone in the list after the suggested start node. Let's check the beginning now.
958
- if (suggestedStart != null && tryFindChildren(suggestedStart = null , closeList = false )) return true
974
+ if (suggestedStartSegment != null && tryFindChildren(closeList = false )) return true
959
975
// Now we know that, at the moment this function started, there were no more children.
960
976
// We can close the list for the new children, and if we still don't find any, we can be sure there are none.
961
- return tryFindChildren(suggestedStart = null , closeList = true )
977
+ return tryFindChildren(closeList = true )
962
978
}
963
979
964
980
// ## IMPORTANT INVARIANT: Only one thread can be concurrently invoking this method.
965
- private fun continueCompleting (state : Finishing , lastChild : ChildHandleNode , proposedUpdate : Any? ) {
981
+ private fun continueCompleting (state : Finishing , proposedUpdate : Any? , lastSegment : LockFreeLinkedListSegment , lastIndexInSegment : Int ) {
966
982
assert { this .state == = state } // consistency check -- it cannot change while we are waiting for children
967
- if (shouldWaitForChildren(state, proposedUpdate, suggestedStart = lastChild )) return // waiting for the next child
983
+ if (shouldWaitForChildren(state, proposedUpdate, suggestedStartSegment = lastSegment, suggestedStartIndex = lastIndexInSegment )) return // waiting for the next child
968
984
// no more children, now we are sure; try to update the state
969
985
val finalState = finalizeFinishingState(state, proposedUpdate)
970
986
afterCompletion(finalState)
@@ -974,7 +990,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
974
990
when (val state = this @JobSupport.state) {
975
991
is ChildHandleNode -> yield (state.childJob)
976
992
is Incomplete -> state.list?.let { list ->
977
- list.forEach { if (it is ChildHandleNode ) yield (it.childJob) }
993
+ list.forEach { it, _, _ -> if (it is ChildHandleNode ) yield (it.childJob) }
978
994
}
979
995
}
980
996
}
@@ -1232,11 +1248,12 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
1232
1248
private class ChildCompletion (
1233
1249
private val parent : JobSupport ,
1234
1250
private val state : Finishing ,
1235
- private val child : ChildHandleNode ,
1251
+ private val segment : LockFreeLinkedListSegment ,
1252
+ private val indexInSegment : Int ,
1236
1253
private val proposedUpdate : Any?
1237
1254
) : JobNode() {
1238
1255
override fun invoke (cause : Throwable ? ) {
1239
- parent.continueCompleting(state, child, proposedUpdate )
1256
+ parent.continueCompleting(state, proposedUpdate, lastSegment = segment, lastIndexInSegment = indexInSegment )
1240
1257
}
1241
1258
override val onCancelling: Boolean get() = false
1242
1259
}
@@ -1477,7 +1494,7 @@ internal class NodeList : LockFreeLinkedListHead(), Incomplete {
1477
1494
append(state)
1478
1495
append(" }[" )
1479
1496
var first = true
1480
- this @NodeList.forEach { node ->
1497
+ this @NodeList.forEach { node, _, _ ->
1481
1498
if (node is JobNode ) {
1482
1499
if (first) first = false else append(" , " )
1483
1500
append(node)
0 commit comments