diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-debug.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-debug.txt index 604e6cd253..79f5b75d15 100644 --- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-debug.txt +++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-debug.txt @@ -1,13 +1,9 @@ public final class kotlinx/coroutines/debug/CoroutineInfo { - public final fun component1 ()Lkotlin/coroutines/CoroutineContext; - public final fun copy (Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/jvm/internal/CoroutineStackFrame;J)Lkotlinx/coroutines/debug/CoroutineInfo; - public static synthetic fun copy$default (Lkotlinx/coroutines/debug/CoroutineInfo;Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/jvm/internal/CoroutineStackFrame;JILjava/lang/Object;)Lkotlinx/coroutines/debug/CoroutineInfo; - public fun equals (Ljava/lang/Object;)Z + public final fun copy ()Lkotlinx/coroutines/debug/CoroutineInfo; public final fun getContext ()Lkotlin/coroutines/CoroutineContext; public final fun getCreationStackTrace ()Ljava/util/List; public final fun getJob ()Lkotlinx/coroutines/Job; public final fun getState ()Lkotlinx/coroutines/debug/State; - public fun hashCode ()I public final fun lastObservedStackTrace ()Ljava/util/List; public fun toString ()Ljava/lang/String; } diff --git a/kotlinx-coroutines-debug/src/CoroutineInfo.kt b/kotlinx-coroutines-debug/src/CoroutineInfo.kt index 56f391a203..84cd9f370e 100644 --- a/kotlinx-coroutines-debug/src/CoroutineInfo.kt +++ b/kotlinx-coroutines-debug/src/CoroutineInfo.kt @@ -14,7 +14,7 @@ import kotlin.coroutines.jvm.internal.* * Class describing coroutine info such as its context, state and stacktrace. */ @ExperimentalCoroutinesApi -public data class CoroutineInfo internal constructor( +public class CoroutineInfo internal constructor( val context: CoroutineContext, private val creationStackBottom: CoroutineStackFrame, @JvmField internal val sequenceNumber: Long @@ -44,14 +44,10 @@ public data class CoroutineInfo internal constructor( @JvmField internal var lastObservedFrame: CoroutineStackFrame? = null - // Copy constructor - internal constructor(coroutine: Continuation<*>, state: CoroutineInfo) : this( - coroutine.context, - state.creationStackBottom, - state.sequenceNumber - ) { - _state = state.state - this.lastObservedFrame = state.lastObservedFrame + public fun copy(): CoroutineInfo = CoroutineInfo(context, creationStackBottom, sequenceNumber).also { + it._state = _state + it.lastObservedFrame = lastObservedFrame + it.lastObservedThread = lastObservedThread } /** @@ -94,6 +90,8 @@ public data class CoroutineInfo internal constructor( lastObservedThread = null } } + + override fun toString(): String = "CoroutineInfo(state=$state,context=$context)" } /** diff --git a/kotlinx-coroutines-debug/src/internal/DebugProbesImpl.kt b/kotlinx-coroutines-debug/src/internal/DebugProbesImpl.kt index 29b1e36e09..b8b01c3587 100644 --- a/kotlinx-coroutines-debug/src/internal/DebugProbesImpl.kt +++ b/kotlinx-coroutines-debug/src/internal/DebugProbesImpl.kt @@ -80,7 +80,7 @@ internal object DebugProbesImpl { check(isInstalled) { "Debug probes are not installed" } val jobToStack = capturedCoroutines .filter { it.delegate.context[Job] != null } - .associateBy({ it.delegate.context[Job]!! }, {it.info}) + .associateBy({ it.delegate.context[Job]!! }, { it.info }) return buildString { job.build(jobToStack, this, "") } @@ -118,7 +118,7 @@ internal object DebugProbesImpl { public fun dumpCoroutinesInfo(): List { check(isInstalled) { "Debug probes are not installed" } return capturedCoroutines.asSequence() - .map { CoroutineInfo(it.delegate, it.info) } + .map { it.info.copy() } // Copy as CoroutineInfo can be mutated concurrently by DebugProbes .sortedBy { it.sequenceNumber } .toList() } @@ -373,7 +373,7 @@ internal object DebugProbesImpl { private fun sanitizeStackTrace(throwable: T): List { val stackTrace = throwable.stackTrace val size = stackTrace.size - val probeIndex = stackTrace.indexOfLast { it.className == "kotlin.coroutines.jvm.internal.DebugProbesKt" } + val probeIndex = stackTrace.indexOfLast { it.className == "kotlin.coroutines.jvm.internal.DebugProbesKt" } if (!DebugProbes.sanitizeStackTraces) { return List(size - probeIndex) { diff --git a/kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt b/kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt index 3ccbe0ae00..c15fe89487 100644 --- a/kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt +++ b/kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt @@ -167,4 +167,15 @@ class RunningThreadStackMergeTest : DebugTestBase() { yield() assertTrue(true) } + + @Test + fun testActiveThread() = runBlocking { + launchCoroutine() + awaitCoroutineStarted() + val info = DebugProbes.dumpCoroutinesInfo().find { it.state == State.RUNNING } + assertNotNull(info) + @Suppress("INVISIBLE_MEMBER") // IDEA bug + assertNotNull(info.lastObservedThread) + coroutineBlocker.await() + } }