Skip to content

Commit 0172998

Browse files
authored
Fully copy CoroutineInfo for DebugProbes.dumpCoroutinesInfo, it is re… (#1368)
* Fully copy CoroutineInfo for DebugProbes.dumpCoroutinesInfo, it is required for IDEA integration (field is left as internal deliberately) * Make CoroutineInfo non-data class
1 parent 1dcfd97 commit 0172998

File tree

4 files changed

+22
-17
lines changed

4 files changed

+22
-17
lines changed

binary-compatibility-validator/reference-public-api/kotlinx-coroutines-debug.txt

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
public final class kotlinx/coroutines/debug/CoroutineInfo {
2-
public final fun component1 ()Lkotlin/coroutines/CoroutineContext;
3-
public final fun copy (Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/jvm/internal/CoroutineStackFrame;J)Lkotlinx/coroutines/debug/CoroutineInfo;
4-
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;
5-
public fun equals (Ljava/lang/Object;)Z
2+
public final fun copy ()Lkotlinx/coroutines/debug/CoroutineInfo;
63
public final fun getContext ()Lkotlin/coroutines/CoroutineContext;
74
public final fun getCreationStackTrace ()Ljava/util/List;
85
public final fun getJob ()Lkotlinx/coroutines/Job;
96
public final fun getState ()Lkotlinx/coroutines/debug/State;
10-
public fun hashCode ()I
117
public final fun lastObservedStackTrace ()Ljava/util/List;
128
public fun toString ()Ljava/lang/String;
139
}

kotlinx-coroutines-debug/src/CoroutineInfo.kt

+7-9
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import kotlin.coroutines.jvm.internal.*
1414
* Class describing coroutine info such as its context, state and stacktrace.
1515
*/
1616
@ExperimentalCoroutinesApi
17-
public data class CoroutineInfo internal constructor(
17+
public class CoroutineInfo internal constructor(
1818
val context: CoroutineContext,
1919
private val creationStackBottom: CoroutineStackFrame,
2020
@JvmField internal val sequenceNumber: Long
@@ -44,14 +44,10 @@ public data class CoroutineInfo internal constructor(
4444
@JvmField
4545
internal var lastObservedFrame: CoroutineStackFrame? = null
4646

47-
// Copy constructor
48-
internal constructor(coroutine: Continuation<*>, state: CoroutineInfo) : this(
49-
coroutine.context,
50-
state.creationStackBottom,
51-
state.sequenceNumber
52-
) {
53-
_state = state.state
54-
this.lastObservedFrame = state.lastObservedFrame
47+
public fun copy(): CoroutineInfo = CoroutineInfo(context, creationStackBottom, sequenceNumber).also {
48+
it._state = _state
49+
it.lastObservedFrame = lastObservedFrame
50+
it.lastObservedThread = lastObservedThread
5551
}
5652

5753
/**
@@ -94,6 +90,8 @@ public data class CoroutineInfo internal constructor(
9490
lastObservedThread = null
9591
}
9692
}
93+
94+
override fun toString(): String = "CoroutineInfo(state=$state,context=$context)"
9795
}
9896

9997
/**

kotlinx-coroutines-debug/src/internal/DebugProbesImpl.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ internal object DebugProbesImpl {
8080
check(isInstalled) { "Debug probes are not installed" }
8181
val jobToStack = capturedCoroutines
8282
.filter { it.delegate.context[Job] != null }
83-
.associateBy({ it.delegate.context[Job]!! }, {it.info})
83+
.associateBy({ it.delegate.context[Job]!! }, { it.info })
8484
return buildString {
8585
job.build(jobToStack, this, "")
8686
}
@@ -118,7 +118,7 @@ internal object DebugProbesImpl {
118118
public fun dumpCoroutinesInfo(): List<CoroutineInfo> {
119119
check(isInstalled) { "Debug probes are not installed" }
120120
return capturedCoroutines.asSequence()
121-
.map { CoroutineInfo(it.delegate, it.info) }
121+
.map { it.info.copy() } // Copy as CoroutineInfo can be mutated concurrently by DebugProbes
122122
.sortedBy { it.sequenceNumber }
123123
.toList()
124124
}
@@ -373,7 +373,7 @@ internal object DebugProbesImpl {
373373
private fun <T : Throwable> sanitizeStackTrace(throwable: T): List<StackTraceElement> {
374374
val stackTrace = throwable.stackTrace
375375
val size = stackTrace.size
376-
val probeIndex = stackTrace.indexOfLast { it.className == "kotlin.coroutines.jvm.internal.DebugProbesKt" }
376+
val probeIndex = stackTrace.indexOfLast { it.className == "kotlin.coroutines.jvm.internal.DebugProbesKt" }
377377

378378
if (!DebugProbes.sanitizeStackTraces) {
379379
return List(size - probeIndex) {

kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt

+11
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,15 @@ class RunningThreadStackMergeTest : DebugTestBase() {
167167
yield()
168168
assertTrue(true)
169169
}
170+
171+
@Test
172+
fun testActiveThread() = runBlocking<Unit> {
173+
launchCoroutine()
174+
awaitCoroutineStarted()
175+
val info = DebugProbes.dumpCoroutinesInfo().find { it.state == State.RUNNING }
176+
assertNotNull(info)
177+
@Suppress("INVISIBLE_MEMBER") // IDEA bug
178+
assertNotNull(info.lastObservedThread)
179+
coroutineBlocker.await()
180+
}
170181
}

0 commit comments

Comments
 (0)