Created
November 18, 2020 13:21
-
-
Save elizarov/2de3bf1131bc65608836d11e07731819 to your computer and use it in GitHub Desktop.
Dump cycles for kotinx-coroutines 1.4.1 running on Kotlin 1.4.20
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: kotlinx-coroutines-core/concurrent/src/internal/LockFreeLinkedList.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/concurrent/src/internal/LockFreeLinkedList.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/concurrent/src/internal/LockFreeLinkedList.kt (date 1605704376180) | |
@@ -62,12 +62,19 @@ | |
*/ | |
@Suppress("LeakingThis") | |
@InternalCoroutinesApi | |
-public actual open class LockFreeLinkedListNode { | |
+public actual open class LockFreeLinkedListNode : Dump { | |
// those _next & _prev refs can be null on Kotlin/Native when doubly-linked list is unlinked | |
private val _next = atomic<Any?>(this) // Node | Removed | OpDescriptor | |
private val _prev = atomic<Node?>(this) // Node to the left (cannot be marked as removed) | |
private val _removedRef = atomic<Removed?>(null) // lazily cached removed ref to this | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ seen.dumpField("prev", _prev.value) | |
+ seen.dumpField("next", _next.value) | |
+ } | |
+ | |
+ open fun dumpNode(seen: ArrayList<Any>) {} | |
+ | |
private fun removed(): Removed = | |
_removedRef.value ?: Removed(this).also { | |
storeCyclicRef { _removedRef.lazySet(it) } | |
@@ -374,10 +381,17 @@ | |
public open class RemoveFirstDesc<T>( | |
@JvmField val queue: Node | |
- ) : AbstractAtomicDesc() { | |
+ ) : AbstractAtomicDesc(), Dump { | |
private val _affectedNode = atomic<Node?>(null) | |
private val _originalNext = atomic<Node?>(null) | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ seen.dumpField("atomicOp", atomicOp) | |
+ seen.dumpField("affectedNode", _affectedNode.value) | |
+ seen.dumpField("originalNext", _originalNext.value) | |
+ seen.dumpField("queue", queue) | |
+ } | |
+ | |
@Suppress("UNCHECKED_CAST") | |
public val result: T get() = affectedNode!! as T | |
@@ -657,10 +671,14 @@ | |
override fun toString(): String = "$classSimpleName@$hexAddress" | |
} | |
-private class Removed(ref: Node) { | |
+private class Removed(ref: Node) : Dump { | |
private val wRef: Any = ref.weakRef() | |
val ref: Node? get() = wRef.unweakRef() as Node? | |
override fun toString(): String = "Removed[$ref]" | |
+ | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ ref?.dump(seen) | |
+ } | |
} | |
@PublishedApi | |
Index: kotlinx-coroutines-core/common/src/CancellableContinuation.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/common/src/CancellableContinuation.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/common/src/CancellableContinuation.kt (date 1605702588076) | |
@@ -382,7 +382,11 @@ | |
override fun toString() = "RemoveOnCancel[$node]" | |
} | |
-private class DisposeOnCancel(private val handle: DisposableHandle) : CancelHandler() { | |
+private class DisposeOnCancel(private val handle: DisposableHandle) : CancelHandler(), Dump { | |
override fun invoke(cause: Throwable?) = handle.dispose() | |
override fun toString(): String = "DisposeOnCancel[$handle]" | |
+ | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ seen.dumpField("handle", handle) | |
+ } | |
} | |
Index: kotlinx-coroutines-core/native/src/channels/ArrayBufferState.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/native/src/channels/ArrayBufferState.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/native/src/channels/ArrayBufferState.kt (date 1605704376184) | |
@@ -6,11 +6,17 @@ | |
import kotlinx.atomicfu.* | |
import kotlinx.atomicfu.locks.* | |
+import kotlinx.coroutines.internal.* | |
-internal actual open class ArrayBufferState actual constructor(initialBufferSize: Int) : SynchronizedObject() { | |
+internal actual open class ArrayBufferState actual constructor(initialBufferSize: Int) : SynchronizedObject(), Dump { | |
protected val _buffer = atomic(atomicArrayOfNulls<Any?>(initialBufferSize)) | |
protected val _bufferSize = atomic(initialBufferSize) | |
+ | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ seen.dumpField("buffer", _buffer.value) | |
+ } | |
+ | |
actual val bufferSize: Int | |
get() = _bufferSize.value | |
Index: kotlinx-coroutines-core/common/src/selects/Select.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/common/src/selects/Select.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/common/src/selects/Select.kt (date 1605704376125) | |
@@ -235,7 +235,7 @@ | |
internal class SelectBuilderImpl<in R>( | |
uCont: Continuation<R> | |
) : LockFreeLinkedListHead(), SelectBuilder<R>, | |
- SelectInstance<R>, Continuation<R>, CoroutineStackFrame | |
+ SelectInstance<R>, Continuation<R>, CoroutineStackFrame, Dump | |
{ | |
private val uCont: Continuation<R> = uCont.asShareable() // unintercepted delegate continuation, shareable | |
@@ -256,6 +256,13 @@ | |
get() = _parentHandle.value | |
set(value) { _parentHandle.value = value } | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ super<LockFreeLinkedListHead>.dumpImpl(seen) | |
+ seen.dumpField("state", _state.value) | |
+ seen.dumpField("result", _result.value) | |
+ seen.dumpField("parentHandle", _parentHandle.value) | |
+ } | |
+ | |
/* Result state machine | |
+-----------+ getResult +---------------------+ resume +---------+ | |
@@ -341,6 +348,14 @@ | |
if (trySelect()) | |
resumeSelectWithException(job.getCancellationException()) | |
} | |
+ override fun toString(): String = "SelectOnCancelling[${this@SelectBuilderImpl}]" | |
+ | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ super.dumpImpl(seen) | |
+ val p = seen.dumpPrefix() | |
+ println("$p impl: ${this@SelectBuilderImpl}") | |
+ this@SelectBuilderImpl.dump(seen) | |
+ } | |
} | |
@PublishedApi | |
@@ -571,10 +586,15 @@ | |
private class AtomicSelectOp( | |
@JvmField val impl: SelectBuilderImpl<*>, | |
@JvmField val desc: AtomicDesc | |
- ) : AtomicOp<Any?>() { | |
+ ) : AtomicOp<Any?>(), Dump { | |
// all select operations are totally ordered by their creating time using selectOpSequenceNumber | |
override val opSequence = selectOpSequenceNumber.next() | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ seen.dumpField("impl", impl) | |
+ seen.dumpField("desc", desc) | |
+ } | |
+ | |
init { | |
desc.atomicOp = this | |
} | |
@@ -660,9 +680,14 @@ | |
private class DisposeNode( | |
handle: DisposableHandle | |
- ) : LockFreeLinkedListNode() { | |
+ ) : LockFreeLinkedListNode(), Dump { | |
private val _handle = atomic<DisposableHandle?>(handle) | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ super<LockFreeLinkedListNode>.dumpImpl(seen) | |
+ seen.dumpField("handle", _handle) | |
+ } | |
+ | |
fun dispose() { | |
val handle = _handle.getAndSet(null) | |
handle?.dispose() | |
Index: kotlinx-coroutines-core/common/src/channels/ArrayBroadcastChannel.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/common/src/channels/ArrayBroadcastChannel.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/common/src/channels/ArrayBroadcastChannel.kt (date 1605704376114) | |
@@ -42,6 +42,12 @@ | |
*/ | |
private val state = ArrayBufferState(capacity) | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ super.dumpImpl(seen) | |
+ seen.dumpField("state", state) | |
+ seen.dumpField("subscribers", subscribers) | |
+ } | |
+ | |
// head & tail are Long (64 bits) and we assume that they never wrap around | |
// head, tail, and size are guarded by bufferLock | |
@@ -207,6 +213,12 @@ | |
) : AbstractChannel<E>(null), ReceiveChannel<E> { | |
private val subLock = reentrantLock() | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ super.dumpImpl(seen) | |
+ seen.dumpField("broadcastChannel", broadcastChannel) | |
+ seen.dumpField("subLock", subLock) | |
+ } | |
+ | |
private val _subHead = atomic(0L) | |
var subHead: Long // guarded by subLock | |
get() = _subHead.value | |
Index: kotlinx-coroutines-core/native/src/internal/CopyOnWriteList.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/native/src/internal/CopyOnWriteList.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/native/src/internal/CopyOnWriteList.kt (date 1605704376186) | |
@@ -7,7 +7,11 @@ | |
import kotlinx.atomicfu.* | |
@Suppress("UNCHECKED_CAST") | |
-internal class CopyOnWriteList<E>() : AbstractMutableList<E>() { | |
+internal class CopyOnWriteList<E>() : AbstractMutableList<E>(), Dump { | |
+ | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ seen.dumpField("array", _array.value) | |
+ } | |
private val _array = atomic<Array<Any?>>(arrayOfNulls<Any?>(0)) | |
private var array: Array<Any?> | |
Index: kotlinx-coroutines-core/common/src/AbstractCoroutine.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/common/src/AbstractCoroutine.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/common/src/AbstractCoroutine.kt (date 1605703019482) | |
@@ -7,6 +7,7 @@ | |
import kotlinx.coroutines.CoroutineStart.* | |
import kotlinx.coroutines.intrinsics.* | |
+import kotlinx.coroutines.internal.* | |
import kotlin.coroutines.* | |
import kotlin.jvm.* | |
@@ -40,6 +41,11 @@ | |
protected val parentContext: CoroutineContext, | |
active: Boolean = true | |
) : JobSupport(active), Job, Continuation<T>, CoroutineScope { | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ super.dumpImpl(seen) | |
+ seen.dumpField("parentContext", parentContext) | |
+ } | |
+ | |
/** | |
* The context of this coroutine that includes this coroutine as a [Job]. | |
*/ | |
Index: kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt (date 1605704376111) | |
@@ -18,10 +18,14 @@ | |
*/ | |
internal abstract class AbstractSendChannel<E>( | |
@JvmField protected val onUndeliveredElement: OnUndeliveredElement<E>? | |
-) : SendChannel<E> { | |
+) : SendChannel<E>, Dump { | |
/** @suppress **This is unstable API and it is subject to change.** */ | |
protected val queue = LockFreeLinkedListHead() | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ seen.dumpField("queue", queue) | |
+ } | |
+ | |
// ------ extension points for buffered channels ------ | |
/** | |
@@ -992,9 +996,16 @@ | |
@JvmField val select: SelectInstance<R>, | |
block: suspend (Any?) -> R, | |
@JvmField val receiveMode: Int | |
- ) : Receive<E>(), DisposableHandle { | |
+ ) : Receive<E>(), DisposableHandle, Dump { | |
@JvmField val block: suspend (Any?) -> R = block.asShareable() // captured variables in this block need screening | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ super<Receive>.dumpImpl(seen) | |
+ seen.dumpField("channel", channel) | |
+ seen.dumpField("select", select) | |
+ seen.dumpField("block", block) | |
+ } | |
+ | |
override fun tryResumeReceive(value: E, otherOp: PrepareOp?): Symbol? = | |
select.trySelectOther(otherOp) as Symbol? | |
@@ -1098,6 +1109,12 @@ | |
private val _cont = atomic<CancellableContinuation<Unit>?>(cont) | |
protected val cont get() = _cont.value!! | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ super.dumpImpl(seen) | |
+ seen.dumpField("pollResult", pollResult) | |
+ seen.dumpField("cont", _cont) | |
+ } | |
+ | |
override fun tryResumeSend(otherOp: PrepareOp?): Symbol? { | |
val token = _cont.value?.tryResume(Unit, otherOp?.desc) ?: return null | |
assert { token === RESUME_TOKEN } // the only other possible result | |
Index: kotlinx-coroutines-core/common/src/JobSupport.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/common/src/JobSupport.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/common/src/JobSupport.kt (date 1605704376167) | |
@@ -26,7 +26,7 @@ | |
* @suppress **This is unstable API and it is subject to change.** | |
*/ | |
@Deprecated(level = DeprecationLevel.ERROR, message = "This is internal API and may be removed in the future releases") | |
-public open class JobSupport constructor(active: Boolean) : Job, ChildJob, ParentJob, SelectClause0 { | |
+public open class JobSupport constructor(active: Boolean) : Job, ChildJob, ParentJob, SelectClause0, Dump { | |
final override val key: CoroutineContext.Key<*> get() = Job | |
/* | |
@@ -134,6 +134,11 @@ | |
get() = _parentHandle.value | |
set(value) { _parentHandle.value = value } | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ seen.dumpField("state", _state.value) | |
+ seen.dumpField("parentHandle", _parentHandle.value) | |
+ } | |
+ | |
// ------------ initialization ------------ | |
/** | |
@@ -1376,6 +1381,13 @@ | |
override val list: NodeList? get() = null | |
override fun dispose() = (job as JobSupport).removeNode(this) | |
override fun toString() = "$classSimpleName@$hexAddress[job@${job.hexAddress}]" | |
+ | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ super.dumpImpl(seen) | |
+ seen.dumpField("job", job) | |
+ seen.dumpField("isActive", isActive) | |
+ seen.dumpField("list", list) | |
+ } | |
} | |
internal class NodeList : LockFreeLinkedListHead(), Incomplete { | |
@@ -1491,6 +1503,12 @@ | |
) : JobCancellingNode<JobSupport>(parent), ChildHandle { | |
override fun invoke(cause: Throwable?) = childJob.parentCancelled(job) | |
override fun childCancelled(cause: Throwable): Boolean = job.childCancelled(cause) | |
+ override fun toString(): String = "ChildHandle[$childJob]" | |
+ | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ super.dumpImpl(seen) | |
+ seen.dumpField("childJob", childJob) | |
+ } | |
} | |
// Same as ChildHandleNode, but for cancellable continuation | |
Index: kotlinx-coroutines-core/nativeDarwin/test/Launcher.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/nativeDarwin/test/Launcher.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/nativeDarwin/test/Launcher.kt (date 1605704376182) | |
@@ -4,8 +4,10 @@ | |
package kotlinx.coroutines | |
+import kotlinx.coroutines.internal.* | |
import platform.CoreFoundation.* | |
import kotlin.native.concurrent.* | |
+import kotlin.native.internal.* | |
import kotlin.native.internal.test.* | |
import kotlin.system.* | |
@@ -26,5 +28,17 @@ | |
testLauncherEntryPoint(args) | |
mainThread.shutdown() | |
DefaultDispatcher.shutdown() | |
+ printCycles() | |
+ } | |
+} | |
+ | |
+private fun printCycles() { | |
+ GC.collect() | |
+ GC.detectCycles()?.let { cycles -> | |
+ println("!!! Detected ${cycles.size} cycles") | |
+ for (cycle in cycles) { | |
+ println("Cycle: $cycle") | |
+ if (cycle is FreezableAtomicReference<*>) cycle.value.dump(ArrayList()) | |
+ } | |
} | |
} | |
\ No newline at end of file | |
Index: kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt (date 1605704376139) | |
@@ -26,11 +26,10 @@ | |
internal open class CancellableContinuationImpl<in T>( | |
delegate: Continuation<T>, | |
resumeMode: Int | |
-) : DispatchedTask<T>(resumeMode), CancellableContinuation<T>, CoroutineStackFrame { | |
+) : DispatchedTask<T>(resumeMode), CancellableContinuation<T>, CoroutineStackFrame, Dump { | |
init { | |
assert { resumeMode != MODE_UNINITIALIZED } // invalid mode for CancellableContinuationImpl | |
} | |
- | |
@PublishedApi // for Kotlin/Native | |
final override val delegate: Continuation<T> = delegate.asShareable() | |
public override val context: CoroutineContext = delegate.context | |
@@ -79,6 +78,12 @@ | |
get() = _parentHandle.value | |
set(value) { _parentHandle.value = value } | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ seen.dumpField("decision", _decision.value) | |
+ seen.dumpField("state", _state.value) | |
+ seen.dumpField("parentHandle", _parentHandle.value) | |
+ } | |
+ | |
internal val state: Any? get() = _state.value | |
public override val isActive: Boolean get() = state is NotCompleted | |
@@ -558,7 +563,17 @@ | |
@JvmField val onCancellation: ((cause: Throwable) -> Unit)? = null, // installed via resume block | |
@JvmField val idempotentResume: Any? = null, | |
@JvmField val cancelCause: Throwable? = null | |
-) { | |
+) : Dump { | |
+ override fun dumpImpl(seen: ArrayList<Any>) { | |
+ val p = seen.dumpPrefix() | |
+ println("$p CompletedContinuation@$hexAddress") | |
+ seen.dumpField("result", result) | |
+ seen.dumpField("cancelHandler", cancelHandler) | |
+ seen.dumpField("onCancellation", onCancellation) | |
+ seen.dumpField("idempotentResume", idempotentResume) | |
+ seen.dumpField("cancelCause", cancelCause) | |
+ } | |
+ | |
val cancelled: Boolean get() = cancelCause != null | |
fun invokeHandlers(cont: CancellableContinuationImpl<*>, cause: Throwable) { | |
Index: kotlinx-coroutines-core/common/src/internal/LockFreeLinkedList.common.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/common/src/internal/LockFreeLinkedList.common.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/common/src/internal/LockFreeLinkedList.common.kt (date 1605704376120) | |
@@ -9,7 +9,7 @@ | |
import kotlin.native.concurrent.* | |
/** @suppress **This is unstable API and it is subject to change.** */ | |
-public expect open class LockFreeLinkedListNode() { | |
+public expect open class LockFreeLinkedListNode() : Dump { | |
public val isRemoved: Boolean | |
public val nextNode: LockFreeLinkedListNode | |
public val prevNode: LockFreeLinkedListNode | |
Index: kotlinx-coroutines-core/common/src/internal/Dump.kt | |
=================================================================== | |
--- kotlinx-coroutines-core/common/src/internal/Dump.kt (date 1605704376118) | |
+++ kotlinx-coroutines-core/common/src/internal/Dump.kt (date 1605704376118) | |
@@ -0,0 +1,62 @@ | |
+/* | |
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. | |
+ */ | |
+ | |
+package kotlinx.coroutines.internal | |
+ | |
+import kotlin.coroutines.* | |
+ | |
+ | |
+public interface Dump { | |
+ public fun dump(seen: ArrayList<Any>) { | |
+ wrapDump(seen) { dumpImpl(seen) } | |
+ } | |
+ | |
+ public fun dumpImpl(seen: ArrayList<Any>) {} | |
+} | |
+ | |
+private inline fun Any.wrapDump(seen: ArrayList<Any>, block: () -> Unit) { | |
+ if (cycle(seen)) return | |
+ seen.add(this) | |
+ block() | |
+ seen.removeAt(seen.lastIndex) | |
+} | |
+ | |
+public fun ArrayList<Any>.dumpPrefix(): String = " ".repeat(4 * size) | |
+ | |
+public fun ArrayList<Any>.dumpField(name: String, value: Any?) { | |
+ println("${dumpPrefix()} $name: $value") | |
+ value.dump(this) | |
+} | |
+ | |
+public fun Any?.dump(seen: ArrayList<Any>) { | |
+ when (this) { | |
+ is Dump -> dump(seen) | |
+ is Array<*> -> dump(seen) | |
+ is CoroutineContext -> dump(seen) | |
+ } | |
+} | |
+ | |
+public fun Array<*>.dump(seen: ArrayList<Any>) { | |
+ wrapDump(seen) { | |
+ for (i in indices) seen.dumpField("[$i]", get(i)) | |
+ } | |
+} | |
+ | |
+public fun CoroutineContext.dump(seen: ArrayList<Any>) { | |
+ wrapDump(seen) { | |
+ fold(Unit) { _, element -> | |
+ if (element is Dump) element.dump(seen) | |
+ } | |
+ } | |
+} | |
+ | |
+private fun Any.cycle(seen: ArrayList<Any>): Boolean { | |
+ for ((i, ref) in seen.withIndex()) { | |
+ if (ref === this) { | |
+ println("${seen.dumpPrefix()} !!! CYCLE to #$i: $ref") | |
+ return true | |
+ } | |
+ } | |
+ return false | |
+} | |
Index: kotlinx-coroutines-core/jvm/src/Builders.kt | |
IDEA additional info: | |
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP | |
<+>UTF-8 | |
=================================================================== | |
--- kotlinx-coroutines-core/jvm/src/Builders.kt (revision 4dd4e59f6676a45499cd193aa8fd9521013f8a3f) | |
+++ kotlinx-coroutines-core/jvm/src/Builders.kt (date 1605703482678) | |
@@ -8,6 +8,7 @@ | |
package kotlinx.coroutines | |
+import kotlinx.coroutines.internal.* | |
import kotlinx.coroutines.intrinsics.* | |
import java.util.concurrent.locks.* | |
import kotlin.contracts.* | |
@@ -66,6 +67,12 @@ | |
private val blockedThread: Thread, | |
private val eventLoop: EventLoop? | |
) : AbstractCoroutine<T>(parentContext, true) { | |
+ fun dumpImpl(seen: ArrayList<Any>) { | |
+ super.dumpImpl(seen) | |
+ seen.dumpField("blockedThread", blockedThread) | |
+ seen.dumpField("eventLoop", eventLoop) | |
+ } | |
+ | |
override val isScopedCoroutine: Boolean get() = true | |
override fun afterCompletion(state: Any?) { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment