Skip to content

Commit f528898

Browse files
committed
Update documentation
1 parent fd2b3e9 commit f528898

File tree

2 files changed

+45
-12
lines changed

2 files changed

+45
-12
lines changed

docs/debugging.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414

1515
## Debugging coroutines
16-
Asynchronous programming is hard and debugging asynchronous programs is even harder.
17-
To improve user experience, `kotlinx.coroutines` comes with additional features for debugging: debug mode, stacktrace recovery
16+
Debugging asynchronous programs is challenging, because multiple concurrent coroutines are typically working at the same time.
17+
To help with that, `kotlinx.coroutines` comes with additional features for debugging: debug mode, stacktrace recovery
1818
and debug agent.
1919

2020
## Debug mode
@@ -23,19 +23,21 @@ The first debugging feature of `kotlinx.coroutines` is debug mode.
2323
It can be enabled either by setting system property [DEBUG_PROPERTY_NAME] or by running Java with enabled assertions (`-ea` flag).
2424
The latter is helpful to have debug mode enabled by default in unit tests.
2525

26-
Debug mode attaches a unique [name][CoroutineName] to every launched coroutine, which then can be seen in a regular Java debugger,
27-
a string representation of coroutine and thread name executing named coroutine.
26+
Debug mode attaches a unique [name][CoroutineName] to every launched coroutine.
27+
Coroutine name can be seen in a regular Java debugger,
28+
in a string representation of the coroutine or in the thread name executing named coroutine.
2829
Overhead of this feature is negligible and it can be safely turned on by default to simplify logging and diagnostic.
2930

3031
## Stacktrace recovery
3132

3233
Stacktrace recovery is another useful feature of debug mode. It is enabled by default in the debug mode,
3334
but can be separately disabled by setting `kotlinx.coroutines.stacktrace.recovery` system property to `false`.
3435

35-
Stacktrace recovery tries to knit asynchronous exception stacktrace with a stacktrace of the receiver by copying it, providing
36+
Stacktrace recovery tries to stitch asynchronous exception stacktrace with a stacktrace of the receiver by copying it, providing
3637
not only information where an exception was thrown, but also where it was asynchronously rethrown or caught.
3738

38-
It is easy to demonstrate with actual stacktraces of the same program that awaits asynchronous operation in `main` function:
39+
It is easy to demonstrate with actual stacktraces of the same program that awaits asynchronous operation in `main` function
40+
(runnable code is [here](../kotlinx-coroutines-debug/test/RecoveryExample.kt)):
3941

4042
| Without recovery | With recovery |
4143
| - | - |
@@ -50,21 +52,21 @@ This section explains the inner mechanism of stacktrace recovery and can be skip
5052
When an exception is rethrown between coroutines (e.g. through `withContext` or `Deferred.await` boundary), stacktrace recovery
5153
machinery tries to create a copy of the original exception (with the original exception as the cause), then rewrite stacktrace
5254
of the copy with coroutine-related stack frames (using [Throwable.setStackTrace](https://docs.oracle.com/javase/9/docs/api/java/lang/Throwable.html#setStackTrace-java.lang.StackTraceElement:A-))
53-
and then throws resulting exception instead of the original one.
55+
and then throws the resulting exception instead of the original one.
5456

5557
Exception copy logic is straightforward:
56-
1) If exception class implements [CopyableThrowable], [CopyableThrowable.createCopy] is used.
57-
2) If exception class has class-specific fields not inherited from Throwable, the exception is not copied.
58-
3) Otherwise, one of the public exception's constructor is invoked reflectively with optional an `initCause` call.
58+
1) If the exception class implements [CopyableThrowable], [CopyableThrowable.createCopy] is used.
59+
2) If the exception class has class-specific fields not inherited from Throwable, the exception is not copied.
60+
3) Otherwise, one of the public exception's constructor is invoked reflectively with an optional `initCause` call.
5961

6062
## Debug agent
6163

6264
[kotlinx-coroutines-debug](../kotlinx-coroutines-debug) module provides one of the most powerful debug capabilities in `kotlinx.coroutines`.
6365

64-
This is a separate module with a JVM agent that keeps track of all alive coroutines, introspect and dump them similar to thread dump command,
66+
This is a separate module with a JVM agent that keeps track of all alive coroutines, introspects and dumps them similar to thread dump command,
6567
additionally enhancing stacktraces with information where coroutine was created.
6668

67-
The full tutorial of how to use debug agent can be found in a corresponding [readme](../kotlinx-coroutines-debug/README.md).
69+
The full tutorial of how to use debug agent can be found in the corresponding [readme](../kotlinx-coroutines-debug/README.md).
6870

6971
### Debug agent and Android
7072

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
@file:Suppress("PackageDirectoryMismatch")
5+
package example
6+
7+
import kotlinx.coroutines.*
8+
9+
object PublicApiImplementation : CoroutineScope by CoroutineScope(CoroutineName("Example")) {
10+
11+
private fun doWork(): Int {
12+
error("Internal invariant failed")
13+
}
14+
15+
private fun asynchronousWork(): Int {
16+
return doWork() + 1
17+
}
18+
19+
public suspend fun awaitAsynchronousWorkInMainThread() {
20+
val task = async(Dispatchers.Default) {
21+
asynchronousWork()
22+
}
23+
24+
task.await()
25+
}
26+
}
27+
28+
suspend fun main() {
29+
// Try to switch debug mode on and off to see the difference
30+
PublicApiImplementation.awaitAsynchronousWorkInMainThread()
31+
}

0 commit comments

Comments
 (0)