blob: 6c846f235d2f51daa04f5dc6b5c46e5602bff2ca [file] [log] [blame] [view]
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +03001**Table of contents**
2
3<!--- TOC -->
4
5* [Debugging coroutines](#debugging-coroutines)
6* [Debug mode](#debug-mode)
7* [Stacktrace recovery](#stacktrace-recovery)
8 * [Stacktrace recovery machinery](#stacktrace-recovery-machinery)
9* [Debug agent](#debug-agent)
Vsevolod Tolstopyatov4764e982019-02-04 12:39:34 +030010 * [Debug agent and Android](#debug-agent-and-android)
Roman Elizarovbf9509d2020-02-14 15:52:10 +030011* [Android optimization](#android-optimization)
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030012
Roman Elizarov660c2d72020-02-14 13:18:37 +030013<!--- END -->
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030014
15## Debugging coroutines
Roman Elizarovbf9509d2020-02-14 15:52:10 +030016
Vsevolod Tolstopyatovf5288982019-02-18 14:46:58 +030017Debugging asynchronous programs is challenging, because multiple concurrent coroutines are typically working at the same time.
18To help with that, `kotlinx.coroutines` comes with additional features for debugging: debug mode, stacktrace recovery
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030019and debug agent.
20
21## Debug mode
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030022
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030023The first debugging feature of `kotlinx.coroutines` is debug mode.
24It can be enabled either by setting system property [DEBUG_PROPERTY_NAME] or by running Java with enabled assertions (`-ea` flag).
25The latter is helpful to have debug mode enabled by default in unit tests.
26
Vsevolod Tolstopyatovf5288982019-02-18 14:46:58 +030027Debug mode attaches a unique [name][CoroutineName] to every launched coroutine.
28Coroutine name can be seen in a regular Java debugger,
29in a string representation of the coroutine or in the thread name executing named coroutine.
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030030Overhead of this feature is negligible and it can be safely turned on by default to simplify logging and diagnostic.
31
32## Stacktrace recovery
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030033
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030034Stacktrace recovery is another useful feature of debug mode. It is enabled by default in the debug mode,
35but can be separately disabled by setting `kotlinx.coroutines.stacktrace.recovery` system property to `false`.
36
Vsevolod Tolstopyatovf5288982019-02-18 14:46:58 +030037Stacktrace recovery tries to stitch asynchronous exception stacktrace with a stacktrace of the receiver by copying it, providing
Vsevolod Tolstopyatov4764e982019-02-04 12:39:34 +030038not only information where an exception was thrown, but also where it was asynchronously rethrown or caught.
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030039
Vsevolod Tolstopyatovf5288982019-02-18 14:46:58 +030040It is easy to demonstrate with actual stacktraces of the same program that awaits asynchronous operation in `main` function
41(runnable code is [here](../kotlinx-coroutines-debug/test/RecoveryExample.kt)):
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030042
43| Without recovery | With recovery |
44| - | - |
45| ![before](images/before.png "before") | ![after](images/after.png "after") |
46
47The only downside of this approach is losing referential transparency of the exception.
48
Vsevolod Tolstopyatov897f02e2019-08-09 17:32:34 +030049### Stacktrace recovery machinery
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030050
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030051This section explains the inner mechanism of stacktrace recovery and can be skipped.
52
53When an exception is rethrown between coroutines (e.g. through `withContext` or `Deferred.await` boundary), stacktrace recovery
54machinery tries to create a copy of the original exception (with the original exception as the cause), then rewrite stacktrace
55of 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-))
Vsevolod Tolstopyatovf5288982019-02-18 14:46:58 +030056and then throws the resulting exception instead of the original one.
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030057
58Exception copy logic is straightforward:
Vsevolod Tolstopyatovf5288982019-02-18 14:46:58 +030059 1) If the exception class implements [CopyableThrowable], [CopyableThrowable.createCopy] is used.
Vsevolod Tolstopyatov897f02e2019-08-09 17:32:34 +030060 `null` can be returned from `createCopy` to opt-out specific exception from being recovered.
Vsevolod Tolstopyatovf5288982019-02-18 14:46:58 +030061 2) If the exception class has class-specific fields not inherited from Throwable, the exception is not copied.
62 3) Otherwise, one of the public exception's constructor is invoked reflectively with an optional `initCause` call.
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030063
64## Debug agent
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030065
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030066[kotlinx-coroutines-debug](../kotlinx-coroutines-debug) module provides one of the most powerful debug capabilities in `kotlinx.coroutines`.
67
Vsevolod Tolstopyatovf5288982019-02-18 14:46:58 +030068This is a separate module with a JVM agent that keeps track of all alive coroutines, introspects and dumps them similar to thread dump command,
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030069additionally enhancing stacktraces with information where coroutine was created.
70
Vsevolod Tolstopyatovf5288982019-02-18 14:46:58 +030071The full tutorial of how to use debug agent can be found in the corresponding [readme](../kotlinx-coroutines-debug/README.md).
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030072
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030073### Debug agent and Android
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030074
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030075Unfortunately, Android runtime does not support Instrument API necessary for `kotlinx-coroutines-debug` to function, triggering `java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/ManagementFactory;`.
76
Mike Nakhimovichda2cf232019-05-22 09:04:22 -040077Nevertheless, it will be possible to support debug agent on Android as soon as [GradleAspectJ-Android](https://github.com/Archinamon/android-gradle-aspectj) will support android-gradle 3.3
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030078
79<!---
80Make an exception googlable
81java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/ManagementFactory;
82 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent$ProcessProvider$ForCurrentVm$ForLegacyVm.resolve(ByteBuddyAgent.java:1055)
83 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent$ProcessProvider$ForCurrentVm.resolve(ByteBuddyAgent.java:1038)
84 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:374)
85 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:342)
86 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:328)
87 at kotlinx.coroutines.debug.internal.DebugProbesImpl.install(DebugProbesImpl.kt:39)
88 at kotlinx.coroutines.debug.DebugProbes.install(DebugProbes.kt:49)
89-->
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030090
Roman Elizarovbf9509d2020-02-14 15:52:10 +030091## Android optimization
92
93In optimized (release) builds with R8 version 1.6.0 or later both
94[Debugging mode](../../docs/debugging.md#debug-mode) and
95[Stacktrace recovery](../../docs/debugging.md#stacktrace-recovery)
96are permanently turned off.
97For more details see ["Optimization" section for Android](../ui/kotlinx-coroutines-android/README.md#optimization).
98
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030099<!--- MODULE kotlinx-coroutines-core -->
100<!--- INDEX kotlinx.coroutines -->
101[DEBUG_PROPERTY_NAME]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-d-e-b-u-g_-p-r-o-p-e-r-t-y_-n-a-m-e.html
102[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-name/index.html
103[CopyableThrowable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/index.html
104[CopyableThrowable.createCopy]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/create-copy.html
105<!--- MODULE kotlinx-coroutines-debug -->
106<!--- END -->