Skip to content

Commit a5a7cdb

Browse files
authored
Merge pull request #876 from Kotlin/debug-agent
Coroutines debug agent Fixes #772
2 parents f64bcde + 3781a82 commit a5a7cdb

File tree

33 files changed

+1655
-41
lines changed

33 files changed

+1655
-41
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ GlobalScope.launch {
3131
* [core](core/README.md) — Kotlin/JVM implementation of common coroutines with additional features:
3232
* `Dispatchers.IO` dispatcher for blocking coroutines;
3333
* `Executor.asCoroutineDispatcher()` extension, custom thread pools, and more.
34+
* [debug](core/README.md) — debug utilities for coroutines.
35+
* `DebugProbes` API to probe, keep track of, print and dump active coroutines.
3436
* [js](js/README.md) — Kotlin/JS implementation of common coroutines with `Promise` support.
3537
* [native](native/README.md) — Kotlin/Native implementation of common coroutines with `runBlocking` single-threaded event loop.
3638
* [reactive](reactive/README.md) — modules that provide builders and iteration support for various reactive streams libraries:

RELEASE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ To release new `<version>` of `kotlinx-coroutines`:
1212
`git merge origin/master`
1313

1414
4. Search & replace `<old-version>` with `<version>` across the project files. Should replace in:
15-
* [`README.md`](README.md)
15+
* [`README.md`](README.md) (native, core, test, debug, modules)
1616
* [`coroutines-guide.md`](docs/coroutines-guide.md)
1717
* [`gradle.properties`](gradle.properties)
1818
* [`ui/kotlinx-coroutines-android/example-app/gradle.properties`](ui/kotlinx-coroutines-android/example-app/gradle.properties)

binary-compatibility-validator/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dependencies {
1313
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
1414

1515
testArtifacts project(':kotlinx-coroutines-core')
16+
testArtifacts project(':kotlinx-coroutines-debug')
1617

1718
testArtifacts project(':kotlinx-coroutines-reactive')
1819
testArtifacts project(':kotlinx-coroutines-reactor')

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ public class kotlinx/coroutines/JobSupport : kotlinx/coroutines/ChildJob, kotlin
349349
public fun plus (Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/Job;
350350
public final fun registerSelectClause0 (Lkotlinx/coroutines/selects/SelectInstance;Lkotlin/jvm/functions/Function1;)V
351351
public final fun start ()Z
352+
public final fun toDebugString ()Ljava/lang/String;
352353
public fun toString ()Ljava/lang/String;
353354
}
354355

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
public final class kotlinx/coroutines/debug/CoroutineState {
2+
public final fun component1 ()Lkotlin/coroutines/Continuation;
3+
public final fun copy (Lkotlin/coroutines/Continuation;Lkotlin/coroutines/jvm/internal/CoroutineStackFrame;J)Lkotlinx/coroutines/debug/CoroutineState;
4+
public static synthetic fun copy$default (Lkotlinx/coroutines/debug/CoroutineState;Lkotlin/coroutines/Continuation;Lkotlin/coroutines/jvm/internal/CoroutineStackFrame;JILjava/lang/Object;)Lkotlinx/coroutines/debug/CoroutineState;
5+
public fun equals (Ljava/lang/Object;)Z
6+
public final fun getContinuation ()Lkotlin/coroutines/Continuation;
7+
public final fun getCreationStackTrace ()Ljava/util/List;
8+
public final fun getJob ()Lkotlinx/coroutines/Job;
9+
public final fun getJobOrNull ()Lkotlinx/coroutines/Job;
10+
public final fun getState ()Lkotlinx/coroutines/debug/State;
11+
public fun hashCode ()I
12+
public final fun lastObservedStackTrace ()Ljava/util/List;
13+
public fun toString ()Ljava/lang/String;
14+
}
15+
16+
public final class kotlinx/coroutines/debug/DebugProbes {
17+
public static final field INSTANCE Lkotlinx/coroutines/debug/DebugProbes;
18+
public final fun dumpCoroutines (Ljava/io/PrintStream;)V
19+
public static synthetic fun dumpCoroutines$default (Lkotlinx/coroutines/debug/DebugProbes;Ljava/io/PrintStream;ILjava/lang/Object;)V
20+
public final fun dumpCoroutinesState ()Ljava/util/List;
21+
public final fun getSanitizeStackTraces ()Z
22+
public final fun hierarchyToString (Lkotlinx/coroutines/Job;)Ljava/lang/String;
23+
public final fun install ()V
24+
public final fun printHierarchy (Lkotlinx/coroutines/Job;Ljava/io/PrintStream;)V
25+
public static synthetic fun printHierarchy$default (Lkotlinx/coroutines/debug/DebugProbes;Lkotlinx/coroutines/Job;Ljava/io/PrintStream;ILjava/lang/Object;)V
26+
public final fun setSanitizeStackTraces (Z)V
27+
public final fun uninstall ()V
28+
public final fun withDebugProbes (Lkotlin/jvm/functions/Function0;)V
29+
}
30+
31+
public final class kotlinx/coroutines/debug/State : java/lang/Enum {
32+
public static final field CREATED Lkotlinx/coroutines/debug/State;
33+
public static final field RUNNING Lkotlinx/coroutines/debug/State;
34+
public static final field SUSPENDED Lkotlinx/coroutines/debug/State;
35+
public static fun valueOf (Ljava/lang/String;)Lkotlinx/coroutines/debug/State;
36+
public static fun values ()[Lkotlinx/coroutines/debug/State;
37+
}
38+

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ buildscript {
4040
classpath "com.moowork.gradle:gradle-node-plugin:$gradle_node_version"
4141

4242
// JMH plugins
43-
classpath "com.github.jengelman.gradle.plugins:shadow:2.0.2"
43+
classpath "com.github.jengelman.gradle.plugins:shadow:4.0.2"
4444
classpath "me.champeau.gradle:jmh-gradle-plugin:0.4.7"
4545
classpath "net.ltgt.gradle:gradle-apt-plugin:0.10"
4646
}

common/kotlinx-coroutines-core-common/src/JobSupport.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,10 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
930930

931931
// for nicer debugging
932932
public override fun toString(): String =
933-
"${nameString()}{${stateString(state)}}@$hexAddress"
933+
"${toDebugString()}@$hexAddress"
934+
935+
@InternalCoroutinesApi
936+
public fun toDebugString(): String = "${nameString()}{${stateString(state)}}"
934937

935938
/**
936939
* @suppress **This is unstable API and it is subject to change.**
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.coroutines.internal
6+
7+
import kotlin.coroutines.*
8+
9+
internal expect inline fun <T> probeCoroutineCreated(completion: Continuation<T>): Continuation<T>

common/kotlinx-coroutines-core-common/src/intrinsics/Undispatched.kt

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import kotlin.coroutines.intrinsics.*
1515
* It does not use [ContinuationInterceptor] and does not update context of the current thread.
1616
*/
1717
internal fun <T> (suspend () -> T).startCoroutineUnintercepted(completion: Continuation<T>) {
18-
startDirect(completion) {
19-
startCoroutineUninterceptedOrReturn(completion)
18+
startDirect(completion) { actualCompletion ->
19+
startCoroutineUninterceptedOrReturn(actualCompletion)
2020
}
2121
}
2222

@@ -26,8 +26,8 @@ internal fun <T> (suspend () -> T).startCoroutineUnintercepted(completion: Conti
2626
* It does not use [ContinuationInterceptor] and does not update context of the current thread.
2727
*/
2828
internal fun <R, T> (suspend (R) -> T).startCoroutineUnintercepted(receiver: R, completion: Continuation<T>) {
29-
startDirect(completion) {
30-
startCoroutineUninterceptedOrReturn(receiver, completion)
29+
startDirect(completion) { actualCompletion ->
30+
startCoroutineUninterceptedOrReturn(receiver, actualCompletion)
3131
}
3232
}
3333

@@ -37,9 +37,9 @@ internal fun <R, T> (suspend (R) -> T).startCoroutineUnintercepted(receiver: R,
3737
* It does not use [ContinuationInterceptor], but updates the context of the current thread for the new coroutine.
3838
*/
3939
internal fun <T> (suspend () -> T).startCoroutineUndispatched(completion: Continuation<T>) {
40-
startDirect(completion) {
40+
startDirect(completion) { actualCompletion ->
4141
withCoroutineContext(completion.context, null) {
42-
startCoroutineUninterceptedOrReturn(completion)
42+
startCoroutineUninterceptedOrReturn(actualCompletion)
4343
}
4444
}
4545
}
@@ -50,23 +50,29 @@ internal fun <T> (suspend () -> T).startCoroutineUndispatched(completion: Contin
5050
* It does not use [ContinuationInterceptor], but updates the context of the current thread for the new coroutine.
5151
*/
5252
internal fun <R, T> (suspend (R) -> T).startCoroutineUndispatched(receiver: R, completion: Continuation<T>) {
53-
startDirect(completion) {
53+
startDirect(completion) { actualCompletion ->
5454
withCoroutineContext(completion.context, null) {
55-
startCoroutineUninterceptedOrReturn(receiver, completion)
55+
startCoroutineUninterceptedOrReturn(receiver, actualCompletion)
5656
}
5757
}
5858
}
5959

60-
private inline fun <T> startDirect(completion: Continuation<T>, block: () -> Any?) {
60+
/**
61+
* Starts given [block] immediately in the current stack-frame until first suspension point.
62+
* This method supports debug probes and thus can intercept completion, thus completion is provide
63+
* as the parameter of [block].
64+
*/
65+
private inline fun <T> startDirect(completion: Continuation<T>, block: (Continuation<T>) -> Any?) {
66+
val actualCompletion = probeCoroutineCreated(completion)
6167
val value = try {
62-
block()
68+
block(actualCompletion)
6369
} catch (e: Throwable) {
64-
completion.resumeWithException(e)
70+
actualCompletion.resumeWithException(e)
6571
return
6672
}
6773
if (value !== COROUTINE_SUSPENDED) {
6874
@Suppress("UNCHECKED_CAST")
69-
completion.resume(value as T)
75+
actualCompletion.resume(value as T)
7076
}
7177
}
7278

core/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ Module name below corresponds to the artifact name in Maven/Gradle.
55

66
## Modules
77

8-
* [kotlinx-coroutines-core](kotlinx-coroutines-core/README.md) -- core coroutine builders and synchronization primitives.
9-
8+
* [kotlinx-coroutines-core](kotlinx-coroutines-core/README.md) &mdash; core coroutine builders and synchronization primitives.
9+
* [kotlinx-coroutines-debug](kotlinx-coroutines-debug/README.md) &mdash; coroutines debug utilities.

0 commit comments

Comments
 (0)