Repository: Kotlin/kotlinx.coroutines
File: kotlinx-coroutines-core/common/src/JobSupport.kt (Kotlin)

Code before:
            }
        }
    }

    private fun makeNode(handler: CompletionHandler, onCancelling: Boolean): JobNode<*> {
        return if (onCancelling)
            (handler as? JobCancellingNode<*>)?.also { assert { it.job === this } }
                ?: InvokeOnCancelling(this, handler)
        else
            (handler as? JobNode<*>)?.also { assert { it.job === this && it !is JobCancellingNode } }
                ?: InvokeOnCompletion(this, handler)
    }

    private fun addLastAtomic(expect: Any, list: NodeList, node: JobNode<*>): Boolean {
        list.addLast(node)
        if (this.state === expect) return true
        node.dispose()
        return false
    }

    private fun promoteEmptyToNodeList(state: Empty) {
        // try to promote it to LIST state with the corresponding state
        val list = NodeList()
        val update = if (state.isActive) list else InactiveNodeList(list)
        _state.compareAndSet(state, update)
    }

    private fun promoteSingleToNodeList(state: JobNode<*>) {
        // try to promote it to list (SINGLE+ state)
        state.addOneIfEmpty(NodeList())
        // it must be in SINGLE+ state or state has changed (node could have need removed from state)
        val list = state.nextNode // either our NodeList or somebody else won the race, updated state
        // just attempt converting it to list if state is still the same, then we'll continue lock-free loop
        _state.compareAndSet(state, list)
    }

    public final override suspend fun join() {
        if (!joinInternal()) { // fast-path no wait
            coroutineContext.checkCompletion()
            return // do not suspend
        }
        return joinSuspend() // slow-path wait
    }

    private fun joinInternal(): Boolean {
        loopOnState { state ->
            if (state !is Incomplete) return false // not active anymore (complete) -- no need to wait
            if (startInternal(state) >= 0) return true // wait unless need to retry
        }
    }


Review comment (suggestion):
```suggestion
    private fun addLastAtomic(expectedState: Any, list: NodeList, node: JobNode<*>): Boolean {
        list.addLast(node)
        if (this.state === expectedState) return true
```

I think this naming is more explicit and avoids confusion with the `expect` soft keyword.

Code after:
                    }
                    if (rootCause != null) {
                        // Note: attachChild uses invokeImmediately, so it gets invoked when adding to cancelled job
                        if (invokeImmediately) {
                            node.invoke(rootCause)
                        }
                        return handle
                    } else {
                        if (!isNodeAdded) list.addLast(node)
                        if (this.state !== state) {
                            // Here again, we try to prevent concurrent finalization of the parent,
                            // if the parent fails to add ChildCompletion because the child changed it's state to Completed.
                            if (node is ChildCompletion && !node.markInvoked()) return node
                            // If the state has changed to Complete, the node can stay in the list, just retry.
                            if (this.state !is Incomplete) return@loopOnState
                            // If the state is Incomplete, set the flag that the node is already added to the list instead of removing it.
                            isNodeAdded = true
                        } else {
                            return node
                        }
                    }
                }
                else -> { // is complete
                    if (invokeImmediately) {
                        node.invoke((state as? CompletedExceptionally)?.cause)
                    }
                    return NonDisposableHandle
                }
            }
        }
    }

    private fun makeNode(handler: CompletionHandler, onCancelling: Boolean): JobNode {
        val node = if (onCancelling) {
            (handler as? JobCancellingNode)
                ?: InvokeOnCancelling(handler)
        } else {
            (handler as? JobNode)
                ?.also { assert { it !is JobCancellingNode } }
                ?: InvokeOnCompletion(handler)
        }
        node.job = this
        return node
    }

    private fun promoteEmptyToNodeList(state: Empty) {
        // try to promote it to LIST state with the corresponding state
        val list = NodeList()
        val update = if (state.isActive) list else InactiveNodeList(list)
        _state.compareAndSet(state, update)
    }