@@ -690,11 +690,10 @@ internal open class JobSupport constructor(active: Boolean) : Job, SelectClause0
690
690
}
691
691
is Incomplete -> {
692
692
// Not yet finishing -- try to make it failing
693
- val list = tryPromoteToList(state) ? : return @loopOnState
694
693
val causeException = causeExceptionCache ? : createCauseException(cause).also { causeExceptionCache = it }
695
694
if (state.isActive) {
696
695
// active state becomes failing
697
- if (tryMakeFailing(state, list, causeException, cancel)) return true
696
+ if (tryMakeFailing(state, causeException, cancel)) return true
698
697
} else {
699
698
// non active state starts completing
700
699
when (tryMakeCompleting(state, createFailure(causeException, cancel), mode = MODE_ATOMIC_DEFAULT )) {
@@ -710,19 +709,26 @@ internal open class JobSupport constructor(active: Boolean) : Job, SelectClause0
710
709
}
711
710
}
712
711
713
- // Performs promotion of incomplete coroutine state to NodeList, returns null when need to retry
714
- private fun tryPromoteToList (state : Incomplete ): NodeList ? = state.list ? : null .also {
712
+ // Performs promotion of incomplete coroutine state to NodeList for the purpose of
713
+ // converting coroutine state to Failing, returns null when need to retry
714
+ private fun getOrPromoteFailingList (state : Incomplete ): NodeList ? = state.list ? :
715
715
when (state) {
716
- is Empty -> promoteEmptyToNodeList(state)
717
- is JobNode <* > -> promoteSingleToNodeList(state)
716
+ is Empty -> NodeList () // we can allocate new empty list that'll get integrated into Failing state
717
+ is JobNode <* > -> {
718
+ // SINGLE/SINGLE+ must be promoted to NodeList first, because otherwise we cannot
719
+ // correctly capture a reference to it
720
+ promoteSingleToNodeList(state)
721
+ null // retry
722
+ }
718
723
else -> error(" State should have list: $state " )
719
724
}
720
- }
721
725
722
726
// try make new failing state on the condition that we're still in the expected state
723
- private fun tryMakeFailing (state : Incomplete , list : NodeList , rootCause : Throwable , cancel : Boolean ): Boolean {
727
+ private fun tryMakeFailing (state : Incomplete , rootCause : Throwable , cancel : Boolean ): Boolean {
724
728
check(state !is Finishing ) // only for non-finishing states
725
729
check(state.isActive) // only for active states
730
+ // get state's list or else promote to list to correctly operate on child lists
731
+ val list = getOrPromoteFailingList(state) ? : return false
726
732
// Create failing state (with rootCause!)
727
733
val failing = Finishing (list, cancel, false , rootCause)
728
734
if (! _state .compareAndSet(state, failing)) return false
@@ -782,7 +788,7 @@ internal open class JobSupport constructor(active: Boolean) : Job, SelectClause0
782
788
return COMPLETING_COMPLETED
783
789
}
784
790
// get state's list or else promote to list to correctly operate on child lists
785
- val list = tryPromoteToList (state) ? : return COMPLETING_RETRY
791
+ val list = getOrPromoteFailingList (state) ? : return COMPLETING_RETRY
786
792
// promote to Finishing state if we are not in it yet
787
793
// This promotion has to be atomic w.r.t to state change, so that a coroutine that is not active yet
788
794
// atomically transition to finishing & completing state
0 commit comments