aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2021-05-13 21:10:03 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2021-05-13 21:10:03 +0000
commitca844a281f708fe9473e72ed769ae1d26deebbc1 (patch)
treecd835b4f3ee81a86fc0625444b031b33cb3c2b60
parentd5890c368a901697c67059ee8b0b7e2a10ca667e (diff)
parent50999e917ed00d5092e63ec0d4d62a08aff84761 (diff)
downloadkotlinx.coroutines-android12L-d2-s2-release.tar.gz
Change-Id: I7fb353cb713bb4d0e776e2c7342980959f2e64d3
-rw-r--r--.gitignore1
-rw-r--r--.idea/dictionaries/shared.xml9
-rw-r--r--CHANGES.md74
-rw-r--r--METADATA8
-rw-r--r--README.md127
-rw-r--r--RELEASE.md11
-rw-r--r--benchmarks/build.gradle.kts2
-rw-r--r--benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabble.java2
-rw-r--r--benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabbleOpt.java2
-rw-r--r--benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableCharSequence.java2
-rw-r--r--benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableSplit.java2
-rw-r--r--benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/StringFlowable.java2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/ChannelProducerConsumerBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkBenchmark.kt6
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkDepthBenchmark.kt91
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/ParametrizedDispatcherBase.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/SemaphoreBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/akka/PingPongAkkaBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/akka/StatefulActorAkkaBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/CombineFlowsBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/CombineTwoFlowsBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/FlatMapMergeBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/FlowFlattenMergeBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/NumbersBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/SafeFlowBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/TakeBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/TakeWhileBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleBase.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleOpt.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/IterableSpliterator.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ReactorPlaysScrabble.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SaneFlowPlaysScrabble.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SequencePlaysScrabble.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ShakespearePlaysScrabble.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/scheduler/DispatchersContextSwitchBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/scheduler/ForkJoinBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/scheduler/LaunchBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/scheduler/StatefulAwaitsBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/ConcurrentStatefulActorBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/CycledActorsBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongActorBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongWithBlockingContext.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/StatefulActorBenchmark.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannel.kt2
-rw-r--r--benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannelBenchmark.kt2
-rw-r--r--benchmarks/src/main/kotlin/benchmarks/common/BenchmarkUtils.kt2
-rw-r--r--build.gradle67
-rw-r--r--buildSrc/build.gradle.kts4
-rw-r--r--buildSrc/settings.gradle.kts2
-rw-r--r--buildSrc/src/main/kotlin/CacheRedirector.kt2
-rw-r--r--buildSrc/src/main/kotlin/Dokka.kt2
-rw-r--r--buildSrc/src/main/kotlin/Idea.kt4
-rw-r--r--buildSrc/src/main/kotlin/MavenCentral.kt37
-rw-r--r--buildSrc/src/main/kotlin/Platform.kt4
-rw-r--r--buildSrc/src/main/kotlin/Projects.kt4
-rw-r--r--buildSrc/src/main/kotlin/Properties.kt2
-rw-r--r--buildSrc/src/main/kotlin/Publishing.kt93
-rw-r--r--buildSrc/src/main/kotlin/RunR8.kt4
-rw-r--r--buildSrc/src/main/kotlin/UnpackAar.kt4
-rw-r--r--buildSrc/src/main/kotlin/jdk-convention.gradle.kts4
-rw-r--r--buildSrc/src/main/kotlin/kotlin-js-conventions.gradle.kts40
-rw-r--r--buildSrc/src/main/kotlin/kotlin-jvm-conventions.gradle.kts46
-rwxr-xr-xbump-version.sh2
-rw-r--r--coroutines-guide.md132
-rw-r--r--docs/_nav.yml30
-rw-r--r--docs/basics.md411
-rw-r--r--docs/cancellation-and-timeouts.md483
-rw-r--r--docs/cfg/buildprofiles.xml10
-rw-r--r--docs/channels.md703
-rw-r--r--docs/compatibility.md126
-rw-r--r--docs/composing-suspending-functions.md436
-rw-r--r--docs/coroutine-context-and-dispatchers.md713
-rw-r--r--docs/coroutines-guide.md33
-rw-r--r--docs/debugging.md107
-rw-r--r--docs/exception-handling.md527
-rw-r--r--docs/flow.md1980
-rw-r--r--docs/images/coroutine-breakpoint.pngbin106968 -> 0 bytes
-rw-r--r--docs/images/coroutine-debug-1.pngbin226219 -> 0 bytes
-rw-r--r--docs/images/coroutine-debug-2.pngbin209165 -> 0 bytes
-rw-r--r--docs/images/coroutine-debug-3.pngbin203521 -> 0 bytes
-rw-r--r--docs/images/flow-breakpoint.pngbin111598 -> 0 bytes
-rw-r--r--docs/images/flow-build-project.pngbin44472 -> 0 bytes
-rw-r--r--docs/images/flow-debug-1.pngbin313682 -> 0 bytes
-rw-r--r--docs/images/flow-debug-2.pngbin314131 -> 0 bytes
-rw-r--r--docs/images/flow-debug-3.pngbin224245 -> 0 bytes
-rw-r--r--docs/images/flow-debug-4.pngbin221360 -> 0 bytes
-rw-r--r--docs/images/flow-debug-project.pngbin44199 -> 0 bytes
-rw-r--r--docs/images/flow-resume-debug.pngbin101404 -> 0 bytes
-rw-r--r--docs/images/new-gradle-project-jvm.pngbin150223 -> 0 bytes
-rw-r--r--docs/images/new-mvn-project-jvm.pngbin378558 -> 0 bytes
-rw-r--r--docs/kc.tree26
-rw-r--r--docs/knit.properties10
-rw-r--r--docs/project.ihp13
-rw-r--r--docs/select-expression.md550
-rw-r--r--docs/shared-mutable-state-and-concurrency.md540
-rw-r--r--docs/topics/cancellation-and-timeouts.md461
-rw-r--r--docs/topics/channels.md649
-rw-r--r--docs/topics/compatibility.md129
-rw-r--r--docs/topics/composing-suspending-functions.md406
-rw-r--r--docs/topics/coroutine-context-and-dispatchers.md681
-rw-r--r--docs/topics/coroutines-basic-jvm.md267
-rw-r--r--docs/topics/coroutines-basics.md379
-rw-r--r--docs/topics/coroutines-guide.md37
-rw-r--r--docs/topics/debug-coroutines-with-idea.md82
-rw-r--r--docs/topics/debug-flow-with-idea.md126
-rw-r--r--docs/topics/debugging.md112
-rw-r--r--docs/topics/exception-handling.md513
-rw-r--r--docs/topics/flow.md1896
-rw-r--r--docs/topics/knit.properties9
-rw-r--r--docs/topics/select-expression.md502
-rw-r--r--docs/topics/shared-mutable-state-and-concurrency.md513
-rw-r--r--gradle.properties18
-rw-r--r--gradle/compile-common.gradle2
-rw-r--r--gradle/compile-js-multiplatform.gradle11
-rw-r--r--gradle/compile-js.gradle32
-rw-r--r--gradle/compile-jvm-multiplatform.gradle10
-rw-r--r--gradle/compile-jvm.gradle34
-rw-r--r--gradle/compile-native-multiplatform.gradle2
-rw-r--r--gradle/dokka.gradle2
-rw-r--r--gradle/experimental.gradle2
-rw-r--r--gradle/node-js.gradle2
-rw-r--r--gradle/publish-bintray.gradle60
-rw-r--r--gradle/publish-mpp-root-module-in-platform.gradle55
-rw-r--r--gradle/publish-npm-js.gradle2
-rw-r--r--gradle/test-mocha-js.gradle2
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin59203 -> 56172 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties4
-rwxr-xr-xgradlew41
-rw-r--r--gradlew.bat43
-rw-r--r--integration-testing/build.gradle10
-rw-r--r--integration-testing/src/coreAgentTest/kotlin/CoreAgentTest.kt2
-rw-r--r--integration-testing/src/debugAgentTest/kotlin/DebugAgentTest.kt2
-rw-r--r--integration-testing/src/debugAgentTest/kotlin/DebugProbes.kt4
-rw-r--r--integration-testing/src/debugAgentTest/kotlin/PrecompiledDebugProbesTest.kt4
-rw-r--r--integration-testing/src/mavenTest/kotlin/MavenPublicationValidator.kt2
-rw-r--r--integration-testing/src/npmTest/kotlin/NpmPublicationValidator.kt2
-rw-r--r--integration/kotlinx-coroutines-guava/README.md4
-rw-r--r--integration/kotlinx-coroutines-guava/build.gradle.kts2
-rw-r--r--integration/kotlinx-coroutines-guava/src/ListenableFuture.kt315
-rw-r--r--integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt207
-rw-r--r--integration/kotlinx-coroutines-guava/test/ListenableFutureToStringTest.kt69
-rw-r--r--integration/kotlinx-coroutines-jdk8/README.md4
-rw-r--r--integration/kotlinx-coroutines-jdk8/build.gradle.kts2
-rw-r--r--integration/kotlinx-coroutines-jdk8/src/future/Future.kt35
-rw-r--r--integration/kotlinx-coroutines-jdk8/src/stream/Stream.kt2
-rw-r--r--integration/kotlinx-coroutines-jdk8/src/time/Time.kt2
-rw-r--r--integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt77
-rw-r--r--integration/kotlinx-coroutines-play-services/build.gradle45
-rw-r--r--integration/kotlinx-coroutines-play-services/build.gradle.kts41
-rw-r--r--integration/kotlinx-coroutines-play-services/src/Tasks.kt2
-rw-r--r--integration/kotlinx-coroutines-slf4j/README.md2
-rw-r--r--integration/kotlinx-coroutines-slf4j/build.gradle.kts2
-rw-r--r--integration/kotlinx-coroutines-slf4j/src/MDCContext.kt2
-rw-r--r--js/example-frontend-js/build.gradle33
-rw-r--r--js/example-frontend-js/build.gradle.kts27
-rw-r--r--js/example-frontend-js/src/ExampleMain.kt2
-rw-r--r--js/example-frontend-js/src/main/web/style.css2
-rw-r--r--js/js-stub/build.gradle.kts2
-rw-r--r--js/js-stub/src/Performance.kt2
-rw-r--r--js/js-stub/src/Promise.kt2
-rw-r--r--js/js-stub/src/Window.kt2
-rw-r--r--knit.properties4
-rw-r--r--kotlinx-coroutines-bom/build.gradle2
-rw-r--r--kotlinx-coroutines-core/README.md8
-rw-r--r--kotlinx-coroutines-core/api/kotlinx-coroutines-core.api23
-rw-r--r--kotlinx-coroutines-core/build.gradle65
-rw-r--r--kotlinx-coroutines-core/common/README.md10
-rw-r--r--kotlinx-coroutines-core/common/src/AbstractCoroutine.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/Annotations.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/Await.kt7
-rw-r--r--kotlinx-coroutines-core/common/src/Builders.common.kt20
-rw-r--r--kotlinx-coroutines-core/common/src/CancellableContinuation.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt13
-rw-r--r--kotlinx-coroutines-core/common/src/CompletableDeferred.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/CompletableJob.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/CompletionHandler.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/CompletionState.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/CoroutineContext.common.kt3
-rw-r--r--kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/CoroutineExceptionHandler.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/CoroutineName.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/CoroutineScope.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/CoroutineStart.kt13
-rw-r--r--kotlinx-coroutines-core/common/src/Debug.common.kt3
-rw-r--r--kotlinx-coroutines-core/common/src/Deferred.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/Delay.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/Dispatchers.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/EventLoop.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/Exceptions.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/Job.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/JobSupport.kt117
-rw-r--r--kotlinx-coroutines-core/common/src/MainCoroutineDispatcher.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/NonCancellable.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/Runnable.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/SchedulerTask.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/Supervisor.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/Timeout.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/Unconfined.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/Yield.kt5
-rw-r--r--kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt25
-rw-r--r--kotlinx-coroutines-core/common/src/channels/ArrayBroadcastChannel.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/channels/Broadcast.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/channels/BroadcastChannel.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/channels/BufferOverflow.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/channels/Channel.kt6
-rw-r--r--kotlinx-coroutines-core/common/src/channels/ChannelCoroutine.kt3
-rw-r--r--kotlinx-coroutines-core/common/src/channels/Channels.common.kt29
-rw-r--r--kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt16
-rw-r--r--kotlinx-coroutines-core/common/src/channels/Produce.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/channels/RendezvousChannel.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/Builders.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/Channels.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/flow/Flow.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/flow/FlowCollector.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/Migration.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/SharedFlow.kt28
-rw-r--r--kotlinx-coroutines-core/common/src/flow/SharingStarted.kt16
-rw-r--r--kotlinx-coroutines-core/common/src/flow/StateFlow.kt8
-rw-r--r--kotlinx-coroutines-core/common/src/flow/internal/AbstractSharedFlow.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/flow/internal/ChannelFlow.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/internal/Combine.kt6
-rw-r--r--kotlinx-coroutines-core/common/src/flow/internal/FlowCoroutine.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/internal/FlowExceptions.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/internal/Merge.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/internal/NopCollector.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/internal/NullSurrogate.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/internal/SafeCollector.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/internal/SendingCollector.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/operators/Context.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/flow/operators/Delay.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/operators/Distinct.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/flow/operators/Emitters.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/operators/Errors.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/operators/Limit.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/operators/Lint.kt64
-rw-r--r--kotlinx-coroutines-core/common/src/flow/operators/Merge.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/flow/operators/Share.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/operators/Transform.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/operators/Zip.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/flow/terminal/Collect.kt6
-rw-r--r--kotlinx-coroutines-core/common/src/flow/terminal/Collection.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/terminal/Count.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/flow/terminal/Reduce.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/ArrayQueue.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/Atomic.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/Concurrent.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/ConcurrentLinkedList.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/internal/DispatchedContinuation.kt6
-rw-r--r--kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt12
-rw-r--r--kotlinx-coroutines-core/common/src/internal/InlineList.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/LocalAtomics.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/LockFreeLinkedList.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/LockFreeTaskQueue.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/MainDispatcherFactory.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/OnUndeliveredElement.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/ProbesSupport.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/Scopes.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/internal/StackTraceRecovery.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/Symbol.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/internal/Synchronized.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/SystemProps.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/ThreadContext.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/ThreadLocal.common.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/internal/ThreadSafeHeap.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/intrinsics/Cancellable.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/intrinsics/Undispatched.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/selects/Select.kt9
-rw-r--r--kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt4
-rw-r--r--kotlinx-coroutines-core/common/src/selects/WhileSelect.kt2
-rw-r--r--kotlinx-coroutines-core/common/src/sync/Mutex.kt5
-rw-r--r--kotlinx-coroutines-core/common/src/sync/Semaphore.kt9
-rw-r--r--kotlinx-coroutines-core/common/test/AtomicCancellationCommonTest.kt36
-rw-r--r--kotlinx-coroutines-core/common/test/AwaitTest.kt28
-rw-r--r--kotlinx-coroutines-core/common/test/BuilderContractsTest.kt20
-rw-r--r--kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt20
-rw-r--r--kotlinx-coroutines-core/common/test/channels/ProduceTest.kt23
-rw-r--r--kotlinx-coroutines-core/common/test/flow/channels/ChannelFlowTest.kt15
-rw-r--r--kotlinx-coroutines-core/common/test/flow/sharing/ShareInTest.kt8
-rw-r--r--kotlinx-coroutines-core/common/test/sync/MutexTest.kt3
-rw-r--r--kotlinx-coroutines-core/js/src/CompletionHandler.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/CoroutineContext.kt11
-rw-r--r--kotlinx-coroutines-core/js/src/CoroutineExceptionHandlerImpl.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/Debug.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/Dispatchers.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/EventLoop.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/Exceptions.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/JSDispatcher.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/Promise.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/Runnable.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/SchedulerTask.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/Window.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/flow/internal/FlowExceptions.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/flow/internal/SafeCollector.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/internal/Concurrent.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/internal/CopyOnWriteList.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/internal/LinkedList.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/internal/LocalAtomics.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/internal/ProbesSupport.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/internal/StackTraceRecovery.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/internal/Synchronized.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/internal/SystemProps.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/internal/ThreadContext.kt2
-rw-r--r--kotlinx-coroutines-core/js/src/internal/ThreadLocal.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/resources/DebugProbesKt.binbin1728 -> 1728 bytes
-rw-r--r--kotlinx-coroutines-core/jvm/resources/META-INF/proguard/coroutines.pro4
-rw-r--r--kotlinx-coroutines-core/jvm/src/Builders.kt4
-rw-r--r--kotlinx-coroutines-core/jvm/src/CommonPool.kt6
-rw-r--r--kotlinx-coroutines-core/jvm/src/CompletionHandler.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/CoroutineContext.kt100
-rw-r--r--kotlinx-coroutines-core/jvm/src/CoroutineExceptionHandlerImpl.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/Debug.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/DebugStrings.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/Dispatchers.kt3
-rw-r--r--kotlinx-coroutines-core/jvm/src/EventLoop.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/Exceptions.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/Executors.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/Future.kt8
-rw-r--r--kotlinx-coroutines-core/jvm/src/Interruptible.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/Runnable.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/SchedulerTask.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/ThreadPoolDispatcher.kt4
-rw-r--r--kotlinx-coroutines-core/jvm/src/TimeSource.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/channels/Actor.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/channels/Channels.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/channels/TickerChannels.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/debug/AgentPremain.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/debug/internal/ConcurrentWeakMap.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/debug/internal/DebugCoroutineInfo.kt4
-rw-r--r--kotlinx-coroutines-core/jvm/src/debug/internal/DebugCoroutineInfoImpl.kt4
-rw-r--r--kotlinx-coroutines-core/jvm/src/debug/internal/DebugProbesImpl.kt49
-rw-r--r--kotlinx-coroutines-core/jvm/src/debug/internal/DebuggerInfo.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/debug/internal/StackTraceFrame.kt4
-rw-r--r--kotlinx-coroutines-core/jvm/src/flow/internal/FlowExceptions.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/flow/internal/SafeCollector.kt4
-rw-r--r--kotlinx-coroutines-core/jvm/src/internal/Concurrent.kt4
-rw-r--r--kotlinx-coroutines-core/jvm/src/internal/ExceptionsConstuctor.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/internal/FastServiceLoader.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/internal/LocalAtomics.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt10
-rw-r--r--kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt4
-rw-r--r--kotlinx-coroutines-core/jvm/src/internal/ProbesSupport.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/internal/StackTraceRecovery.kt4
-rw-r--r--kotlinx-coroutines-core/jvm/src/internal/Synchronized.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/internal/SystemProps.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/internal/ThreadContext.kt45
-rw-r--r--kotlinx-coroutines-core/jvm/src/internal/ThreadLocal.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/scheduling/CoroutineScheduler.kt30
-rw-r--r--kotlinx-coroutines-core/jvm/src/scheduling/Dispatcher.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/scheduling/Tasks.kt9
-rw-r--r--kotlinx-coroutines-core/jvm/src/scheduling/WorkQueue.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/src/test_/TestCoroutineContext.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/test/AbstractLincheckTest.kt41
-rw-r--r--kotlinx-coroutines-core/jvm/test/LCStressOptionsDefault.kt20
-rw-r--r--kotlinx-coroutines-core/jvm/test/ThreadContextElementRestoreTest.kt198
-rw-r--r--kotlinx-coroutines-core/jvm/test/ThreadContextOrderTest.kt65
-rw-r--r--kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/test/guide/example-basic-08.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/test/guide/example-basic-09.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/test/guide/test/BasicsGuideTest.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/test/lincheck/SemaphoreLincheckTest.kt35
-rw-r--r--kotlinx-coroutines-core/jvm/test/linearizability/ChannelsLCStressTest.kt (renamed from kotlinx-coroutines-core/jvm/test/lincheck/ChannelsLincheckTest.kt)32
-rw-r--r--kotlinx-coroutines-core/jvm/test/linearizability/LockFreeListLCStressTest.kt (renamed from kotlinx-coroutines-core/jvm/test/lincheck/LockFreeListLincheckTest.kt)13
-rw-r--r--kotlinx-coroutines-core/jvm/test/linearizability/LockFreeTaskQueueLCStressTest.kt (renamed from kotlinx-coroutines-core/jvm/test/lincheck/LockFreeTaskQueueLincheckTest.kt)34
-rw-r--r--kotlinx-coroutines-core/jvm/test/linearizability/MutexLCStressTest.kt (renamed from kotlinx-coroutines-core/jvm/test/lincheck/MutexLincheckTest.kt)19
-rw-r--r--kotlinx-coroutines-core/jvm/test/linearizability/SegmentListRemoveLCStressTest.kt (renamed from kotlinx-coroutines-core/jvm/test/lincheck/SegmentListRemoveLincheckTest.kt)20
-rw-r--r--kotlinx-coroutines-core/jvm/test/linearizability/SegmentQueueLCStressTest.kt (renamed from kotlinx-coroutines-core/jvm/test/lincheck/SegmentQueueLincheckTest.kt)11
-rw-r--r--kotlinx-coroutines-core/jvm/test/linearizability/SemaphoreLCStressTest.kt34
-rw-r--r--kotlinx-coroutines-core/jvm/test/scheduling/BlockingCoroutineDispatcherMixedStealingStressTest.kt2
-rw-r--r--kotlinx-coroutines-core/jvm/test/scheduling/TestTimeSource.kt4
-rw-r--r--kotlinx-coroutines-core/jvm/test/sync/MutexStressTest.kt19
-rw-r--r--kotlinx-coroutines-core/jvm/test/sync/SemaphoreStressTest.kt19
-rw-r--r--kotlinx-coroutines-core/knit.properties2
-rw-r--r--kotlinx-coroutines-core/native/src/Builders.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/CompletionHandler.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/CoroutineContext.kt11
-rw-r--r--kotlinx-coroutines-core/native/src/CoroutineExceptionHandlerImpl.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/Debug.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/Dispatchers.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/EventLoop.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/Exceptions.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/Runnable.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/SchedulerTask.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/WorkerMain.native.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/flow/internal/FlowExceptions.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/flow/internal/SafeCollector.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/internal/Concurrent.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/internal/CopyOnWriteList.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/internal/LinkedList.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/internal/LocalAtomics.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/internal/ProbesSupport.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/internal/StackTraceRecovery.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/internal/Synchronized.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/internal/SystemProps.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/internal/ThreadContext.kt2
-rw-r--r--kotlinx-coroutines-core/native/src/internal/ThreadLocal.kt2
-rw-r--r--kotlinx-coroutines-core/nativeDarwin/src/WorkerMain.kt2
-rw-r--r--kotlinx-coroutines-core/nativeOther/src/WorkerMain.kt2
-rw-r--r--kotlinx-coroutines-debug/README.md12
-rw-r--r--kotlinx-coroutines-debug/build.gradle12
-rw-r--r--kotlinx-coroutines-debug/src/CoroutineInfo.kt4
-rw-r--r--kotlinx-coroutines-debug/src/CoroutinesBlockHoundIntegration.kt4
-rw-r--r--kotlinx-coroutines-debug/src/DebugProbes.kt2
-rw-r--r--kotlinx-coroutines-debug/src/internal/Attach.kt2
-rw-r--r--kotlinx-coroutines-debug/src/internal/NoOpProbes.kt2
-rw-r--r--kotlinx-coroutines-debug/src/junit4/CoroutinesTimeout.kt2
-rw-r--r--kotlinx-coroutines-debug/src/junit4/CoroutinesTimeoutStatement.kt2
-rw-r--r--kotlinx-coroutines-debug/test/DebugProbesTest.kt2
-rw-r--r--kotlinx-coroutines-debug/test/SanitizedProbesTest.kt4
-rw-r--r--kotlinx-coroutines-test/README.md6
-rw-r--r--kotlinx-coroutines-test/build.gradle.kts4
-rw-r--r--kotlinx-coroutines-test/resources/META-INF/proguard/coroutines.pro2
-rw-r--r--kotlinx-coroutines-test/src/DelayController.kt2
-rw-r--r--kotlinx-coroutines-test/src/TestBuilders.kt2
-rw-r--r--kotlinx-coroutines-test/src/TestCoroutineDispatcher.kt2
-rw-r--r--kotlinx-coroutines-test/src/TestCoroutineExceptionHandler.kt2
-rw-r--r--kotlinx-coroutines-test/src/TestCoroutineScope.kt2
-rw-r--r--kotlinx-coroutines-test/src/TestDispatchers.kt2
-rw-r--r--kotlinx-coroutines-test/src/internal/MainTestDispatcher.kt2
-rw-r--r--reactive/knit.properties4
-rw-r--r--reactive/kotlinx-coroutines-jdk9/build.gradle.kts2
-rw-r--r--reactive/kotlinx-coroutines-jdk9/src/Await.kt2
-rw-r--r--reactive/kotlinx-coroutines-jdk9/src/Publish.kt2
-rw-r--r--reactive/kotlinx-coroutines-jdk9/src/ReactiveFlow.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactive/README.md6
-rw-r--r--reactive/kotlinx-coroutines-reactive/build.gradle.kts2
-rw-r--r--reactive/kotlinx-coroutines-reactive/src/Await.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactive/src/Channel.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactive/src/ContextInjector.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactive/src/Convert.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactive/src/Migration.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactive/src/Publish.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactive/src/ReactiveFlow.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactor/README.md6
-rw-r--r--reactive/kotlinx-coroutines-reactor/build.gradle.kts6
-rw-r--r--reactive/kotlinx-coroutines-reactor/src/Convert.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactor/src/Flux.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactor/src/Migration.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactor/src/Mono.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactor/src/ReactorContext.kt6
-rw-r--r--reactive/kotlinx-coroutines-reactor/src/ReactorContextInjector.kt6
-rw-r--r--reactive/kotlinx-coroutines-reactor/src/ReactorFlow.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactor/src/Scheduler.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactor/test/FlowAsFluxTest.kt8
-rw-r--r--reactive/kotlinx-coroutines-reactor/test/MonoTest.kt2
-rw-r--r--reactive/kotlinx-coroutines-reactor/test/ReactorContextTest.kt10
-rw-r--r--reactive/kotlinx-coroutines-rx2/README.md8
-rw-r--r--reactive/kotlinx-coroutines-rx2/build.gradle2
-rw-r--r--reactive/kotlinx-coroutines-rx2/src/RxAwait.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx2/src/RxCancellable.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx2/src/RxChannel.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx2/src/RxConvert.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx2/src/RxObservable.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx2/src/RxScheduler.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx2/src/RxSingle.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx3/README.md8
-rw-r--r--reactive/kotlinx-coroutines-rx3/build.gradle2
-rw-r--r--reactive/kotlinx-coroutines-rx3/src/RxAwait.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx3/src/RxCancellable.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx3/src/RxChannel.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx3/src/RxCompletable.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx3/src/RxConvert.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx3/src/RxFlowable.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx3/src/RxMaybe.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx3/src/RxObservable.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx3/src/RxScheduler.kt2
-rw-r--r--reactive/kotlinx-coroutines-rx3/src/RxSingle.kt2
-rw-r--r--settings.gradle2
-rw-r--r--site/build.gradle.kts4
-rw-r--r--site/docs/index.md1
-rw-r--r--stdlib-stubs/build.gradle.kts2
-rw-r--r--stdlib-stubs/src/Continuation.kt2
-rw-r--r--stdlib-stubs/src/ContinuationInterceptor.kt2
-rw-r--r--stdlib-stubs/src/CoroutineContext.kt2
-rw-r--r--stdlib-stubs/src/Result.kt2
-rw-r--r--ui/coroutines-guide-ui.md12
-rw-r--r--ui/knit.properties4
-rw-r--r--ui/kotlinx-coroutines-android/android-unit-tests/build.gradle.kts2
-rw-r--r--ui/kotlinx-coroutines-android/android-unit-tests/src/EmptyCoroutineScopeImpl.kt2
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/build.gradle.kts35
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/AndroidManifest.xml27
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/Animation.kt159
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/MainActivity.kt30
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml34
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/drawable/ic_launcher_background.xml170
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/activity_main.xml47
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/content_main.xml24
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml9
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml9
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3056 bytes
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.pngbin0 -> 5024 bytes
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2096 bytes
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.pngbin0 -> 2858 bytes
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4569 bytes
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 7098 bytes
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 6464 bytes
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 10676 bytes
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 9250 bytes
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 15523 bytes
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/colors.xml6
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/dimens.xml3
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/strings.xml4
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/styles.xml20
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/build.gradle.kts30
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/gradle.properties28
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.jarbin0 -> 58694 bytes
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xui/kotlinx-coroutines-android/animation-app/gradlew183
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/gradlew.bat103
-rw-r--r--ui/kotlinx-coroutines-android/animation-app/settings.gradle.kts5
-rw-r--r--ui/kotlinx-coroutines-android/build.gradle.kts6
-rw-r--r--ui/kotlinx-coroutines-android/example-app/.gitignore7
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/build.gradle.kts34
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/AndroidManifest.xml28
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/java/com/example/app/MainActivity.kt43
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/activity_main.xml37
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/content_main.xml25
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/menu/menu_main.xml10
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3418 bytes
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.pngbin0 -> 4208 bytes
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2206 bytes
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.pngbin0 -> 2555 bytes
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4842 bytes
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 6114 bytes
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 7718 bytes
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 10056 bytes
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 10486 bytes
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 14696 bytes
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/colors.xml6
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/dimens.xml3
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/strings.xml4
-rw-r--r--ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/styles.xml20
-rw-r--r--ui/kotlinx-coroutines-android/example-app/build.gradle.kts30
-rw-r--r--ui/kotlinx-coroutines-android/example-app/gradle.properties28
-rw-r--r--ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.jarbin0 -> 58694 bytes
-rw-r--r--ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xui/kotlinx-coroutines-android/example-app/gradlew183
-rw-r--r--ui/kotlinx-coroutines-android/example-app/gradlew.bat103
-rw-r--r--ui/kotlinx-coroutines-android/example-app/settings.gradle.kts1
-rw-r--r--ui/kotlinx-coroutines-android/src/AndroidExceptionPreHandler.kt2
-rw-r--r--ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt2
-rw-r--r--ui/kotlinx-coroutines-javafx/build.gradle.kts13
-rw-r--r--ui/kotlinx-coroutines-javafx/src/JavaFxConvert.kt2
-rw-r--r--ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt2
-rw-r--r--ui/kotlinx-coroutines-swing/build.gradle.kts2
-rw-r--r--ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt2
-rw-r--r--ui/kotlinx-coroutines-swing/test/examples/swing-example.kt39
560 files changed, 9666 insertions, 9664 deletions
diff --git a/.gitignore b/.gitignore
index 52843ca5..aed71032 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,6 @@
!/.idea/copyright
!/.idea/codeStyleSettings.xml
!/.idea/codeStyles
-!/.idea/dictionaries
*.iml
.gradle
.gradletasknamecache
diff --git a/.idea/dictionaries/shared.xml b/.idea/dictionaries/shared.xml
deleted file mode 100644
index 3da8e229..00000000
--- a/.idea/dictionaries/shared.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<component name="ProjectDictionaryState">
- <dictionary name="shared">
- <words>
- <w>kotlinx</w>
- <w>lincheck</w>
- <w>redirector</w>
- </words>
- </dictionary>
-</component> \ No newline at end of file
diff --git a/CHANGES.md b/CHANGES.md
index b4c2a7bd..baee6c43 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,43 +1,5 @@
# Change log for kotlinx.coroutines
-## Version 1.4.3
-
-### General changes
-
-* Thread context is properly preserved and restored for coroutines without `ThreadContextElement` (#985)
-* `ThreadContextElement`s are now restored in the opposite order from update (#2195)
-* Improved performance of combine with 4 parameters, thanks to @alexvanyo (#2419)
-* Debug agent sanitizer leaves at least one frame with source location (#1437)
-* Update Reactor version in `kotlinx-coroutines-reactor` to `3.4.1`, thanks to @sokomishalov (#2432)
-* `callInPlace` contract added to `ReceiveChannel.consume` (#941)
-* `CoroutineStart.UNDISPATCHED` promoted to stable API (#1393)
-* Kotlin updated to 1.4.30
-* `kotlinx.coroutines` are now released directly to MavenCentral
-* Reduced the size of `DispatchedCoroutine` by a field
-* Internal class `TimeSource` renamed to `SchedulerTimeSource` to prevent wildcard import issues (#2537)
-
-### Bug fixes
-
-* Fixed the problem that prevented implementation via delegation for `Job` interface (#2423)
-* Fixed incorrect ProGuard rules that allowed shrinking volatile felds (#1564)
-* Fixed `await/`asDeferred` for `MinimalState` implementations in jdk8 module (#2456)
-* Fixed bug when `onUndeliveredElement` wasn't called for unlimited channels (#2435)
-* Fixed a bug when `ListenableFuture.isCancelled` returned from `asListenableFuture` could have thrown an exception, thanks to @vadimsemenov (#2421)
-* Coroutine in `callbackFlow` and `produce` is properly cancelled when the channel was closed separately (#2506)
-
-
-## Version 1.4.2
-
-* Fixed `StackOverflowError` in `Job.toString` when `Job` is observed in its intermediate state (#2371).
-* Improved liveness and latency of `Dispatchers.Default` and `Dispatchers.IO` in low-loaded mode (#2381).
-* Improved performance of consecutive `Channel.cancel` invocations (#2384).
-* `SharingStarted` is now `fun` interface (#2397).
-* Additional lint settings for `SharedFlow` to catch programmatic errors early (#2376).
-* Fixed bug when mutex and semaphore were not released during cancellation (#2390, thanks to @Tilps for reproducing).
-* Some corner cases in cancellation propagation between coroutines and listenable futures are repaired (#1442, thanks to @vadimsemenov).
-* Fixed unconditional cast to `CoroutineStackFrame` in exception recovery that triggered failures of instrumented code (#2386).
-* Platform-specific dependencies are removed from `kotlinx-coroutines-javafx` (#2360).
-
## Version 1.4.1
This is a patch release with an important fix to the `SharedFlow` implementation.
@@ -263,12 +225,12 @@ Gradle version 5.3 or later to use this version of kotlinx.coroutines in your Ko
This version is the first stable release with [`Flow`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html) API.
All `Flow` API not marked with `@FlowPreview` or `@ExperimentalCoroutinesApi` annotations are stable and here to stay.
-Flow declarations marked with `@ExperimentalCoroutinesApi` have [the same guarantees](/docs/topics/compatibility.md#experimental-api) as regular experimental API.
-Please note that API marked with `@FlowPreview` have [weak guarantees](/docs/topics/compatibility.md#flow-preview-api) on source, binary and semantic compatibility.
+Flow declarations marked with `@ExperimentalCoroutinesApi` have [the same guarantees](/docs/compatibility.md#experimental-api) as regular experimental API.
+Please note that API marked with `@FlowPreview` have [weak guarantees](/docs/compatibility.md#flow-preview-api) on source, binary and semantic compatibility.
### Changelog
-* A new [guide section](/docs/topics/flow.md) about Flow.
+* A new [guide section](/docs/flow.md) about Flow.
* `CoroutineDispatcher.asExecutor` extension (#1450).
* Fixed bug when `select` statement could report the same exception twice (#1433).
* Fixed context preservation in `flatMapMerge` in a case when collected values were immediately emitted to another flow (#1440).
@@ -409,11 +371,11 @@ A lot of `Flow` improvements:
* `flatMap`, `merge` and `concatenate` are replaced with `flattenConcat`, `flattenMerge`, `flatMapConcat` and `flatMapMerge`.
* Various documentation improvements and minor bug fixes.
-Note that `Flow` **is not** leaving its [preview status](/docs/topics/compatibility.md#flow-preview-api).
+Note that `Flow` **is not** leaving its [preview status](/docs/compatibility.md#flow-preview-api).
## Version 1.2.0-alpha-2
-This release contains major [feature preview](/docs/topics/compatibility.md#flow-preview-api): cold streams aka `Flow` (#254).
+This release contains major [feature preview](/docs/compatibility.md#flow-preview-api): cold streams aka `Flow` (#254).
Performance:
* Performance of `Dispatcher.Main` initialization is significantly improved (#878).
@@ -536,7 +498,7 @@ Maintenance release:
* `Job()` wih parent now also cancels parent on failure consistently with other scopes.
* All coroutine builders and `Job` implementations propagate failure to the parent unless it is a `CancellationException`.
* Note, "scoping" builders don't "cancel the parent" verbatim, but rethrow the corresponding exception to the caller for handling.
- * `SupervisorJob()` and `supervisorScope { ... }` are introduced, allowing for a flexible implementation of custom exception-handling policies, see a [new section in the guide on supervision](docs/topics/exception-handling.md#supervision).
+ * `SupervisorJob()` and `supervisorScope { ... }` are introduced, allowing for a flexible implementation of custom exception-handling policies, see a [new section in the guide on supervision](docs/exception-handling.md#supervision).
* Got rid of `awaitAll` in documentation and rewrote `currentScope` section (see #624).
* **[Major]** Coroutine scheduler is used for `Dispatchers.Default` by default instead of deprecated `CommonPool`.
* "`DefaultDispatcher`" is used as a public name of the default impl (you'll see it thread names and in the guide).
@@ -595,7 +557,7 @@ Visible consequences of include more robust exception handling for large corouti
* `currentScope` and `coroutineScope` builders are introduced to extract and provide `CoroutineScope`.
* Factory methods to create `CoroutineScope` from `CoroutineContext` are introduced.
* `CoroutineScope.isActive` became an extension property.
- * New sections about structured concurrency in core guide: ["Structured concurrency"](docs/topics/coroutines-guide.md#structured-concurrency), ["Scope builder"](docs/topics/coroutines-guide.md#scope-builder) and ["Structured concurrency with async"](docs/topics/coroutines-guide.md#structured-concurrency-with-async).
+ * New sections about structured concurrency in core guide: ["Structured concurrency"](docs/coroutines-guide.md#structured-concurrency), ["Scope builder"](docs/coroutines-guide.md#scope-builder) and ["Structured concurrency with async"](docs/coroutines-guide.md#structured-concurrency-with-async).
* New section in UI guide with Android example: ["Structured concurrency, lifecycle and coroutine parent-child hierarchy"](ui/coroutines-guide-ui.md#structured-concurrency,-lifecycle-and-coroutine-parent-child-hierarchy).
* Deprecated reactive API is removed.
* Dispatchers are renamed and grouped in the Dispatchers object (see #41 and #533):
@@ -615,7 +577,7 @@ Visible consequences of include more robust exception handling for large corouti
## Version 0.25.0
* Major rework on exception-handling and cancellation in coroutines (see #333, #452 and #451):
- * New ["Exception Handling" section in the guide](docs/topics/coroutines-guide.md#exception-handling) explains exceptions in coroutines.
+ * New ["Exception Handling" section in the guide](docs/coroutines-guide.md#exception-handling) explains exceptions in coroutines.
* Semantics of `Job.cancel` resulting `Boolean` value changed &mdash; `true` means exception was handled by the job, caller shall handle otherwise.
* Exceptions are properly propagated from children to parents.
* Installed `CoroutineExceptionHandler` for a family of coroutines receives one aggregated exception in case of failure.
@@ -624,7 +586,7 @@ Visible consequences of include more robust exception handling for large corouti
* Introduced support for thread-local elements in coroutines context (see #119):
* `ThreadContextElement` API for custom thread-context sensitive context elements.
* `ThreadLocal.asContextElement()` extension function to convert an arbitrary thread-local into coroutine context element.
- * New ["Thread-local data" subsection in the guide](docs/topics/coroutines-guide.md#thread-local-data) with examples.
+ * New ["Thread-local data" subsection in the guide](docs/coroutines-guide.md#thread-local-data) with examples.
* SLF4J Mapped Diagnostic Context (MDC) integration is provided via `MDCContext` element defined in [`kotlinx-coroutines-slf4j`](integration/kotlinx-coroutines-slf4j/README.md) integration module.
* Introduced IO dispatcher to offload blocking I/O-intensive tasks (see #79).
* Introduced `ExecutorCoroutineDispatcher` instead of `CloseableCoroutineDispatcher` (see #385).
@@ -857,7 +819,7 @@ Visible consequences of include more robust exception handling for large corouti
* Fixed `actor` and `produce` so that a cancellation of a Job cancels the underlying channel (closes and removes all the pending messages).
* Fixed sporadic failure of `example-context-06` (see #160)
* Fixed hang of `Job.start` on lazy coroutine with attached `invokeOnCompletion` handler.
-* A more gradual introduction to `runBlocking` and coroutines in the [guide](docs/topics/coroutines-guide.md) (see #166).
+* A more gradual introduction to `runBlocking` and coroutines in the [guide](docs/coroutines-guide.md) (see #166).
## Version 0.19.3
@@ -908,7 +870,7 @@ Visible consequences of include more robust exception handling for large corouti
* When a context is explicitly specified, `newCoroutineContext` function checks if there is any
interceptor/dispatcher defined in the context and uses `DefaultDispatcher` if there is none.
* `DefaultDispatcher` is currently defined to be equal to `CommonPool`.
- * Examples in the [guide](docs/topics/coroutines-guide.md) now start with `launch { ... }` code and explanation on the nature
+ * Examples in the [guide](docs/coroutines-guide.md) now start with `launch { ... }` code and explanation on the nature
and the need for coroutine context starts in "Coroutine context and dispatchers" section.
* Parent coroutines now wait for their children (see #125):
* Job _completing_ state is introduced in documentation as a state in which parent coroutine waits for its children.
@@ -968,7 +930,7 @@ Visible consequences of include more robust exception handling for large corouti
## Version 0.17
* `CompletableDeferred` is introduced as a set-once event-like communication primitive (see #70).
- * [Coroutines guide](docs/topics/coroutines-guide.md) uses it in a section on actors.
+ * [Coroutines guide](docs/coroutines-guide.md) uses it in a section on actors.
* `CompletableDeferred` is an interface with private impl (courtesy of @fvasco, see #86).
* It extends `Deferred` interface with `complete` and `completeExceptionally` functions.
* `Job.join` and `Deferred.await` wait until a cancelled coroutine stops execution (see #64).
@@ -1114,7 +1076,7 @@ Visible consequences of include more robust exception handling for large corouti
* `actor` coroutine builder.
* Couple more examples for "Shared mutable state and concurrency" section and
"Channels are fair" section with ping-pong table example
- in [coroutines guide](docs/topics/coroutines-guide.md).
+ in [coroutines guide](docs/coroutines-guide.md).
## Version 0.11-rc
@@ -1122,7 +1084,7 @@ Visible consequences of include more robust exception handling for large corouti
* `Mutex` is moved to `kotlinx.coroutines.sync` package.
* `ClosedSendChannelException` is a subclass of `CancellationException` now.
* New sections on "Shared mutable state and concurrency" and "Select expression"
- in [coroutines guide](docs/topics/coroutines-guide.md).
+ in [coroutines guide](docs/coroutines-guide.md).
## Version 0.10-rc
@@ -1150,7 +1112,7 @@ Visible consequences of include more robust exception handling for large corouti
So, lazy coroutines do not need a separate state variable to track their started/not-started (new/active) status.
* Exception transparency in `Job.cancel` (original cause is rethrown).
* Clarified possible states for `Job`/`CancellableContinuation`/`Deferred` in docs.
-* Example on async-style functions and links to API reference site from [coroutines guide](docs/topics/coroutines-guide.md).
+* Example on async-style functions and links to API reference site from [coroutines guide](docs/coroutines-guide.md).
## Version 0.7-beta
@@ -1158,12 +1120,12 @@ Visible consequences of include more robust exception handling for large corouti
`RendezvousChannel` and `ArrayChannel` implementations, `Channel()` factory function and `buildChannel{}`
coroutines builder.
* `Here` context is renamed to `Unconfined` (the old name is deprecated).
-* A [guide on coroutines](docs/topics/coroutines-guide.md) is expanded: sections on contexts and channels.
+* A [guide on coroutines](docs/coroutines-guide.md) is expanded: sections on contexts and channels.
## Version 0.6-beta
* Switched to Kotlin version 1.1.0-beta-37.
-* A [guide on coroutines](docs/topics/coroutines-guide.md) is expanded.
+* A [guide on coroutines](docs/coroutines-guide.md) is expanded.
## Version 0.5-beta
@@ -1176,7 +1138,7 @@ Visible consequences of include more robust exception handling for large corouti
has a default implementation that returns `true`.
* `NonCancellable` context is introduced.
* Performance optimizations for cancellable continuations (fewer objects created).
-* A [guide on coroutines](docs/topics/coroutines-guide.md) is added.
+* A [guide on coroutines](docs/coroutines-guide.md) is added.
## Version 0.4-beta
diff --git a/METADATA b/METADATA
index 17612396..9859a06a 100644
--- a/METADATA
+++ b/METADATA
@@ -5,11 +5,11 @@ third_party {
type: GIT
value: "https://github.com/Kotlin/kotlinx.coroutines"
}
- version: "1.4.3"
+ version: "1.4.1"
license_type: NOTICE
last_upgrade_date {
- year: 2021
- month: 5
- day: 5
+ year: 2020
+ month: 11
+ day: 25
}
}
diff --git a/README.md b/README.md
index 08417dd0..7bd8e5a7 100644
--- a/README.md
+++ b/README.md
@@ -2,12 +2,12 @@
[![official JetBrains project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0)
-[![Download](https://api.bintray.com/packages/kotlin/kotlinx/kotlinx.coroutines/images/download.svg?version=1.4.3) ](https://bintray.com/kotlin/kotlinx/kotlinx.coroutines/1.4.3)
-[![Kotlin](https://img.shields.io/badge/kotlin-1.4.30-blue.svg?logo=kotlin)](http://kotlinlang.org)
+[![Download](https://api.bintray.com/packages/kotlin/kotlinx/kotlinx.coroutines/images/download.svg?version=1.4.1) ](https://bintray.com/kotlin/kotlinx/kotlinx.coroutines/1.4.1)
+[![Kotlin](https://img.shields.io/badge/kotlin-1.4.0-blue.svg?logo=kotlin)](http://kotlinlang.org)
[![Slack channel](https://img.shields.io/badge/chat-slack-green.svg?logo=slack)](https://kotlinlang.slack.com/messages/coroutines/)
Library support for Kotlin coroutines with [multiplatform](#multiplatform) support.
-This is a companion version for Kotlin `1.4.30` release.
+This is a companion version for Kotlin `1.4.0` release.
```kotlin
suspend fun main() = coroutineScope {
@@ -45,7 +45,6 @@ suspend fun main() = coroutineScope {
* [debug](kotlinx-coroutines-debug/README.md) &mdash; debug utilities for coroutines:
* [DebugProbes] API to probe, keep track of, print and dump active coroutines;
* [CoroutinesTimeout] test rule to automatically dump coroutines on test timeout.
- * Automatic integration with [BlockHound](https://github.com/reactor/BlockHound).
* [reactive](reactive/README.md) &mdash; modules that provide builders and iteration support for various reactive streams libraries:
* Reactive Streams ([Publisher.collect], [Publisher.awaitSingle], [kotlinx.coroutines.reactive.publish], etc),
* Flow (JDK 9) (the same interface as for Reactive Streams),
@@ -65,10 +64,10 @@ suspend fun main() = coroutineScope {
* [Deep dive into Coroutines](https://www.youtube.com/watch?v=YrrUCSi72E8) (Roman Elizarov at KotlinConf 2017, [slides](https://www.slideshare.net/elizarov/deep-dive-into-coroutines-on-jvm-kotlinconf-2017))
* [Kotlin Coroutines in Practice](https://www.youtube.com/watch?v=a3agLJQ6vt8) (Roman Elizarov at KotlinConf 2018, [slides](https://www.slideshare.net/elizarov/kotlin-coroutines-in-practice-kotlinconf-2018))
* Guides and manuals:
- * [Guide to kotlinx.coroutines by example](https://kotlinlang.org/docs/coroutines-guide.html) (**read it first**)
+ * [Guide to kotlinx.coroutines by example](https://kotlinlang.org/docs/reference/coroutines/coroutines-guide.html) (**read it first**)
* [Guide to UI programming with coroutines](ui/coroutines-guide-ui.md)
- * [Debugging capabilities in kotlinx.coroutines](docs/topics/debugging.md)
-* [Compatibility policy and experimental annotations](docs/topics/compatibility.md)
+ * [Debugging capabilities in kotlinx.coroutines](docs/debugging.md)
+* [Compatibility policy and experimental annotations](docs/compatibility.md)
* [Change log for kotlinx.coroutines](CHANGES.md)
* [Coroutines design document (KEEP)](https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md)
* [Full kotlinx.coroutines API reference](https://kotlin.github.io/kotlinx.coroutines)
@@ -87,7 +86,7 @@ Add dependencies (you can also add other modules that you need):
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-core</artifactId>
- <version>1.4.3</version>
+ <version>1.4.1</version>
</dependency>
```
@@ -95,7 +94,7 @@ And make sure that you use the latest Kotlin version:
```xml
<properties>
- <kotlin.version>1.4.30</kotlin.version>
+ <kotlin.version>1.4.0</kotlin.version>
</properties>
```
@@ -105,7 +104,7 @@ Add dependencies (you can also add other modules that you need):
```groovy
dependencies {
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1'
}
```
@@ -113,15 +112,15 @@ And make sure that you use the latest Kotlin version:
```groovy
buildscript {
- ext.kotlin_version = '1.4.30'
+ ext.kotlin_version = '1.4.0'
}
```
-Make sure that you have `mavenCentral()` in the list of repositories:
+Make sure that you have either `jcenter()` or `mavenCentral()` in the list of repositories:
```
repository {
- mavenCentral()
+ jcenter()
}
```
@@ -131,7 +130,7 @@ Add dependencies (you can also add other modules that you need):
```groovy
dependencies {
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1")
}
```
@@ -139,11 +138,24 @@ And make sure that you use the latest Kotlin version:
```groovy
plugins {
- kotlin("jvm") version "1.4.30"
+ kotlin("jvm") version "1.4.0"
}
```
-Make sure that you have `mavenCentral()` in the list of repositories.
+Make sure that you have either `jcenter()` or `mavenCentral()` in the list of repositories.
+
+### Multiplatform
+
+Core modules of `kotlinx.coroutines` are also available for
+[Kotlin/JS](#js) and [Kotlin/Native](#native).
+In common code that should get compiled for different platforms, you can add dependency to `kotlinx-coroutines-core` right to the `commonMain` source set:
+```groovy
+commonMain {
+ dependencies {
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1")
+ }
+}
+```
### Android
@@ -151,18 +163,18 @@ Add [`kotlinx-coroutines-android`](ui/kotlinx-coroutines-android)
module as dependency when using `kotlinx.coroutines` on Android:
```groovy
-implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3'
+implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
```
This gives you access to Android [Dispatchers.Main]
coroutine dispatcher and also makes sure that in case of crashed coroutine with unhandled exception this
-exception is logged before crashing Android application, similarly to the way uncaught exceptions in
-threads are handled by Android runtime.
+exception is logged before crashing Android application, similarly to the way uncaught exceptions in
+threads are handled by Android runtime.
#### R8 and ProGuard
R8 and ProGuard rules are bundled into the [`kotlinx-coroutines-android`](ui/kotlinx-coroutines-android) module.
-For more details see ["Optimization" section for Android](ui/kotlinx-coroutines-android/README.md#optimization).
+For more details see ["Optimization" section for Android](ui/kotlinx-coroutines-android/README.md#optimization).
#### Avoiding including the debug infrastructure in the resulting APK
@@ -175,40 +187,27 @@ packagingOptions {
}
```
-### Multiplatform
+### JS
-Core modules of `kotlinx.coroutines` are also available for
-[Kotlin/JS](https://kotlinlang.org/docs/reference/js-overview.html) and [Kotlin/Native](https://kotlinlang.org/docs/reference/native-overview.html).
-
-In common code that should get compiled for different platforms, you can add dependency to `kotlinx-coroutines-core` right to the `commonMain` source set:
-```groovy
-commonMain {
- dependencies {
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3")
- }
-}
-```
-
-No more additional dependencies is needed, platform-specific artifacts will be resolved automatically via Gradle metadata available since Gradle 5.3.
-
-Platform-specific dependencies are recommended to be used only for non-multiplatform projects that are compiled only for target platform.
-
-#### JS
-
-Kotlin/JS version of `kotlinx.coroutines` is published as
-[`kotlinx-coroutines-core-js`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-js/1.4.3/jar)
-(follow the link to get the dependency declaration snippet) and as [`kotlinx-coroutines-core`](https://www.npmjs.com/package/kotlinx-coroutines-core) NPM package.
+[Kotlin/JS](https://kotlinlang.org/docs/reference/js-overview.html) version of `kotlinx.coroutines` is published as
+[`kotlinx-coroutines-core-js`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-js/1.4.1/jar)
+(follow the link to get the dependency declaration snippet).
+
+You can also use [`kotlinx-coroutines-core`](https://www.npmjs.com/package/kotlinx-coroutines-core) package via NPM.
-#### Native
+### Native
-Kotlin/Native version of `kotlinx.coroutines` is published as
-[`kotlinx-coroutines-core-$platform`](https://mvnrepository.com/search?q=kotlinx-coroutines-core-) where `$platform` is
-the target Kotlin/Native platform. [List of currently supported targets](https://github.com/Kotlin/kotlinx.coroutines/blob/master/gradle/compile-native-multiplatform.gradle#L16).
+[Kotlin/Native](https://kotlinlang.org/docs/reference/native-overview.html) version of `kotlinx.coroutines` is published as
+[`kotlinx-coroutines-core-native`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-native/1.4.1/jar)
+(follow the link to get the dependency declaration snippet).
+Only single-threaded code (JS-style) on Kotlin/Native is currently supported.
+Kotlin/Native supports only Gradle version 4.10 and you need to enable Gradle metadata in your
+`settings.gradle` file:
-Only single-threaded code (JS-style) on Kotlin/Native is supported in stable versions.
-Additionally, special `-native-mt` version is released on a regular basis, for the state of multi-threaded coroutines support
-please follow the [corresponding issue](https://github.com/Kotlin/kotlinx.coroutines/issues/462) for the additional details.
+```groovy
+enableFeaturePreview('GRADLE_METADATA')
+```
Since Kotlin/Native does not generally provide binary compatibility between versions,
you should use the same version of Kotlin/Native compiler as was used to build `kotlinx.coroutines`.
@@ -219,7 +218,6 @@ See [Contributing Guidelines](CONTRIBUTING.md).
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
-
[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
@@ -241,81 +239,52 @@ See [Contributing Guidelines](CONTRIBUTING.md).
[Promise.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/kotlin.js.-promise/await.html
[promise]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/promise.html
[Window.asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/org.w3c.dom.-window/as-coroutine-dispatcher.html
-
<!--- INDEX kotlinx.coroutines.flow -->
-
[Flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html
[_flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow.html
[filter]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/filter.html
[map]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/map.html
-
<!--- INDEX kotlinx.coroutines.channels -->
-
[Channel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel/index.html
-
<!--- INDEX kotlinx.coroutines.selects -->
-
[select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html
-
<!--- INDEX kotlinx.coroutines.sync -->
-
[Mutex]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/index.html
[Semaphore]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-semaphore/index.html
-
<!--- MODULE kotlinx-coroutines-test -->
<!--- INDEX kotlinx.coroutines.test -->
-
[Dispatchers.setMain]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/kotlinx.coroutines.-dispatchers/set-main.html
[TestCoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-scope/index.html
-
<!--- MODULE kotlinx-coroutines-debug -->
<!--- INDEX kotlinx.coroutines.debug -->
-
[DebugProbes]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-debug/kotlinx.coroutines.debug/-debug-probes/index.html
-
<!--- INDEX kotlinx.coroutines.debug.junit4 -->
-
[CoroutinesTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-debug/kotlinx.coroutines.debug.junit4/-coroutines-timeout/index.html
-
<!--- MODULE kotlinx-coroutines-slf4j -->
<!--- INDEX kotlinx.coroutines.slf4j -->
-
[MDCContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-slf4j/kotlinx.coroutines.slf4j/-m-d-c-context/index.html
-
<!--- MODULE kotlinx-coroutines-jdk8 -->
<!--- INDEX kotlinx.coroutines.future -->
-
[CompletionStage.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/java.util.concurrent.-completion-stage/await.html
-
<!--- MODULE kotlinx-coroutines-guava -->
<!--- INDEX kotlinx.coroutines.guava -->
-
[ListenableFuture.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/com.google.common.util.concurrent.-listenable-future/await.html
-
<!--- MODULE kotlinx-coroutines-play-services -->
<!--- INDEX kotlinx.coroutines.tasks -->
-
[Task.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-play-services/kotlinx.coroutines.tasks/com.google.android.gms.tasks.-task/await.html
-
<!--- MODULE kotlinx-coroutines-reactive -->
<!--- INDEX kotlinx.coroutines.reactive -->
-
[Publisher.collect]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/collect.html
[Publisher.awaitSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/await-single.html
[kotlinx.coroutines.reactive.publish]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/publish.html
-
<!--- MODULE kotlinx-coroutines-rx2 -->
<!--- INDEX kotlinx.coroutines.rx2 -->
-
[rxFlowable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/rx-flowable.html
[rxSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/rx-single.html
-
<!--- MODULE kotlinx-coroutines-rx2 -->
<!--- INDEX kotlinx.coroutines.rx2 -->
<!--- MODULE kotlinx-coroutines-reactor -->
<!--- INDEX kotlinx.coroutines.reactor -->
-
[flux]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/flux.html
[mono]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/mono.html
-
<!--- END -->
diff --git a/RELEASE.md b/RELEASE.md
index c9fd83fb..b2a08b67 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -18,7 +18,9 @@ To release new `<version>` of `kotlinx-coroutines`:
* [`kotlinx-coroutines-test/README.md`](kotlinx-coroutines-test/README.md)
* [`coroutines-guide-ui.md`](ui/coroutines-guide-ui.md)
* Properties
- * [`gradle.properties`](gradle.properties)
+ * [`gradle.properties`](gradle.properties)
+ * [`ui/kotlinx-coroutines-android/example-app/gradle.properties`](ui/kotlinx-coroutines-android/example-app/gradle.properties)
+ * [`ui/kotlinx-coroutines-android/animation-app/gradle.properties`](ui/kotlinx-coroutines-android/animation-app/gradle.properties)
* Make sure to **exclude** `CHANGES.md` from replacements.
As an alternative approach you can use `./bump-version.sh old_version new_version`
@@ -59,9 +61,10 @@ To release new `<version>` of `kotlinx-coroutines`:
(make sure you have [Docker](https://www.docker.com/) installed first): <br>
`site/deploy.sh <version> push`
-4. In [Nexus](https://oss.sonatype.org/#stagingRepositories) admin interface:
- * Close the repository and wait for it to verify.
- * Release the repository.
+4. In [Bintray](https://bintray.com/kotlin/kotlinx/kotlinx.coroutines) admin interface:
+ * Publish artifacts of the new version.
+ * Wait until newly published version becomes the most recent.
+ * Sync to Maven Central.
5. Announce new release in [Slack](https://kotlinlang.slack.com)
diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts
index ce0bff1c..b60dcbc8 100644
--- a/benchmarks/build.gradle.kts
+++ b/benchmarks/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("UnstableApiUsage")
diff --git a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabble.java b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabble.java
index 6d9169d3..04f72103 100644
--- a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabble.java
+++ b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabble.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble;
diff --git a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabbleOpt.java b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabbleOpt.java
index 2d900cad..71c7604d 100644
--- a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabbleOpt.java
+++ b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/RxJava2PlaysScrabbleOpt.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble;
diff --git a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableCharSequence.java b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableCharSequence.java
index 0acf98d0..5f93b4ee 100644
--- a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableCharSequence.java
+++ b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableCharSequence.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble.optimizations;
diff --git a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableSplit.java b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableSplit.java
index 1c78f5ec..af8696c8 100644
--- a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableSplit.java
+++ b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/FlowableSplit.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble.optimizations;
diff --git a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/StringFlowable.java b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/StringFlowable.java
index f51112b4..cf6cc79b 100644
--- a/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/StringFlowable.java
+++ b/benchmarks/src/jmh/java/benchmarks/flow/scrabble/optimizations/StringFlowable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble.optimizations;
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/ChannelProducerConsumerBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/ChannelProducerConsumerBenchmark.kt
index 0fa50489..deeea77a 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/ChannelProducerConsumerBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/ChannelProducerConsumerBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkBenchmark.kt
index f706d3aa..6c5b6231 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks
@@ -10,7 +10,7 @@ import org.openjdk.jmh.annotations.*
import java.util.concurrent.*
import kotlin.coroutines.*
-@Warmup(iterations = 7, time = 1)
+@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 5, time = 1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@@ -41,7 +41,7 @@ open class ChannelSinkBenchmark {
private suspend inline fun run(context: CoroutineContext): Int {
return Channel
- .range(1, 10_000, context)
+ .range(1, 1_000_000, context)
.filter(context) { it % 4 == 0 }
.fold(0) { a, b -> a + b }
}
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkDepthBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkDepthBenchmark.kt
deleted file mode 100644
index d3f6be67..00000000
--- a/benchmarks/src/jmh/kotlin/benchmarks/ChannelSinkDepthBenchmark.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package benchmarks
-
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-import org.openjdk.jmh.annotations.*
-import java.util.concurrent.*
-import kotlin.coroutines.*
-
-@Warmup(iterations = 7, time = 1)
-@Measurement(iterations = 5, time = 1)
-@BenchmarkMode(Mode.AverageTime)
-@OutputTimeUnit(TimeUnit.MILLISECONDS)
-@State(Scope.Benchmark)
-@Fork(2)
-open class ChannelSinkDepthBenchmark {
- private val tl = ThreadLocal.withInitial({ 42 })
-
- private val unconfinedOneElement = Dispatchers.Unconfined + tl.asContextElement()
-
- @Benchmark
- fun depth1(): Int = runBlocking {
- run(1, unconfinedOneElement)
- }
-
- @Benchmark
- fun depth10(): Int = runBlocking {
- run(10, unconfinedOneElement)
- }
-
- @Benchmark
- fun depth100(): Int = runBlocking {
- run(100, unconfinedOneElement)
- }
-
- @Benchmark
- fun depth1000(): Int = runBlocking {
- run(1000, unconfinedOneElement)
- }
-
- private suspend inline fun run(callTraceDepth: Int, context: CoroutineContext): Int {
- return Channel
- .range(1, 10_000, context)
- .filter(callTraceDepth, context) { it % 4 == 0 }
- .fold(0) { a, b -> a + b }
- }
-
- private fun Channel.Factory.range(start: Int, count: Int, context: CoroutineContext) =
- GlobalScope.produce(context) {
- for (i in start until (start + count))
- send(i)
- }
-
- // Migrated from deprecated operators, are good only for stressing channels
-
- private fun ReceiveChannel<Int>.filter(
- callTraceDepth: Int,
- context: CoroutineContext = Dispatchers.Unconfined,
- predicate: suspend (Int) -> Boolean
- ): ReceiveChannel<Int> =
- GlobalScope.produce(context, onCompletion = { cancel() }) {
- deeplyNestedFilter(this, callTraceDepth, predicate)
- }
-
- private suspend fun ReceiveChannel<Int>.deeplyNestedFilter(
- sink: ProducerScope<Int>,
- depth: Int,
- predicate: suspend (Int) -> Boolean
- ) {
- if (depth <= 1) {
- for (e in this) {
- if (predicate(e)) sink.send(e)
- }
- } else {
- deeplyNestedFilter(sink, depth - 1, predicate)
- require(true) // tail-call
- }
- }
-
- private suspend inline fun <E, R> ReceiveChannel<E>.fold(initial: R, operation: (acc: R, E) -> R): R {
- var accumulator = initial
- consumeEach {
- accumulator = operation(accumulator, it)
- }
- return accumulator
- }
-}
-
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/ParametrizedDispatcherBase.kt b/benchmarks/src/jmh/kotlin/benchmarks/ParametrizedDispatcherBase.kt
index 9948a371..b635d1ef 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/ParametrizedDispatcherBase.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/ParametrizedDispatcherBase.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/SemaphoreBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/SemaphoreBenchmark.kt
index 40ddc8ec..5da5dc89 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/SemaphoreBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/SemaphoreBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/akka/PingPongAkkaBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/akka/PingPongAkkaBenchmark.kt
index df940752..ea9aeca9 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/akka/PingPongAkkaBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/akka/PingPongAkkaBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.akka
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/akka/StatefulActorAkkaBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/akka/StatefulActorAkkaBenchmark.kt
index fef641ae..5cfb86dd 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/akka/StatefulActorAkkaBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/akka/StatefulActorAkkaBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.akka
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/CombineFlowsBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/CombineFlowsBenchmark.kt
index be371548..4725ceda 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/CombineFlowsBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/CombineFlowsBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/CombineTwoFlowsBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/CombineTwoFlowsBenchmark.kt
index bc8d8687..f7fbc6cf 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/CombineTwoFlowsBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/CombineTwoFlowsBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/FlatMapMergeBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/FlatMapMergeBenchmark.kt
index 32d35475..f3b2082a 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/FlatMapMergeBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/FlatMapMergeBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/FlowFlattenMergeBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/FlowFlattenMergeBenchmark.kt
index 09d841eb..14989888 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/FlowFlattenMergeBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/FlowFlattenMergeBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/NumbersBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/NumbersBenchmark.kt
index 636b334d..8453f5c7 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/NumbersBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/NumbersBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/SafeFlowBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/SafeFlowBenchmark.kt
index d957bdbe..258df9b0 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/SafeFlowBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/SafeFlowBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/TakeBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/TakeBenchmark.kt
index a0a2decc..1e12e2c3 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/TakeBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/TakeBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/TakeWhileBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/TakeWhileBenchmark.kt
index 7501e2c4..fd3d3cdb 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/TakeWhileBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/TakeWhileBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleBase.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleBase.kt
index b8e1f450..3501bdfe 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleBase.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleBase.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleOpt.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleOpt.kt
index cd27cca0..2573d30d 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleOpt.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/FlowPlaysScrabbleOpt.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/IterableSpliterator.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/IterableSpliterator.kt
index e78d7bd0..32c0d4c8 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/IterableSpliterator.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/IterableSpliterator.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ReactorPlaysScrabble.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ReactorPlaysScrabble.kt
index 1db4dae0..2283d6c3 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ReactorPlaysScrabble.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ReactorPlaysScrabble.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SaneFlowPlaysScrabble.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SaneFlowPlaysScrabble.kt
index 533bc5e6..ad97dfa3 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SaneFlowPlaysScrabble.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SaneFlowPlaysScrabble.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SequencePlaysScrabble.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SequencePlaysScrabble.kt
index e7bd1f5f..fa944fac 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SequencePlaysScrabble.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/SequencePlaysScrabble.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ShakespearePlaysScrabble.kt b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ShakespearePlaysScrabble.kt
index 006d36c0..7beb54cc 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ShakespearePlaysScrabble.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble/ShakespearePlaysScrabble.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.flow.scrabble
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/DispatchersContextSwitchBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/DispatchersContextSwitchBenchmark.kt
index 1fe70926..3012b917 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/DispatchersContextSwitchBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/DispatchersContextSwitchBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/ForkJoinBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/ForkJoinBenchmark.kt
index 20bdfa34..724a5909 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/ForkJoinBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/ForkJoinBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/LaunchBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/LaunchBenchmark.kt
index d64fdd2f..a0de6016 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/LaunchBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/LaunchBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/StatefulAwaitsBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/StatefulAwaitsBenchmark.kt
index c5b34eda..f829573c 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/StatefulAwaitsBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/StatefulAwaitsBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/ConcurrentStatefulActorBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/ConcurrentStatefulActorBenchmark.kt
index 1ffb5207..6ac97ad3 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/ConcurrentStatefulActorBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/ConcurrentStatefulActorBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler.actors
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/CycledActorsBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/CycledActorsBenchmark.kt
index cd212cc1..71018abc 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/CycledActorsBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/CycledActorsBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler.actors
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongActorBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongActorBenchmark.kt
index d696c64f..4c6ae775 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongActorBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongActorBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler.actors
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongWithBlockingContext.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongWithBlockingContext.kt
index a6f0a473..dcbda090 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongWithBlockingContext.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/PingPongWithBlockingContext.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler.actors
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/StatefulActorBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/StatefulActorBenchmark.kt
index eebcec01..01691a2d 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/StatefulActorBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/scheduler/actors/StatefulActorBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.scheduler.actors
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannel.kt b/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannel.kt
index 1f71d8dc..d961dab8 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannel.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.tailcall
diff --git a/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannelBenchmark.kt b/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannelBenchmark.kt
index 9654b6da..7bb962b3 100644
--- a/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannelBenchmark.kt
+++ b/benchmarks/src/jmh/kotlin/benchmarks/tailcall/SimpleChannelBenchmark.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.tailcall
diff --git a/benchmarks/src/main/kotlin/benchmarks/common/BenchmarkUtils.kt b/benchmarks/src/main/kotlin/benchmarks/common/BenchmarkUtils.kt
index 858ecfad..27bc6b7d 100644
--- a/benchmarks/src/main/kotlin/benchmarks/common/BenchmarkUtils.kt
+++ b/benchmarks/src/main/kotlin/benchmarks/common/BenchmarkUtils.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package benchmarks.common
diff --git a/build.gradle b/build.gradle
index 80124e7e..79c7f355 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import org.jetbrains.kotlin.konan.target.HostManager
import org.gradle.util.VersionNumber
@@ -7,6 +7,7 @@ import org.gradle.util.VersionNumber
apply plugin: 'jdk-convention'
apply from: rootProject.file("gradle/experimental.gradle")
+def rootModule = "kotlinx.coroutines"
def coreModule = "kotlinx-coroutines-core"
// Not applicable for Kotlin plugin
def sourceless = ['kotlinx.coroutines', 'site', 'kotlinx-coroutines-bom', 'integration-testing']
@@ -32,10 +33,6 @@ buildscript {
throw new IllegalArgumentException("'kotlin_snapshot_version' should be defined when building with snapshot compiler")
}
}
- // These three flags are enabled in train builds for JVM IR compiler testing
- ext.jvm_ir_enabled = rootProject.properties['enable_jvm_ir'] != null
- ext.jvm_ir_api_check_enabled = rootProject.properties['enable_jvm_ir_api_check'] != null
- ext.native_targets_enabled = rootProject.properties['disable_native_targets'] == null
// Determine if any project dependency is using a snapshot version
ext.using_snapshot_version = build_snapshot_train
@@ -53,7 +50,14 @@ buildscript {
}
repositories {
- maven {url "https://kotlin.bintray.com/kotlinx"}
+ jcenter()
+ maven {
+ url "https://kotlin.bintray.com/kotlinx"
+ credentials {
+ username = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER') ?: ""
+ password = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') ?: ""
+ }
+ }
// Future replacement for kotlin-dev, with cache redirector
maven { url "https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" }
maven {
@@ -63,6 +67,7 @@ buildscript {
password = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') ?: ""
}
}
+ maven { url "https://kotlin.bintray.com/kotlin-eap" }
maven { url "https://jetbrains.bintray.com/kotlin-native-dependencies" }
maven { url "https://plugins.gradle.org/m2/" }
}
@@ -149,10 +154,25 @@ allprojects {
* transitive dependencies was removed from jcenter, thus breaking gradle dependency resolution
*/
google()
- mavenCentral()
+ jcenter()
// Future replacement for kotlin-dev, with cache redirector
maven { url "https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" }
- maven { url "https://kotlin.bintray.com/kotlinx" }
+ maven {
+ url "https://kotlin.bintray.com/kotlin-dev"
+ credentials {
+ username = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER') ?: ""
+ password = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') ?: ""
+ }
+ }
+ maven { url "https://kotlin.bintray.com/kotlin-eap" }
+ maven {
+ url "https://kotlin.bintray.com/kotlinx"
+ credentials {
+ username = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER') ?: ""
+ password = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') ?: ""
+ }
+ }
+ mavenLocal()
}
}
@@ -160,10 +180,10 @@ allprojects {
configure(subprojects.findAll { !sourceless.contains(it.name) && it.name != coreModule }) {
evaluationDependsOn(":$coreModule")
def platform = PlatformKt.platformOf(it)
- apply plugin: "kotlin-${platform}-conventions"
+ apply from: rootProject.file("gradle/compile-${platform}.gradle")
dependencies {
// See comment below for rationale, it will be replaced with "project" dependency
- compile project(":$coreModule")
+ compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version"
// the only way IDEA can resolve test classes
testCompile project(":$coreModule").kotlin.targets.jvm.compilations.test.output.allOutputs
}
@@ -179,8 +199,6 @@ configure(subprojects.findAll { !sourceless.contains(it.name) }) {
kotlinOptions.freeCompilerArgs += experimentalAnnotations.collect { "-Xuse-experimental=" + it }
kotlinOptions.freeCompilerArgs += "-progressive"
kotlinOptions.freeCompilerArgs += "-XXLanguage:+InlineClasses"
- // Disable KT-36770 for RxJava2 integration
- kotlinOptions.freeCompilerArgs += "-XXLanguage:-ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated"
// Remove null assertions to get smaller bytecode on Android
kotlinOptions.freeCompilerArgs += ["-Xno-param-assertions", "-Xno-receiver-assertions", "-Xno-call-assertions"]
}
@@ -219,6 +237,22 @@ if (build_snapshot_train) {
}
}
+/*
+ * Hack to trick nmpp plugin: we are renaming artifacts in order to provide backward compatibility for dependencies,
+ * but publishing plugin does not re-read artifact names for kotlin-jvm projects, so renaming is not applied in pom files
+ * for JVM-only projects.
+ *
+ * We artificially replace "project" dependency with "module" one to have proper names in pom files, but then substitute it
+ * to have out "project" dependency back.
+ */
+configure(subprojects.findAll { it.name != coreModule && it.name != rootModule }) {
+ configurations.all {
+ resolutionStrategy.dependencySubstitution {
+ substitute module("org.jetbrains.kotlinx:kotlinx-coroutines-core:$version") with project(':kotlinx-coroutines-core')
+ }
+ }
+}
+
// Redefine source sets because we are not using 'kotlin/main/fqn' folder convention
configure(subprojects.findAll {
!sourceless.contains(it.name) &&
@@ -289,12 +323,3 @@ knit {
}
knitPrepare.dependsOn getTasksByName("dokka", true)
-
-// Disable binary compatibility check for JVM IR compiler output by default
-if (jvm_ir_enabled) {
- subprojects { project ->
- configure(tasks.matching { it.name == "apiCheck" }) {
- enabled = enabled && jvm_ir_api_check_enabled
- }
- }
-}
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
index 6c373a01..adcbd90f 100644
--- a/buildSrc/build.gradle.kts
+++ b/buildSrc/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import java.util.*
@@ -14,9 +14,11 @@ val buildSnapshotTrain = properties["build_snapshot_train"]?.toString()?.toBoole
repositories {
if (cacheRedirectorEnabled) {
maven("https://cache-redirector.jetbrains.com/plugins.gradle.org/m2")
+ maven("https://cache-redirector.jetbrains.com/dl.bintray.com/kotlin/kotlin-eap")
maven("https://cache-redirector.jetbrains.com/dl.bintray.com/kotlin/kotlin-dev")
} else {
maven("https://plugins.gradle.org/m2")
+ maven("https://dl.bintray.com/kotlin/kotlin-eap")
maven("https://dl.bintray.com/kotlin/kotlin-dev")
}
diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts
index c2e859f6..a6da8fdb 100644
--- a/buildSrc/settings.gradle.kts
+++ b/buildSrc/settings.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
pluginManagement {
val build_snapshot_train: String? by settings
diff --git a/buildSrc/src/main/kotlin/CacheRedirector.kt b/buildSrc/src/main/kotlin/CacheRedirector.kt
index 9f6efd2c..7cf01d8e 100644
--- a/buildSrc/src/main/kotlin/CacheRedirector.kt
+++ b/buildSrc/src/main/kotlin/CacheRedirector.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import org.gradle.api.*
diff --git a/buildSrc/src/main/kotlin/Dokka.kt b/buildSrc/src/main/kotlin/Dokka.kt
index f37aa7c1..dd5f1ea4 100644
--- a/buildSrc/src/main/kotlin/Dokka.kt
+++ b/buildSrc/src/main/kotlin/Dokka.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import org.gradle.api.Project
diff --git a/buildSrc/src/main/kotlin/Idea.kt b/buildSrc/src/main/kotlin/Idea.kt
index 28b4aa55..615b8aad 100644
--- a/buildSrc/src/main/kotlin/Idea.kt
+++ b/buildSrc/src/main/kotlin/Idea.kt
@@ -1,7 +1,3 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
object Idea {
@JvmStatic // for Gradle
val active: Boolean
diff --git a/buildSrc/src/main/kotlin/MavenCentral.kt b/buildSrc/src/main/kotlin/MavenCentral.kt
new file mode 100644
index 00000000..3efaf33f
--- /dev/null
+++ b/buildSrc/src/main/kotlin/MavenCentral.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+import org.gradle.api.Project
+import org.gradle.api.publish.maven.MavenPom
+
+// Pom configuration
+
+fun MavenPom.configureMavenCentralMetadata(project: Project) {
+ name by project.name
+ description by "Coroutines support libraries for Kotlin"
+ url by "https://github.com/Kotlin/kotlinx.coroutines"
+
+ licenses {
+ license {
+ name by "The Apache Software License, Version 2.0"
+ url by "https://www.apache.org/licenses/LICENSE-2.0.txt"
+ distribution by "repo"
+ }
+ }
+
+ developers {
+ developer {
+ id by "JetBrains"
+ name by "JetBrains Team"
+ organization by "JetBrains"
+ organizationUrl by "https://www.jetbrains.com"
+ }
+ }
+
+ scm {
+ url by "https://github.com/Kotlin/kotlinx.coroutines"
+ }
+}
diff --git a/buildSrc/src/main/kotlin/Platform.kt b/buildSrc/src/main/kotlin/Platform.kt
index f22c161b..b667a138 100644
--- a/buildSrc/src/main/kotlin/Platform.kt
+++ b/buildSrc/src/main/kotlin/Platform.kt
@@ -1,7 +1,3 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
import org.gradle.api.Project
// Use from Groovy for now
diff --git a/buildSrc/src/main/kotlin/Projects.kt b/buildSrc/src/main/kotlin/Projects.kt
index dd284b61..109311e8 100644
--- a/buildSrc/src/main/kotlin/Projects.kt
+++ b/buildSrc/src/main/kotlin/Projects.kt
@@ -1,7 +1,3 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
import org.gradle.api.Project
fun Project.version(target: String): String =
diff --git a/buildSrc/src/main/kotlin/Properties.kt b/buildSrc/src/main/kotlin/Properties.kt
index 34314502..a0968ee6 100644
--- a/buildSrc/src/main/kotlin/Properties.kt
+++ b/buildSrc/src/main/kotlin/Properties.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("UnstableApiUsage")
diff --git a/buildSrc/src/main/kotlin/Publishing.kt b/buildSrc/src/main/kotlin/Publishing.kt
deleted file mode 100644
index 5b191bfa..00000000
--- a/buildSrc/src/main/kotlin/Publishing.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-@file:Suppress("UnstableApiUsage")
-
-import org.gradle.api.Project
-import org.gradle.api.artifacts.dsl.*
-import org.gradle.api.publish.maven.*
-import org.gradle.plugins.signing.*
-import java.net.*
-
-// Pom configuration
-
-fun MavenPom.configureMavenCentralMetadata(project: Project) {
- name by project.name
- description by "Coroutines support libraries for Kotlin"
- url by "https://github.com/Kotlin/kotlinx.coroutines"
-
- licenses {
- license {
- name by "The Apache Software License, Version 2.0"
- url by "https://www.apache.org/licenses/LICENSE-2.0.txt"
- distribution by "repo"
- }
- }
-
- developers {
- developer {
- id by "JetBrains"
- name by "JetBrains Team"
- organization by "JetBrains"
- organizationUrl by "https://www.jetbrains.com"
- }
- }
-
- scm {
- url by "https://github.com/Kotlin/kotlinx.coroutines"
- }
-}
-
-fun mavenRepositoryUri(): URI {
- // TODO -SNAPSHOT detection can be made here as well
- val repositoryId: String? = System.getenv("libs.repository.id")
- return if (repositoryId == null) {
- // Using implicitly created staging, for MPP it's likely to be a mistake because
- // publication on TeamCity will create 3 independent staging repositories
- System.err.println("Warning: using an implicitly created staging for coroutines")
- URI("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
- } else {
- URI("https://oss.sonatype.org/service/local/staging/deployByRepositoryId/$repositoryId")
- }
-}
-
-fun configureMavenPublication(rh: RepositoryHandler, project: Project) {
- rh.maven {
- url = mavenRepositoryUri()
- credentials {
- username = project.getSensitiveProperty("libs.sonatype.user")
- password = project.getSensitiveProperty("libs.sonatype.password")
- }
- }
-}
-
-fun configureBintrayPublication(rh: RepositoryHandler, project: Project) {
- rh.maven {
- val user = "kotlin"
- val repo = "kotlinx"
- val name = "kotlinx.coroutines"
- url = URI("https://api.bintray.com/maven/$user/$repo/$name/;publish=0;override=0")
-
- credentials {
- username = project.findProperty("bintrayUser") as? String ?: System.getenv("BINTRAY_USER")
- password = project.findProperty("bintrayApiKey") as? String ?: System.getenv("BINTRAY_API_KEY")
- }
- }
-}
-
-fun signPublicationIfKeyPresent(project: Project, publication: MavenPublication) {
- val keyId = project.getSensitiveProperty("libs.sign.key.id")
- val signingKey = project.getSensitiveProperty("libs.sign.key.private")
- val signingKeyPassphrase = project.getSensitiveProperty("libs.sign.passphrase")
- if (!signingKey.isNullOrBlank()) {
- project.extensions.configure<SigningExtension>("signing") {
- useInMemoryPgpKeys(keyId, signingKey, signingKeyPassphrase)
- sign(publication)
- }
- }
-}
-
-private fun Project.getSensitiveProperty(name: String): String? {
- return project.findProperty(name) as? String ?: System.getenv(name)
-}
diff --git a/buildSrc/src/main/kotlin/RunR8.kt b/buildSrc/src/main/kotlin/RunR8.kt
index b0fccf89..d9eba79b 100644
--- a/buildSrc/src/main/kotlin/RunR8.kt
+++ b/buildSrc/src/main/kotlin/RunR8.kt
@@ -1,7 +1,3 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.JavaExec
diff --git a/buildSrc/src/main/kotlin/UnpackAar.kt b/buildSrc/src/main/kotlin/UnpackAar.kt
index b3152d7a..c7d0b53d 100644
--- a/buildSrc/src/main/kotlin/UnpackAar.kt
+++ b/buildSrc/src/main/kotlin/UnpackAar.kt
@@ -1,7 +1,3 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
import org.gradle.api.artifacts.transform.InputArtifact
import org.gradle.api.artifacts.transform.TransformAction
import org.gradle.api.artifacts.transform.TransformOutputs
diff --git a/buildSrc/src/main/kotlin/jdk-convention.gradle.kts b/buildSrc/src/main/kotlin/jdk-convention.gradle.kts
index 64bd90dc..8bc1abf1 100644
--- a/buildSrc/src/main/kotlin/jdk-convention.gradle.kts
+++ b/buildSrc/src/main/kotlin/jdk-convention.gradle.kts
@@ -1,7 +1,3 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
import org.gradle.api.JavaVersion
if (!JavaVersion.current().isJava11Compatible) {
diff --git a/buildSrc/src/main/kotlin/kotlin-js-conventions.gradle.kts b/buildSrc/src/main/kotlin/kotlin-js-conventions.gradle.kts
deleted file mode 100644
index c1897ca7..00000000
--- a/buildSrc/src/main/kotlin/kotlin-js-conventions.gradle.kts
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-// Platform-specific configuration to compile JS modules
-
-import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile
-
-plugins {
- kotlin("js")
-}
-
-dependencies {
- testImplementation(kotlin("test-js"))
-}
-
-kotlin {
- js(LEGACY) {
- moduleName = project.name.removeSuffix("-js")
- }
-
- sourceSets {
- main {
- kotlin.srcDirs("src")
- resources.srcDirs("resources")
- }
- test {
- kotlin.srcDirs("test")
- resources.srcDirs("test-resources")
- }
- }
-}
-
-tasks.withType<KotlinJsCompile> {
- kotlinOptions {
- moduleKind = "umd"
- sourceMap = true
- metaInfo = true
- }
-}
diff --git a/buildSrc/src/main/kotlin/kotlin-jvm-conventions.gradle.kts b/buildSrc/src/main/kotlin/kotlin-jvm-conventions.gradle.kts
deleted file mode 100644
index 89007718..00000000
--- a/buildSrc/src/main/kotlin/kotlin-jvm-conventions.gradle.kts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-// Platform-specific configuration to compile JVM modules
-
-import org.gradle.api.*
-
-plugins {
- kotlin("jvm")
-}
-
-java {
- sourceCompatibility = JavaVersion.VERSION_1_6
- targetCompatibility = JavaVersion.VERSION_1_6
-}
-
-if (rootProject.extra.get("jvm_ir_enabled") as Boolean) {
- kotlin.target.compilations.configureEach {
- kotlinOptions.useIR = true
- }
-}
-
-dependencies {
- testCompile(kotlin("test"))
- // Workaround to make addSuppressed work in tests
- testCompile(kotlin("reflect"))
- testCompile(kotlin("stdlib-jdk7"))
- testCompile(kotlin("test-junit"))
- testCompile("junit:junit:${version("junit")}")
-}
-
-tasks.compileKotlin {
- kotlinOptions {
- freeCompilerArgs += listOf("-Xexplicit-api=strict")
- }
-}
-
-tasks.withType<Test> {
- testLogging {
- showStandardStreams = true
- events("passed", "failed")
- }
- val stressTest = project.properties["stressTest"]
- if (stressTest != null) systemProperties["stressTest"] = stressTest
-}
diff --git a/bump-version.sh b/bump-version.sh
index ae0fc0b0..00930cbd 100755
--- a/bump-version.sh
+++ b/bump-version.sh
@@ -20,6 +20,8 @@ update_version "kotlinx-coroutines-core/README.md"
update_version "kotlinx-coroutines-debug/README.md"
update_version "kotlinx-coroutines-test/README.md"
update_version "ui/coroutines-guide-ui.md"
+update_version "ui/kotlinx-coroutines-android/example-app/gradle.properties"
+update_version "ui/kotlinx-coroutines-android/animation-app/gradle.properties"
update_version "gradle.properties"
# Escape dots, e.g. 1.0.0 -> 1\.0\.0
diff --git a/coroutines-guide.md b/coroutines-guide.md
index 3b4707cf..09cfb93c 100644
--- a/coroutines-guide.md
+++ b/coroutines-guide.md
@@ -1,14 +1,126 @@
-The main coroutines guide has moved to the [docs folder](docs/topics/coroutines-guide.md) and split up into smaller documents.
+The main coroutines guide has moved to the [docs folder](docs/coroutines-guide.md) and split up into smaller documents.
## Table of contents
-<!--- TOC_REF docs/topics/coroutines-basics.md -->
-<!--- TOC_REF docs/topics/cancellation-and-timeouts.md -->
-<!--- TOC_REF docs/topics/composing-suspending-functions.md -->
-<!--- TOC_REF docs/topics/coroutine-context-and-dispatchers.md -->
-<!--- TOC_REF docs/topics/flow.md -->
-<!--- TOC_REF docs/topics/channels.md -->
-<!--- TOC_REF docs/topics/exception-handling.md -->
-<!--- TOC_REF docs/topics/shared-mutable-state-and-concurrency.md -->
-<!--- TOC_REF docs/topics/select-expression.md -->
+<!--- TOC_REF docs/basics.md -->
+* <a name='coroutine-basics'></a>[Coroutine Basics](docs/basics.md#coroutine-basics)
+ * <a name='your-first-coroutine'></a>[Your first coroutine](docs/basics.md#your-first-coroutine)
+ * <a name='bridging-blocking-and-non-blocking-worlds'></a>[Bridging blocking and non-blocking worlds](docs/basics.md#bridging-blocking-and-non-blocking-worlds)
+ * <a name='waiting-for-a-job'></a>[Waiting for a job](docs/basics.md#waiting-for-a-job)
+ * <a name='structured-concurrency'></a>[Structured concurrency](docs/basics.md#structured-concurrency)
+ * <a name='scope-builder'></a>[Scope builder](docs/basics.md#scope-builder)
+ * <a name='extract-function-refactoring'></a>[Extract function refactoring](docs/basics.md#extract-function-refactoring)
+ * <a name='coroutines-are-light-weight'></a>[Coroutines ARE light-weight](docs/basics.md#coroutines-are-light-weight)
+ * <a name='global-coroutines-are-like-daemon-threads'></a>[Global coroutines are like daemon threads](docs/basics.md#global-coroutines-are-like-daemon-threads)
+<!--- TOC_REF docs/cancellation-and-timeouts.md -->
+* <a name='cancellation-and-timeouts'></a>[Cancellation and Timeouts](docs/cancellation-and-timeouts.md#cancellation-and-timeouts)
+ * <a name='cancelling-coroutine-execution'></a>[Cancelling coroutine execution](docs/cancellation-and-timeouts.md#cancelling-coroutine-execution)
+ * <a name='cancellation-is-cooperative'></a>[Cancellation is cooperative](docs/cancellation-and-timeouts.md#cancellation-is-cooperative)
+ * <a name='making-computation-code-cancellable'></a>[Making computation code cancellable](docs/cancellation-and-timeouts.md#making-computation-code-cancellable)
+ * <a name='closing-resources-with-finally'></a>[Closing resources with `finally`](docs/cancellation-and-timeouts.md#closing-resources-with-finally)
+ * <a name='run-non-cancellable-block'></a>[Run non-cancellable block](docs/cancellation-and-timeouts.md#run-non-cancellable-block)
+ * <a name='timeout'></a>[Timeout](docs/cancellation-and-timeouts.md#timeout)
+ * <a name='asynchronous-timeout-and-resources'></a>[Asynchronous timeout and resources](docs/cancellation-and-timeouts.md#asynchronous-timeout-and-resources)
+<!--- TOC_REF docs/composing-suspending-functions.md -->
+* <a name='composing-suspending-functions'></a>[Composing Suspending Functions](docs/composing-suspending-functions.md#composing-suspending-functions)
+ * <a name='sequential-by-default'></a>[Sequential by default](docs/composing-suspending-functions.md#sequential-by-default)
+ * <a name='concurrent-using-async'></a>[Concurrent using async](docs/composing-suspending-functions.md#concurrent-using-async)
+ * <a name='lazily-started-async'></a>[Lazily started async](docs/composing-suspending-functions.md#lazily-started-async)
+ * <a name='async-style-functions'></a>[Async-style functions](docs/composing-suspending-functions.md#async-style-functions)
+ * <a name='structured-concurrency-with-async'></a>[Structured concurrency with async](docs/composing-suspending-functions.md#structured-concurrency-with-async)
+<!--- TOC_REF docs/coroutine-context-and-dispatchers.md -->
+* <a name='coroutine-context-and-dispatchers'></a>[Coroutine Context and Dispatchers](docs/coroutine-context-and-dispatchers.md#coroutine-context-and-dispatchers)
+ * <a name='dispatchers-and-threads'></a>[Dispatchers and threads](docs/coroutine-context-and-dispatchers.md#dispatchers-and-threads)
+ * <a name='unconfined-vs-confined-dispatcher'></a>[Unconfined vs confined dispatcher](docs/coroutine-context-and-dispatchers.md#unconfined-vs-confined-dispatcher)
+ * <a name='debugging-coroutines-and-threads'></a>[Debugging coroutines and threads](docs/coroutine-context-and-dispatchers.md#debugging-coroutines-and-threads)
+ * <a name='debugging-with-idea'></a>[Debugging with IDEA](docs/coroutine-context-and-dispatchers.md#debugging-with-idea)
+ * <a name='debugging-using-logging'></a>[Debugging using logging](docs/coroutine-context-and-dispatchers.md#debugging-using-logging)
+ * <a name='jumping-between-threads'></a>[Jumping between threads](docs/coroutine-context-and-dispatchers.md#jumping-between-threads)
+ * <a name='job-in-the-context'></a>[Job in the context](docs/coroutine-context-and-dispatchers.md#job-in-the-context)
+ * <a name='children-of-a-coroutine'></a>[Children of a coroutine](docs/coroutine-context-and-dispatchers.md#children-of-a-coroutine)
+ * <a name='parental-responsibilities'></a>[Parental responsibilities](docs/coroutine-context-and-dispatchers.md#parental-responsibilities)
+ * <a name='naming-coroutines-for-debugging'></a>[Naming coroutines for debugging](docs/coroutine-context-and-dispatchers.md#naming-coroutines-for-debugging)
+ * <a name='combining-context-elements'></a>[Combining context elements](docs/coroutine-context-and-dispatchers.md#combining-context-elements)
+ * <a name='coroutine-scope'></a>[Coroutine scope](docs/coroutine-context-and-dispatchers.md#coroutine-scope)
+ * <a name='thread-local-data'></a>[Thread-local data](docs/coroutine-context-and-dispatchers.md#thread-local-data)
+<!--- TOC_REF docs/flow.md -->
+* <a name='asynchronous-flow'></a>[Asynchronous Flow](docs/flow.md#asynchronous-flow)
+ * <a name='representing-multiple-values'></a>[Representing multiple values](docs/flow.md#representing-multiple-values)
+ * <a name='sequences'></a>[Sequences](docs/flow.md#sequences)
+ * <a name='suspending-functions'></a>[Suspending functions](docs/flow.md#suspending-functions)
+ * <a name='flows'></a>[Flows](docs/flow.md#flows)
+ * <a name='flows-are-cold'></a>[Flows are cold](docs/flow.md#flows-are-cold)
+ * <a name='flow-cancellation-basics'></a>[Flow cancellation basics](docs/flow.md#flow-cancellation-basics)
+ * <a name='flow-builders'></a>[Flow builders](docs/flow.md#flow-builders)
+ * <a name='intermediate-flow-operators'></a>[Intermediate flow operators](docs/flow.md#intermediate-flow-operators)
+ * <a name='transform-operator'></a>[Transform operator](docs/flow.md#transform-operator)
+ * <a name='size-limiting-operators'></a>[Size-limiting operators](docs/flow.md#size-limiting-operators)
+ * <a name='terminal-flow-operators'></a>[Terminal flow operators](docs/flow.md#terminal-flow-operators)
+ * <a name='flows-are-sequential'></a>[Flows are sequential](docs/flow.md#flows-are-sequential)
+ * <a name='flow-context'></a>[Flow context](docs/flow.md#flow-context)
+ * <a name='wrong-emission-withcontext'></a>[Wrong emission withContext](docs/flow.md#wrong-emission-withcontext)
+ * <a name='flowon-operator'></a>[flowOn operator](docs/flow.md#flowon-operator)
+ * <a name='buffering'></a>[Buffering](docs/flow.md#buffering)
+ * <a name='conflation'></a>[Conflation](docs/flow.md#conflation)
+ * <a name='processing-the-latest-value'></a>[Processing the latest value](docs/flow.md#processing-the-latest-value)
+ * <a name='composing-multiple-flows'></a>[Composing multiple flows](docs/flow.md#composing-multiple-flows)
+ * <a name='zip'></a>[Zip](docs/flow.md#zip)
+ * <a name='combine'></a>[Combine](docs/flow.md#combine)
+ * <a name='flattening-flows'></a>[Flattening flows](docs/flow.md#flattening-flows)
+ * <a name='flatmapconcat'></a>[flatMapConcat](docs/flow.md#flatmapconcat)
+ * <a name='flatmapmerge'></a>[flatMapMerge](docs/flow.md#flatmapmerge)
+ * <a name='flatmaplatest'></a>[flatMapLatest](docs/flow.md#flatmaplatest)
+ * <a name='flow-exceptions'></a>[Flow exceptions](docs/flow.md#flow-exceptions)
+ * <a name='collector-try-and-catch'></a>[Collector try and catch](docs/flow.md#collector-try-and-catch)
+ * <a name='everything-is-caught'></a>[Everything is caught](docs/flow.md#everything-is-caught)
+ * <a name='exception-transparency'></a>[Exception transparency](docs/flow.md#exception-transparency)
+ * <a name='transparent-catch'></a>[Transparent catch](docs/flow.md#transparent-catch)
+ * <a name='catching-declaratively'></a>[Catching declaratively](docs/flow.md#catching-declaratively)
+ * <a name='flow-completion'></a>[Flow completion](docs/flow.md#flow-completion)
+ * <a name='imperative-finally-block'></a>[Imperative finally block](docs/flow.md#imperative-finally-block)
+ * <a name='declarative-handling'></a>[Declarative handling](docs/flow.md#declarative-handling)
+ * <a name='successful-completion'></a>[Successful completion](docs/flow.md#successful-completion)
+ * <a name='imperative-versus-declarative'></a>[Imperative versus declarative](docs/flow.md#imperative-versus-declarative)
+ * <a name='launching-flow'></a>[Launching flow](docs/flow.md#launching-flow)
+ * <a name='flow-cancellation-checks'></a>[Flow cancellation checks](docs/flow.md#flow-cancellation-checks)
+ * <a name='making-busy-flow-cancellable'></a>[Making busy flow cancellable](docs/flow.md#making-busy-flow-cancellable)
+ * <a name='flow-and-reactive-streams'></a>[Flow and Reactive Streams](docs/flow.md#flow-and-reactive-streams)
+<!--- TOC_REF docs/channels.md -->
+* <a name='channels'></a>[Channels](docs/channels.md#channels)
+ * <a name='channel-basics'></a>[Channel basics](docs/channels.md#channel-basics)
+ * <a name='closing-and-iteration-over-channels'></a>[Closing and iteration over channels](docs/channels.md#closing-and-iteration-over-channels)
+ * <a name='building-channel-producers'></a>[Building channel producers](docs/channels.md#building-channel-producers)
+ * <a name='pipelines'></a>[Pipelines](docs/channels.md#pipelines)
+ * <a name='prime-numbers-with-pipeline'></a>[Prime numbers with pipeline](docs/channels.md#prime-numbers-with-pipeline)
+ * <a name='fan-out'></a>[Fan-out](docs/channels.md#fan-out)
+ * <a name='fan-in'></a>[Fan-in](docs/channels.md#fan-in)
+ * <a name='buffered-channels'></a>[Buffered channels](docs/channels.md#buffered-channels)
+ * <a name='channels-are-fair'></a>[Channels are fair](docs/channels.md#channels-are-fair)
+ * <a name='ticker-channels'></a>[Ticker channels](docs/channels.md#ticker-channels)
+<!--- TOC_REF docs/exception-handling.md -->
+* <a name='exception-handling'></a>[Exception Handling](docs/exception-handling.md#exception-handling)
+ * <a name='exception-propagation'></a>[Exception propagation](docs/exception-handling.md#exception-propagation)
+ * <a name='coroutineexceptionhandler'></a>[CoroutineExceptionHandler](docs/exception-handling.md#coroutineexceptionhandler)
+ * <a name='cancellation-and-exceptions'></a>[Cancellation and exceptions](docs/exception-handling.md#cancellation-and-exceptions)
+ * <a name='exceptions-aggregation'></a>[Exceptions aggregation](docs/exception-handling.md#exceptions-aggregation)
+ * <a name='supervision'></a>[Supervision](docs/exception-handling.md#supervision)
+ * <a name='supervision-job'></a>[Supervision job](docs/exception-handling.md#supervision-job)
+ * <a name='supervision-scope'></a>[Supervision scope](docs/exception-handling.md#supervision-scope)
+ * <a name='exceptions-in-supervised-coroutines'></a>[Exceptions in supervised coroutines](docs/exception-handling.md#exceptions-in-supervised-coroutines)
+<!--- TOC_REF docs/shared-mutable-state-and-concurrency.md -->
+* <a name='shared-mutable-state-and-concurrency'></a>[Shared mutable state and concurrency](docs/shared-mutable-state-and-concurrency.md#shared-mutable-state-and-concurrency)
+ * <a name='the-problem'></a>[The problem](docs/shared-mutable-state-and-concurrency.md#the-problem)
+ * <a name='volatiles-are-of-no-help'></a>[Volatiles are of no help](docs/shared-mutable-state-and-concurrency.md#volatiles-are-of-no-help)
+ * <a name='thread-safe-data-structures'></a>[Thread-safe data structures](docs/shared-mutable-state-and-concurrency.md#thread-safe-data-structures)
+ * <a name='thread-confinement-fine-grained'></a>[Thread confinement fine-grained](docs/shared-mutable-state-and-concurrency.md#thread-confinement-fine-grained)
+ * <a name='thread-confinement-coarse-grained'></a>[Thread confinement coarse-grained](docs/shared-mutable-state-and-concurrency.md#thread-confinement-coarse-grained)
+ * <a name='mutual-exclusion'></a>[Mutual exclusion](docs/shared-mutable-state-and-concurrency.md#mutual-exclusion)
+ * <a name='actors'></a>[Actors](docs/shared-mutable-state-and-concurrency.md#actors)
+<!--- TOC_REF docs/select-expression.md -->
+* <a name='select-expression-experimental'></a>[Select Expression (experimental)](docs/select-expression.md#select-expression-experimental)
+ * <a name='selecting-from-channels'></a>[Selecting from channels](docs/select-expression.md#selecting-from-channels)
+ * <a name='selecting-on-close'></a>[Selecting on close](docs/select-expression.md#selecting-on-close)
+ * <a name='selecting-to-send'></a>[Selecting to send](docs/select-expression.md#selecting-to-send)
+ * <a name='selecting-deferred-values'></a>[Selecting deferred values](docs/select-expression.md#selecting-deferred-values)
+ * <a name='switch-over-a-channel-of-deferred-values'></a>[Switch over a channel of deferred values](docs/select-expression.md#switch-over-a-channel-of-deferred-values)
<!--- END -->
diff --git a/docs/_nav.yml b/docs/_nav.yml
new file mode 100644
index 00000000..79a69690
--- /dev/null
+++ b/docs/_nav.yml
@@ -0,0 +1,30 @@
+- md: coroutines-guide.md
+ url: coroutines-guide.html
+ title: Coroutines Guide
+- md: basics.md
+ url: basics.html
+ title: Basics
+- md: cancellation-and-timeouts.md
+ url: cancellation-and-timeouts.html
+ title: Cancellation and Timeouts
+- md: composing-suspending-functions.md
+ url: composing-suspending-functions.html
+ title: Composing Suspending Functions
+- md: coroutine-context-and-dispatchers.md
+ url: coroutine-context-and-dispatchers.html
+ title: Coroutine Context and Dispatchers
+- md: flow.md
+ url: flow.html
+ title: Asynchronous Flow
+- md: channels.md
+ url: channels.html
+ title: Channels
+- md: exception-handling.md
+ url: exception-handling.html
+ title: Exception Handling and Supervision
+- md: shared-mutable-state-and-concurrency.md
+ url: shared-mutable-state-and-concurrency.html
+ title: Shared Mutable State and Concurrency
+- md: select-expression.md
+ url: select-expression.html
+ title: Select Expression (experimental)
diff --git a/docs/basics.md b/docs/basics.md
index a18bf3dd..8aca23a1 100644
--- a/docs/basics.md
+++ b/docs/basics.md
@@ -1,3 +1,410 @@
-The documentation has been moved to the [https://kotlinlang.org/docs/coroutines-basics.html](https://kotlinlang.org/docs/coroutines-basics.html) page.
+<!--- TEST_NAME BasicsGuideTest -->
+
+**Table of contents**
+
+<!--- TOC -->
+
+* [Coroutine Basics](#coroutine-basics)
+ * [Your first coroutine](#your-first-coroutine)
+ * [Bridging blocking and non-blocking worlds](#bridging-blocking-and-non-blocking-worlds)
+ * [Waiting for a job](#waiting-for-a-job)
+ * [Structured concurrency](#structured-concurrency)
+ * [Scope builder](#scope-builder)
+ * [Extract function refactoring](#extract-function-refactoring)
+ * [Coroutines ARE light-weight](#coroutines-are-light-weight)
+ * [Global coroutines are like daemon threads](#global-coroutines-are-like-daemon-threads)
+
+<!--- END -->
+
+## Coroutine Basics
+
+This section covers basic coroutine concepts.
+
+### Your first coroutine
+
+Run the following code:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() {
+ GlobalScope.launch { // launch a new coroutine in background and continue
+ delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
+ println("World!") // print after delay
+ }
+ println("Hello,") // main thread continues while coroutine is delayed
+ Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt).
+
+You will see the following result:
+
+```text
+Hello,
+World!
+```
+
+<!--- TEST -->
+
+Essentially, coroutines are light-weight threads.
+They are launched with [launch] _coroutine builder_ in a context of some [CoroutineScope].
+Here we are launching a new coroutine in the [GlobalScope], meaning that the lifetime of the new
+coroutine is limited only by the lifetime of the whole application.
+
+You can achieve the same result by replacing
+`GlobalScope.launch { ... }` with `thread { ... }`, and `delay(...)` with `Thread.sleep(...)`.
+Try it (don't forget to import `kotlin.concurrent.thread`).
+
+If you start by replacing `GlobalScope.launch` with `thread`, the compiler produces the following error:
+
+```
+Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
+```
+
+That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_ the
+coroutine, and it can be only used from a coroutine.
+
+### Bridging blocking and non-blocking worlds
+
+The first example mixes _non-blocking_ `delay(...)` and _blocking_ `Thread.sleep(...)` in the same code.
+It is easy to lose track of which one is blocking and which one is not.
+Let's be explicit about blocking using the [runBlocking] coroutine builder:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() {
+ GlobalScope.launch { // launch a new coroutine in background and continue
+ delay(1000L)
+ println("World!")
+ }
+ println("Hello,") // main thread continues here immediately
+ runBlocking { // but this expression blocks the main thread
+ delay(2000L) // ... while we delay for 2 seconds to keep JVM alive
+ }
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt).
+
+<!--- TEST
+Hello,
+World!
+-->
+
+The result is the same, but this code uses only non-blocking [delay].
+The main thread invoking `runBlocking` _blocks_ until the coroutine inside `runBlocking` completes.
+
+This example can be also rewritten in a more idiomatic way, using `runBlocking` to wrap
+the execution of the main function:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking<Unit> { // start main coroutine
+ GlobalScope.launch { // launch a new coroutine in background and continue
+ delay(1000L)
+ println("World!")
+ }
+ println("Hello,") // main coroutine continues here immediately
+ delay(2000L) // delaying for 2 seconds to keep JVM alive
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt).
+
+<!--- TEST
+Hello,
+World!
+-->
+
+Here `runBlocking<Unit> { ... }` works as an adaptor that is used to start the top-level main coroutine.
+We explicitly specify its `Unit` return type, because a well-formed `main` function in Kotlin has to return `Unit`.
+
+This is also a way to write unit tests for suspending functions:
+
+<!--- INCLUDE
+import kotlinx.coroutines.*
+-->
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+class MyTest {
+ @Test
+ fun testMySuspendingFunction() = runBlocking<Unit> {
+ // here we can use suspending functions using any assertion style that we like
+ }
+}
+```
+
+</div>
+
+<!--- CLEAR -->
+
+### Waiting for a job
+
+Delaying for a time while another coroutine is working is not a good approach. Let's explicitly
+wait (in a non-blocking way) until the background [Job] that we have launched is complete:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+//sampleStart
+ val job = GlobalScope.launch { // launch a new coroutine and keep a reference to its Job
+ delay(1000L)
+ println("World!")
+ }
+ println("Hello,")
+ job.join() // wait until child coroutine completes
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt).
+
+<!--- TEST
+Hello,
+World!
+-->
+
+Now the result is still the same, but the code of the main coroutine is not tied to the duration of
+the background job in any way. Much better.
+
+### Structured concurrency
+
+There is still something to be desired for practical usage of coroutines.
+When we use `GlobalScope.launch`, we create a top-level coroutine. Even though it is light-weight, it still
+consumes some memory resources while it runs. If we forget to keep a reference to the newly launched
+coroutine, it still runs. What if the code in the coroutine hangs (for example, we erroneously
+delay for too long), what if we launched too many coroutines and ran out of memory?
+Having to manually keep references to all the launched coroutines and [join][Job.join] them is error-prone.
+
+There is a better solution. We can use structured concurrency in our code.
+Instead of launching coroutines in the [GlobalScope], just like we usually do with threads (threads are always global),
+we can launch coroutines in the specific scope of the operation we are performing.
+
+In our example, we have a `main` function that is turned into a coroutine using the [runBlocking] coroutine builder.
+Every coroutine builder, including `runBlocking`, adds an instance of [CoroutineScope] to the scope of its code block.
+We can launch coroutines in this scope without having to `join` them explicitly, because
+an outer coroutine (`runBlocking` in our example) does not complete until all the coroutines launched
+in its scope complete. Thus, we can make our example simpler:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking { // this: CoroutineScope
+ launch { // launch a new coroutine in the scope of runBlocking
+ delay(1000L)
+ println("World!")
+ }
+ println("Hello,")
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt).
+
+<!--- TEST
+Hello,
+World!
+-->
+
+### Scope builder
+
+In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using the
+[coroutineScope][_coroutineScope] builder. It creates a coroutine scope and does not complete until all launched children complete.
+
+[runBlocking] and [coroutineScope][_coroutineScope] may look similar because they both wait for their body and all its children to complete.
+The main difference is that the [runBlocking] method _blocks_ the current thread for waiting,
+while [coroutineScope][_coroutineScope] just suspends, releasing the underlying thread for other usages.
+Because of that difference, [runBlocking] is a regular function and [coroutineScope][_coroutineScope] is a suspending function.
+
+It can be demonstrated by the following example:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking { // this: CoroutineScope
+ launch {
+ delay(200L)
+ println("Task from runBlocking")
+ }
+
+ coroutineScope { // Creates a coroutine scope
+ launch {
+ delay(500L)
+ println("Task from nested launch")
+ }
+
+ delay(100L)
+ println("Task from coroutine scope") // This line will be printed before the nested launch
+ }
+
+ println("Coroutine scope is over") // This line is not printed until the nested launch completes
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt).
+
+<!--- TEST
+Task from coroutine scope
+Task from runBlocking
+Task from nested launch
+Coroutine scope is over
+-->
+
+Note that right after the "Task from coroutine scope" message (while waiting for nested launch)
+ "Task from runBlocking" is executed and printed — even though the [coroutineScope][_coroutineScope] is not completed yet.
+
+### Extract function refactoring
+
+Let's extract the block of code inside `launch { ... }` into a separate function. When you
+perform "Extract function" refactoring on this code, you get a new function with the `suspend` modifier.
+This is your first _suspending function_. Suspending functions can be used inside coroutines
+just like regular functions, but their additional feature is that they can, in turn,
+use other suspending functions (like `delay` in this example) to _suspend_ execution of a coroutine.
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+ launch { doWorld() }
+ println("Hello,")
+}
+
+// this is your first suspending function
+suspend fun doWorld() {
+ delay(1000L)
+ println("World!")
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt).
+
+<!--- TEST
+Hello,
+World!
+-->
+
+
+But what if the extracted function contains a coroutine builder which is invoked on the current scope?
+In this case, the `suspend` modifier on the extracted function is not enough. Making `doWorld` an extension
+method on `CoroutineScope` is one of the solutions, but it may not always be applicable as it does not make the API clearer.
+The idiomatic solution is to have either an explicit `CoroutineScope` as a field in a class containing the target function
+or an implicit one when the outer class implements `CoroutineScope`.
+As a last resort, [CoroutineScope(coroutineContext)][CoroutineScope()] can be used, but such an approach is structurally unsafe
+because you no longer have control on the scope of execution of this method. Only private APIs can use this builder.
+
+### Coroutines ARE light-weight
+
+Run the following code:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+ repeat(100_000) { // launch a lot of coroutines
+ launch {
+ delay(5000L)
+ print(".")
+ }
+ }
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-08.kt).
+
+<!--- TEST lines.size == 1 && lines[0] == ".".repeat(100_000) -->
+
+It launches 100K coroutines and, after 5 seconds, each coroutine prints a dot.
+
+Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
+
+### Global coroutines are like daemon threads
+
+The following code launches a long-running coroutine in [GlobalScope] that prints "I'm sleeping" twice a second and then
+returns from the main function after some delay:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+//sampleStart
+ GlobalScope.launch {
+ repeat(1000) { i ->
+ println("I'm sleeping $i ...")
+ delay(500L)
+ }
+ }
+ delay(1300L) // just quit after delay
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-09.kt).
+
+You can run and see that it prints three lines and terminates:
+
+```text
+I'm sleeping 0 ...
+I'm sleeping 1 ...
+I'm sleeping 2 ...
+```
+
+<!--- TEST -->
+
+Active coroutines that were launched in [GlobalScope] do not keep the process alive. They are like daemon threads.
+
+<!--- MODULE kotlinx-coroutines-core -->
+<!--- INDEX kotlinx.coroutines -->
+[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
+[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
+[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
+[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
+[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
+[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
+[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
+[_coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
+[CoroutineScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
+<!--- END -->
+
-To edit the documentation, open the [topics/coroutines-basics.md](topics/coroutines-basics.md) page.
diff --git a/docs/cancellation-and-timeouts.md b/docs/cancellation-and-timeouts.md
index ad6afca9..b296bde4 100644
--- a/docs/cancellation-and-timeouts.md
+++ b/docs/cancellation-and-timeouts.md
@@ -1,3 +1,482 @@
-The documentation has been moved to the [https://kotlinlang.org/docs/cancellation-and-timeouts.html](https://kotlinlang.org/docs/cancellation-and-timeouts.html) page.
+<!--- TEST_NAME CancellationGuideTest -->
-To edit the documentation, open the [topics/cancellation-and-timeouts.md](topics/cancellation-and-timeouts.md) page. \ No newline at end of file
+**Table of contents**
+
+<!--- TOC -->
+
+* [Cancellation and Timeouts](#cancellation-and-timeouts)
+ * [Cancelling coroutine execution](#cancelling-coroutine-execution)
+ * [Cancellation is cooperative](#cancellation-is-cooperative)
+ * [Making computation code cancellable](#making-computation-code-cancellable)
+ * [Closing resources with `finally`](#closing-resources-with-finally)
+ * [Run non-cancellable block](#run-non-cancellable-block)
+ * [Timeout](#timeout)
+ * [Asynchronous timeout and resources](#asynchronous-timeout-and-resources)
+
+<!--- END -->
+
+## Cancellation and Timeouts
+
+This section covers coroutine cancellation and timeouts.
+
+### Cancelling coroutine execution
+
+In a long-running application you might need fine-grained control on your background coroutines.
+For example, a user might have closed the page that launched a coroutine and now its result
+is no longer needed and its operation can be cancelled.
+The [launch] function returns a [Job] that can be used to cancel the running coroutine:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+//sampleStart
+ val job = launch {
+ repeat(1000) { i ->
+ println("job: I'm sleeping $i ...")
+ delay(500L)
+ }
+ }
+ delay(1300L) // delay a bit
+ println("main: I'm tired of waiting!")
+ job.cancel() // cancels the job
+ job.join() // waits for job's completion
+ println("main: Now I can quit.")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-01.kt).
+
+It produces the following output:
+
+```text
+job: I'm sleeping 0 ...
+job: I'm sleeping 1 ...
+job: I'm sleeping 2 ...
+main: I'm tired of waiting!
+main: Now I can quit.
+```
+
+<!--- TEST -->
+
+As soon as main invokes `job.cancel`, we don't see any output from the other coroutine because it was cancelled.
+There is also a [Job] extension function [cancelAndJoin]
+that combines [cancel][Job.cancel] and [join][Job.join] invocations.
+
+### Cancellation is cooperative
+
+Coroutine cancellation is _cooperative_. A coroutine code has to cooperate to be cancellable.
+All the suspending functions in `kotlinx.coroutines` are _cancellable_. They check for cancellation of
+coroutine and throw [CancellationException] when cancelled. However, if a coroutine is working in
+a computation and does not check for cancellation, then it cannot be cancelled, like the following
+example shows:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+//sampleStart
+ val startTime = System.currentTimeMillis()
+ val job = launch(Dispatchers.Default) {
+ var nextPrintTime = startTime
+ var i = 0
+ while (i < 5) { // computation loop, just wastes CPU
+ // print a message twice a second
+ if (System.currentTimeMillis() >= nextPrintTime) {
+ println("job: I'm sleeping ${i++} ...")
+ nextPrintTime += 500L
+ }
+ }
+ }
+ delay(1300L) // delay a bit
+ println("main: I'm tired of waiting!")
+ job.cancelAndJoin() // cancels the job and waits for its completion
+ println("main: Now I can quit.")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-02.kt).
+
+Run it to see that it continues to print "I'm sleeping" even after cancellation
+until the job completes by itself after five iterations.
+
+<!--- TEST
+job: I'm sleeping 0 ...
+job: I'm sleeping 1 ...
+job: I'm sleeping 2 ...
+main: I'm tired of waiting!
+job: I'm sleeping 3 ...
+job: I'm sleeping 4 ...
+main: Now I can quit.
+-->
+
+### Making computation code cancellable
+
+There are two approaches to making computation code cancellable. The first one is to periodically
+invoke a suspending function that checks for cancellation. There is a [yield] function that is a good choice for that purpose.
+The other one is to explicitly check the cancellation status. Let us try the latter approach.
+
+Replace `while (i < 5)` in the previous example with `while (isActive)` and rerun it.
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+//sampleStart
+ val startTime = System.currentTimeMillis()
+ val job = launch(Dispatchers.Default) {
+ var nextPrintTime = startTime
+ var i = 0
+ while (isActive) { // cancellable computation loop
+ // print a message twice a second
+ if (System.currentTimeMillis() >= nextPrintTime) {
+ println("job: I'm sleeping ${i++} ...")
+ nextPrintTime += 500L
+ }
+ }
+ }
+ delay(1300L) // delay a bit
+ println("main: I'm tired of waiting!")
+ job.cancelAndJoin() // cancels the job and waits for its completion
+ println("main: Now I can quit.")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-03.kt).
+
+As you can see, now this loop is cancelled. [isActive] is an extension property
+available inside the coroutine via the [CoroutineScope] object.
+
+<!--- TEST
+job: I'm sleeping 0 ...
+job: I'm sleeping 1 ...
+job: I'm sleeping 2 ...
+main: I'm tired of waiting!
+main: Now I can quit.
+-->
+
+### Closing resources with `finally`
+
+Cancellable suspending functions throw [CancellationException] on cancellation which can be handled in
+the usual way. For example, `try {...} finally {...}` expression and Kotlin `use` function execute their
+finalization actions normally when a coroutine is cancelled:
+
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+//sampleStart
+ val job = launch {
+ try {
+ repeat(1000) { i ->
+ println("job: I'm sleeping $i ...")
+ delay(500L)
+ }
+ } finally {
+ println("job: I'm running finally")
+ }
+ }
+ delay(1300L) // delay a bit
+ println("main: I'm tired of waiting!")
+ job.cancelAndJoin() // cancels the job and waits for its completion
+ println("main: Now I can quit.")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt).
+
+Both [join][Job.join] and [cancelAndJoin] wait for all finalization actions to complete,
+so the example above produces the following output:
+
+```text
+job: I'm sleeping 0 ...
+job: I'm sleeping 1 ...
+job: I'm sleeping 2 ...
+main: I'm tired of waiting!
+job: I'm running finally
+main: Now I can quit.
+```
+
+<!--- TEST -->
+
+### Run non-cancellable block
+
+Any attempt to use a suspending function in the `finally` block of the previous example causes
+[CancellationException], because the coroutine running this code is cancelled. Usually, this is not a
+problem, since all well-behaving closing operations (closing a file, cancelling a job, or closing any kind of a
+communication channel) are usually non-blocking and do not involve any suspending functions. However, in the
+rare case when you need to suspend in a cancelled coroutine you can wrap the corresponding code in
+`withContext(NonCancellable) {...}` using [withContext] function and [NonCancellable] context as the following example shows:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+//sampleStart
+ val job = launch {
+ try {
+ repeat(1000) { i ->
+ println("job: I'm sleeping $i ...")
+ delay(500L)
+ }
+ } finally {
+ withContext(NonCancellable) {
+ println("job: I'm running finally")
+ delay(1000L)
+ println("job: And I've just delayed for 1 sec because I'm non-cancellable")
+ }
+ }
+ }
+ delay(1300L) // delay a bit
+ println("main: I'm tired of waiting!")
+ job.cancelAndJoin() // cancels the job and waits for its completion
+ println("main: Now I can quit.")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-05.kt).
+
+<!--- TEST
+job: I'm sleeping 0 ...
+job: I'm sleeping 1 ...
+job: I'm sleeping 2 ...
+main: I'm tired of waiting!
+job: I'm running finally
+job: And I've just delayed for 1 sec because I'm non-cancellable
+main: Now I can quit.
+-->
+
+### Timeout
+
+The most obvious practical reason to cancel execution of a coroutine
+is because its execution time has exceeded some timeout.
+While you can manually track the reference to the corresponding [Job] and launch a separate coroutine to cancel
+the tracked one after delay, there is a ready to use [withTimeout] function that does it.
+Look at the following example:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+//sampleStart
+ withTimeout(1300L) {
+ repeat(1000) { i ->
+ println("I'm sleeping $i ...")
+ delay(500L)
+ }
+ }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-06.kt).
+
+It produces the following output:
+
+```text
+I'm sleeping 0 ...
+I'm sleeping 1 ...
+I'm sleeping 2 ...
+Exception in thread "main" kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 1300 ms
+```
+
+<!--- TEST STARTS_WITH -->
+
+The `TimeoutCancellationException` that is thrown by [withTimeout] is a subclass of [CancellationException].
+We have not seen its stack trace printed on the console before. That is because
+inside a cancelled coroutine `CancellationException` is considered to be a normal reason for coroutine completion.
+However, in this example we have used `withTimeout` right inside the `main` function.
+
+Since cancellation is just an exception, all resources are closed in the usual way.
+You can wrap the code with timeout in a `try {...} catch (e: TimeoutCancellationException) {...}` block if
+you need to do some additional action specifically on any kind of timeout or use the [withTimeoutOrNull] function
+that is similar to [withTimeout] but returns `null` on timeout instead of throwing an exception:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+//sampleStart
+ val result = withTimeoutOrNull(1300L) {
+ repeat(1000) { i ->
+ println("I'm sleeping $i ...")
+ delay(500L)
+ }
+ "Done" // will get cancelled before it produces this result
+ }
+ println("Result is $result")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-07.kt).
+
+There is no longer an exception when running this code:
+
+```text
+I'm sleeping 0 ...
+I'm sleeping 1 ...
+I'm sleeping 2 ...
+Result is null
+```
+
+<!--- TEST -->
+
+### Asynchronous timeout and resources
+
+<!--
+ NOTE: Don't change this section name. It is being referenced to from within KDoc of withTimeout functions.
+-->
+
+The timeout event in [withTimeout] is asynchronous with respect to the code running in its block and may happen at any time,
+even right before the return from inside of the timeout block. Keep this in mind if you open or acquire some
+resource inside the block that needs closing or release outside of the block.
+
+For example, here we imitate a closeable resource with the `Resource` class, that simply keeps track of how many times
+it was created by incrementing the `acquired` counter and decrementing this counter from its `close` function.
+Let us run a lot of coroutines with the small timeout try acquire this resource from inside
+of the `withTimeout` block after a bit of delay and release it from outside.
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+//sampleStart
+var acquired = 0
+
+class Resource {
+ init { acquired++ } // Acquire the resource
+ fun close() { acquired-- } // Release the resource
+}
+
+fun main() {
+ runBlocking {
+ repeat(100_000) { // Launch 100K coroutines
+ launch {
+ val resource = withTimeout(60) { // Timeout of 60 ms
+ delay(50) // Delay for 50 ms
+ Resource() // Acquire a resource and return it from withTimeout block
+ }
+ resource.close() // Release the resource
+ }
+ }
+ }
+ // Outside of runBlocking all coroutines have completed
+ println(acquired) // Print the number of resources still acquired
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-08.kt).
+
+<!--- CLEAR -->
+
+If you run the above code you'll see that it does not always print zero, though it may depend on the timings
+of your machine you may need to tweak timeouts in this example to actually see non-zero values.
+
+> Note, that incrementing and decrementing `acquired` counter here from 100K coroutines is completely safe,
+> since it always happens from the same main thread. More on that will be explained in the next chapter
+> on coroutine context.
+
+To workaround this problem you can store a reference to the resource in the variable as opposed to returning it
+from the `withTimeout` block.
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+var acquired = 0
+
+class Resource {
+ init { acquired++ } // Acquire the resource
+ fun close() { acquired-- } // Release the resource
+}
+
+fun main() {
+//sampleStart
+ runBlocking {
+ repeat(100_000) { // Launch 100K coroutines
+ launch {
+ var resource: Resource? = null // Not acquired yet
+ try {
+ withTimeout(60) { // Timeout of 60 ms
+ delay(50) // Delay for 50 ms
+ resource = Resource() // Store a resource to the variable if acquired
+ }
+ // We can do something else with the resource here
+ } finally {
+ resource?.close() // Release the resource if it was acquired
+ }
+ }
+ }
+ }
+ // Outside of runBlocking all coroutines have completed
+ println(acquired) // Print the number of resources still acquired
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-09.kt).
+
+This example always prints zero. Resources do not leak.
+
+<!--- TEST
+0
+-->
+
+<!--- MODULE kotlinx-coroutines-core -->
+<!--- INDEX kotlinx.coroutines -->
+[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
+[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
+[cancelAndJoin]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel-and-join.html
+[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html
+[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
+[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html
+[yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/yield.html
+[isActive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/is-active.html
+[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
+[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
+[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable.html
+[withTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout.html
+[withTimeoutOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout-or-null.html
+<!--- END -->
diff --git a/docs/cfg/buildprofiles.xml b/docs/cfg/buildprofiles.xml
deleted file mode 100644
index ac4d04ad..00000000
--- a/docs/cfg/buildprofiles.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<buildprofiles>
- <variables>
- <enable-browser-edits>true</enable-browser-edits>
- <browser-edits-url>https://github.com/Kotlin/kotlinx.coroutines/edit/master/</browser-edits-url>
- <allow-indexable-eaps>true</allow-indexable-eaps>
- </variables>
- <build-profile product="kc"/>
-</buildprofiles>
diff --git a/docs/channels.md b/docs/channels.md
index 73415ce9..d1a4bac0 100644
--- a/docs/channels.md
+++ b/docs/channels.md
@@ -1,3 +1,702 @@
-The documentation has been moved to the [https://kotlinlang.org/docs/channels.html](https://kotlinlang.org/docs/channels.html) page.
+<!--- TEST_NAME ChannelsGuideTest -->
-To edit the documentation, open the [topics/channels.md](topics/channels.md) page. \ No newline at end of file
+**Table of contents**
+
+<!--- TOC -->
+
+* [Channels](#channels)
+ * [Channel basics](#channel-basics)
+ * [Closing and iteration over channels](#closing-and-iteration-over-channels)
+ * [Building channel producers](#building-channel-producers)
+ * [Pipelines](#pipelines)
+ * [Prime numbers with pipeline](#prime-numbers-with-pipeline)
+ * [Fan-out](#fan-out)
+ * [Fan-in](#fan-in)
+ * [Buffered channels](#buffered-channels)
+ * [Channels are fair](#channels-are-fair)
+ * [Ticker channels](#ticker-channels)
+
+<!--- END -->
+
+## Channels
+
+Deferred values provide a convenient way to transfer a single value between coroutines.
+Channels provide a way to transfer a stream of values.
+
+### Channel basics
+
+A [Channel] is conceptually very similar to `BlockingQueue`. One key difference is that
+instead of a blocking `put` operation it has a suspending [send][SendChannel.send], and instead of
+a blocking `take` operation it has a suspending [receive][ReceiveChannel.receive].
+
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+
+fun main() = runBlocking {
+//sampleStart
+ val channel = Channel<Int>()
+ launch {
+ // this might be heavy CPU-consuming computation or async logic, we'll just send five squares
+ for (x in 1..5) channel.send(x * x)
+ }
+ // here we print five received integers:
+ repeat(5) { println(channel.receive()) }
+ println("Done!")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-channel-01.kt).
+
+The output of this code is:
+
+```text
+1
+4
+9
+16
+25
+Done!
+```
+
+<!--- TEST -->
+
+### Closing and iteration over channels
+
+Unlike a queue, a channel can be closed to indicate that no more elements are coming.
+On the receiver side it is convenient to use a regular `for` loop to receive elements
+from the channel.
+
+Conceptually, a [close][SendChannel.close] is like sending a special close token to the channel.
+The iteration stops as soon as this close token is received, so there is a guarantee
+that all previously sent elements before the close are received:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+
+fun main() = runBlocking {
+//sampleStart
+ val channel = Channel<Int>()
+ launch {
+ for (x in 1..5) channel.send(x * x)
+ channel.close() // we're done sending
+ }
+ // here we print received values using `for` loop (until the channel is closed)
+ for (y in channel) println(y)
+ println("Done!")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-channel-02.kt).
+
+<!--- TEST
+1
+4
+9
+16
+25
+Done!
+-->
+
+### Building channel producers
+
+The pattern where a coroutine is producing a sequence of elements is quite common.
+This is a part of _producer-consumer_ pattern that is often found in concurrent code.
+You could abstract such a producer into a function that takes channel as its parameter, but this goes contrary
+to common sense that results must be returned from functions.
+
+There is a convenient coroutine builder named [produce] that makes it easy to do it right on producer side,
+and an extension function [consumeEach], that replaces a `for` loop on the consumer side:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+
+fun CoroutineScope.produceSquares(): ReceiveChannel<Int> = produce {
+ for (x in 1..5) send(x * x)
+}
+
+fun main() = runBlocking {
+//sampleStart
+ val squares = produceSquares()
+ squares.consumeEach { println(it) }
+ println("Done!")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-channel-03.kt).
+
+<!--- TEST
+1
+4
+9
+16
+25
+Done!
+-->
+
+### Pipelines
+
+A pipeline is a pattern where one coroutine is producing, possibly infinite, stream of values:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.produceNumbers() = produce<Int> {
+ var x = 1
+ while (true) send(x++) // infinite stream of integers starting from 1
+}
+```
+
+</div>
+
+And another coroutine or coroutines are consuming that stream, doing some processing, and producing some other results.
+In the example below, the numbers are just squared:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.square(numbers: ReceiveChannel<Int>): ReceiveChannel<Int> = produce {
+ for (x in numbers) send(x * x)
+}
+```
+
+</div>
+
+The main code starts and connects the whole pipeline:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+
+fun main() = runBlocking {
+//sampleStart
+ val numbers = produceNumbers() // produces integers from 1 and on
+ val squares = square(numbers) // squares integers
+ repeat(5) {
+ println(squares.receive()) // print first five
+ }
+ println("Done!") // we are done
+ coroutineContext.cancelChildren() // cancel children coroutines
+//sampleEnd
+}
+
+fun CoroutineScope.produceNumbers() = produce<Int> {
+ var x = 1
+ while (true) send(x++) // infinite stream of integers starting from 1
+}
+
+fun CoroutineScope.square(numbers: ReceiveChannel<Int>): ReceiveChannel<Int> = produce {
+ for (x in numbers) send(x * x)
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-channel-04.kt).
+
+<!--- TEST
+1
+4
+9
+16
+25
+Done!
+-->
+
+> All functions that create coroutines are defined as extensions on [CoroutineScope],
+so that we can rely on [structured concurrency](https://kotlinlang.org/docs/reference/coroutines/composing-suspending-functions.html#structured-concurrency-with-async) to make
+sure that we don't have lingering global coroutines in our application.
+
+### Prime numbers with pipeline
+
+Let's take pipelines to the extreme with an example that generates prime numbers using a pipeline
+of coroutines. We start with an infinite sequence of numbers.
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.numbersFrom(start: Int) = produce<Int> {
+ var x = start
+ while (true) send(x++) // infinite stream of integers from start
+}
+```
+
+</div>
+
+The following pipeline stage filters an incoming stream of numbers, removing all the numbers
+that are divisible by the given prime number:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.filter(numbers: ReceiveChannel<Int>, prime: Int) = produce<Int> {
+ for (x in numbers) if (x % prime != 0) send(x)
+}
+```
+
+</div>
+
+Now we build our pipeline by starting a stream of numbers from 2, taking a prime number from the current channel,
+and launching new pipeline stage for each prime number found:
+
+```
+numbersFrom(2) -> filter(2) -> filter(3) -> filter(5) -> filter(7) ...
+```
+
+The following example prints the first ten prime numbers,
+running the whole pipeline in the context of the main thread. Since all the coroutines are launched in
+the scope of the main [runBlocking] coroutine
+we don't have to keep an explicit list of all the coroutines we have started.
+We use [cancelChildren][kotlin.coroutines.CoroutineContext.cancelChildren]
+extension function to cancel all the children coroutines after we have printed
+the first ten prime numbers.
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+
+fun main() = runBlocking {
+//sampleStart
+ var cur = numbersFrom(2)
+ repeat(10) {
+ val prime = cur.receive()
+ println(prime)
+ cur = filter(cur, prime)
+ }
+ coroutineContext.cancelChildren() // cancel all children to let main finish
+//sampleEnd
+}
+
+fun CoroutineScope.numbersFrom(start: Int) = produce<Int> {
+ var x = start
+ while (true) send(x++) // infinite stream of integers from start
+}
+
+fun CoroutineScope.filter(numbers: ReceiveChannel<Int>, prime: Int) = produce<Int> {
+ for (x in numbers) if (x % prime != 0) send(x)
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-channel-05.kt).
+
+The output of this code is:
+
+```text
+2
+3
+5
+7
+11
+13
+17
+19
+23
+29
+```
+
+<!--- TEST -->
+
+Note that you can build the same pipeline using
+[`iterator`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/iterator.html)
+coroutine builder from the standard library.
+Replace `produce` with `iterator`, `send` with `yield`, `receive` with `next`,
+`ReceiveChannel` with `Iterator`, and get rid of the coroutine scope. You will not need `runBlocking` either.
+However, the benefit of a pipeline that uses channels as shown above is that it can actually use
+multiple CPU cores if you run it in [Dispatchers.Default] context.
+
+Anyway, this is an extremely impractical way to find prime numbers. In practice, pipelines do involve some
+other suspending invocations (like asynchronous calls to remote services) and these pipelines cannot be
+built using `sequence`/`iterator`, because they do not allow arbitrary suspension, unlike
+`produce`, which is fully asynchronous.
+
+### Fan-out
+
+Multiple coroutines may receive from the same channel, distributing work between themselves.
+Let us start with a producer coroutine that is periodically producing integers
+(ten numbers per second):
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.produceNumbers() = produce<Int> {
+ var x = 1 // start from 1
+ while (true) {
+ send(x++) // produce next
+ delay(100) // wait 0.1s
+ }
+}
+```
+
+</div>
+
+Then we can have several processor coroutines. In this example, they just print their id and
+received number:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.launchProcessor(id: Int, channel: ReceiveChannel<Int>) = launch {
+ for (msg in channel) {
+ println("Processor #$id received $msg")
+ }
+}
+```
+
+</div>
+
+Now let us launch five processors and let them work for almost a second. See what happens:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val producer = produceNumbers()
+ repeat(5) { launchProcessor(it, producer) }
+ delay(950)
+ producer.cancel() // cancel producer coroutine and thus kill them all
+//sampleEnd
+}
+
+fun CoroutineScope.produceNumbers() = produce<Int> {
+ var x = 1 // start from 1
+ while (true) {
+ send(x++) // produce next
+ delay(100) // wait 0.1s
+ }
+}
+
+fun CoroutineScope.launchProcessor(id: Int, channel: ReceiveChannel<Int>) = launch {
+ for (msg in channel) {
+ println("Processor #$id received $msg")
+ }
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-channel-06.kt).
+
+The output will be similar to the the following one, albeit the processor ids that receive
+each specific integer may be different:
+
+```
+Processor #2 received 1
+Processor #4 received 2
+Processor #0 received 3
+Processor #1 received 4
+Processor #3 received 5
+Processor #2 received 6
+Processor #4 received 7
+Processor #0 received 8
+Processor #1 received 9
+Processor #3 received 10
+```
+
+<!--- TEST lines.size == 10 && lines.withIndex().all { (i, line) -> line.startsWith("Processor #") && line.endsWith(" received ${i + 1}") } -->
+
+Note that cancelling a producer coroutine closes its channel, thus eventually terminating iteration
+over the channel that processor coroutines are doing.
+
+Also, pay attention to how we explicitly iterate over channel with `for` loop to perform fan-out in `launchProcessor` code.
+Unlike `consumeEach`, this `for` loop pattern is perfectly safe to use from multiple coroutines. If one of the processor
+coroutines fails, then others would still be processing the channel, while a processor that is written via `consumeEach`
+always consumes (cancels) the underlying channel on its normal or abnormal completion.
+
+### Fan-in
+
+Multiple coroutines may send to the same channel.
+For example, let us have a channel of strings, and a suspending function that
+repeatedly sends a specified string to this channel with a specified delay:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+suspend fun sendString(channel: SendChannel<String>, s: String, time: Long) {
+ while (true) {
+ delay(time)
+ channel.send(s)
+ }
+}
+```
+
+</div>
+
+Now, let us see what happens if we launch a couple of coroutines sending strings
+(in this example we launch them in the context of the main thread as main coroutine's children):
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+
+fun main() = runBlocking {
+//sampleStart
+ val channel = Channel<String>()
+ launch { sendString(channel, "foo", 200L) }
+ launch { sendString(channel, "BAR!", 500L) }
+ repeat(6) { // receive first six
+ println(channel.receive())
+ }
+ coroutineContext.cancelChildren() // cancel all children to let main finish
+//sampleEnd
+}
+
+suspend fun sendString(channel: SendChannel<String>, s: String, time: Long) {
+ while (true) {
+ delay(time)
+ channel.send(s)
+ }
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-channel-07.kt).
+
+The output is:
+
+```text
+foo
+foo
+BAR!
+foo
+foo
+BAR!
+```
+
+<!--- TEST -->
+
+### Buffered channels
+
+The channels shown so far had no buffer. Unbuffered channels transfer elements when sender and receiver
+meet each other (aka rendezvous). If send is invoked first, then it is suspended until receive is invoked,
+if receive is invoked first, it is suspended until send is invoked.
+
+Both [Channel()] factory function and [produce] builder take an optional `capacity` parameter to
+specify _buffer size_. Buffer allows senders to send multiple elements before suspending,
+similar to the `BlockingQueue` with a specified capacity, which blocks when buffer is full.
+
+Take a look at the behavior of the following code:
+
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val channel = Channel<Int>(4) // create buffered channel
+ val sender = launch { // launch sender coroutine
+ repeat(10) {
+ println("Sending $it") // print before sending each element
+ channel.send(it) // will suspend when buffer is full
+ }
+ }
+ // don't receive anything... just wait....
+ delay(1000)
+ sender.cancel() // cancel sender coroutine
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-channel-08.kt).
+
+It prints "sending" _five_ times using a buffered channel with capacity of _four_:
+
+```text
+Sending 0
+Sending 1
+Sending 2
+Sending 3
+Sending 4
+```
+
+<!--- TEST -->
+
+The first four elements are added to the buffer and the sender suspends when trying to send the fifth one.
+
+### Channels are fair
+
+Send and receive operations to channels are _fair_ with respect to the order of their invocation from
+multiple coroutines. They are served in first-in first-out order, e.g. the first coroutine to invoke `receive`
+gets the element. In the following example two coroutines "ping" and "pong" are
+receiving the "ball" object from the shared "table" channel.
+
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+
+//sampleStart
+data class Ball(var hits: Int)
+
+fun main() = runBlocking {
+ val table = Channel<Ball>() // a shared table
+ launch { player("ping", table) }
+ launch { player("pong", table) }
+ table.send(Ball(0)) // serve the ball
+ delay(1000) // delay 1 second
+ coroutineContext.cancelChildren() // game over, cancel them
+}
+
+suspend fun player(name: String, table: Channel<Ball>) {
+ for (ball in table) { // receive the ball in a loop
+ ball.hits++
+ println("$name $ball")
+ delay(300) // wait a bit
+ table.send(ball) // send the ball back
+ }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-channel-09.kt).
+
+The "ping" coroutine is started first, so it is the first one to receive the ball. Even though "ping"
+coroutine immediately starts receiving the ball again after sending it back to the table, the ball gets
+received by the "pong" coroutine, because it was already waiting for it:
+
+```text
+ping Ball(hits=1)
+pong Ball(hits=2)
+ping Ball(hits=3)
+pong Ball(hits=4)
+```
+
+<!--- TEST -->
+
+Note that sometimes channels may produce executions that look unfair due to the nature of the executor
+that is being used. See [this issue](https://github.com/Kotlin/kotlinx.coroutines/issues/111) for details.
+
+### Ticker channels
+
+Ticker channel is a special rendezvous channel that produces `Unit` every time given delay passes since last consumption from this channel.
+Though it may seem to be useless standalone, it is a useful building block to create complex time-based [produce]
+pipelines and operators that do windowing and other time-dependent processing.
+Ticker channel can be used in [select] to perform "on tick" action.
+
+To create such channel use a factory method [ticker].
+To indicate that no further elements are needed use [ReceiveChannel.cancel] method on it.
+
+Now let's see how it works in practice:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+
+fun main() = runBlocking<Unit> {
+ val tickerChannel = ticker(delayMillis = 100, initialDelayMillis = 0) // create ticker channel
+ var nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
+ println("Initial element is available immediately: $nextElement") // no initial delay
+
+ nextElement = withTimeoutOrNull(50) { tickerChannel.receive() } // all subsequent elements have 100ms delay
+ println("Next element is not ready in 50 ms: $nextElement")
+
+ nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
+ println("Next element is ready in 100 ms: $nextElement")
+
+ // Emulate large consumption delays
+ println("Consumer pauses for 150ms")
+ delay(150)
+ // Next element is available immediately
+ nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
+ println("Next element is available immediately after large consumer delay: $nextElement")
+ // Note that the pause between `receive` calls is taken into account and next element arrives faster
+ nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
+ println("Next element is ready in 50ms after consumer pause in 150ms: $nextElement")
+
+ tickerChannel.cancel() // indicate that no more elements are needed
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-channel-10.kt).
+
+It prints following lines:
+
+```text
+Initial element is available immediately: kotlin.Unit
+Next element is not ready in 50 ms: null
+Next element is ready in 100 ms: kotlin.Unit
+Consumer pauses for 150ms
+Next element is available immediately after large consumer delay: kotlin.Unit
+Next element is ready in 50ms after consumer pause in 150ms: kotlin.Unit
+```
+
+<!--- TEST -->
+
+Note that [ticker] is aware of possible consumer pauses and, by default, adjusts next produced element
+delay if a pause occurs, trying to maintain a fixed rate of produced elements.
+
+Optionally, a `mode` parameter equal to [TickerMode.FIXED_DELAY] can be specified to maintain a fixed
+delay between elements.
+
+
+<!--- MODULE kotlinx-coroutines-core -->
+<!--- INDEX kotlinx.coroutines -->
+[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
+[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
+[kotlin.coroutines.CoroutineContext.cancelChildren]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/kotlin.coroutines.-coroutine-context/cancel-children.html
+[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html
+<!--- INDEX kotlinx.coroutines.channels -->
+[Channel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel/index.html
+[SendChannel.send]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/send.html
+[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive.html
+[SendChannel.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/close.html
+[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/produce.html
+[consumeEach]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/consume-each.html
+[Channel()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel.html
+[ticker]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/ticker.html
+[ReceiveChannel.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/cancel.html
+[TickerMode.FIXED_DELAY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-ticker-mode/-f-i-x-e-d_-d-e-l-a-y.html
+<!--- INDEX kotlinx.coroutines.selects -->
+[select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html
+<!--- END -->
diff --git a/docs/compatibility.md b/docs/compatibility.md
index b61f6299..8dafae72 100644
--- a/docs/compatibility.md
+++ b/docs/compatibility.md
@@ -1 +1,125 @@
-The documentation has been moved to the [topics/compatibility.md](topics/compatibility.md). \ No newline at end of file
+<!--- TOC -->
+
+* [Compatibility](#compatibility)
+* [Public API types](#public-api-types)
+ * [Experimental API](#experimental-api)
+ * [Flow preview API](#flow-preview-api)
+ * [Obsolete API](#obsolete-api)
+ * [Internal API](#internal-api)
+ * [Stable API](#stable-api)
+ * [Deprecation cycle](#deprecation-cycle)
+* [Using annotated API](#using-annotated-api)
+ * [Programmatically](#programmatically)
+ * [Gradle](#gradle)
+ * [Maven](#maven)
+
+<!--- END -->
+
+## Compatibility
+This document describes the compatibility policy of `kotlinx.coroutines` library since version 1.0.0 and semantics of compatibility-specific annotations.
+
+
+## Public API types
+`kotlinx.coroutines` public API comes in five flavours: stable, experimental, obsolete, internal and deprecated.
+All public API except stable is marked with the corresponding annotation.
+
+### Experimental API
+Experimental API is marked with [@ExperimentalCoroutinesApi][ExperimentalCoroutinesApi] annotation.
+API is marked experimental when its design has potential open questions which may eventually lead to
+either semantics changes of the API or its deprecation.
+
+By default, most of the new API is marked as experimental and becomes stable in one of the next major releases if no new issues arise.
+Otherwise, either semantics is fixed without changes in ABI or API goes through deprecation cycle.
+
+When using experimental API may be dangerous:
+* You are writing a library which depends on `kotlinx.coroutines` and want to use experimental coroutines API in a stable library API.
+It may lead to undesired consequences when end users of your library update their `kotlinx.coroutines` version where experimental API
+has slightly different semantics.
+* You want to build core infrastructure of the application around experimental API.
+
+### Flow preview API
+All [Flow]-related API is marked with [@FlowPreview][FlowPreview] annotation.
+This annotation indicates that Flow API is in preview status.
+We provide no compatibility guarantees between releases for preview features, including binary, source and semantics compatibility.
+
+When using preview API may be dangerous:
+* You are writing a library/framework and want to use [Flow] API in a stable release or in a stable API.
+* You want to use [Flow] in the core infrastructure of your application.
+* You want to use [Flow] as "write-and-forget" solution and cannot afford additional maintenance cost when
+ it comes to `kotlinx.coroutines` updates.
+
+
+### Obsolete API
+Obsolete API is marked with [@ObsoleteCoroutinesApi][ObsoleteCoroutinesApi] annotation.
+Obsolete API is similar to experimental, but already known to have serious design flaws and its potential replacement,
+but replacement is not yet implemented.
+
+The semantics of this API won't be changed, but it will go through a deprecation cycle as soon as the replacement is ready.
+
+### Internal API
+Internal API is marked with [@InternalCoroutinesApi][InternalCoroutinesApi] or is part of `kotlinx.coroutines.internal` package.
+This API has no guarantees on its stability, can and will be changed and/or removed in the future releases.
+If you can't avoid using internal API, please report it to [issue tracker](https://github.com/Kotlin/kotlinx.coroutines/issues/new).
+
+### Stable API
+Stable API is guaranteed to preserve its ABI and documented semantics. If at some point unfixable design flaws will be discovered,
+this API will go through a deprecation cycle and remain binary compatible as long as possible.
+
+### Deprecation cycle
+When some API is deprecated, it goes through multiple stages and there is at least one major release between stages.
+* Feature is deprecated with compilation warning. Most of the time, proper replacement
+(and corresponding `replaceWith` declaration) is provided to automatically migrate deprecated usages with a help of IntelliJ IDEA.
+* Deprecation level is increased to `error` or `hidden`. It is no longer possible to compile new code against deprecated API,
+ though it is still present in the ABI.
+* API is completely removed. While we give our best efforts not to do so and have no plans of removing any API, we still are leaving
+this option in case of unforeseen problems such as security holes.
+
+## Using annotated API
+All API annotations are [kotlin.Experimental](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-experimental/index.html).
+It is done in order to produce compilation warning about using experimental or obsolete API.
+Warnings can be disabled either programmatically for a specific call site or globally for the whole module.
+
+### Programmatically
+For a specific call-site, warning can be disabled by using [UseExperimental](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-use-experimental/index.html) annotation:
+```kotlin
+@UseExperimental(ExperimentalCoroutinesApi::class) // Disables warning about experimental coroutines API
+fun experimentalApiUsage() {
+ someKotlinxCoroutinesExperimentalMethod()
+}
+```
+
+### Gradle
+For the Gradle project, a warning can be disabled by passing a compiler flag in your `build.gradle` file:
+
+```groovy
+tasks.withType(org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile).all {
+ kotlinOptions.freeCompilerArgs += ["-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi"]
+}
+
+```
+
+### Maven
+For the Maven project, a warning can be disabled by passing a compiler flag in your `pom.xml` file:
+```xml
+<plugin>
+ <artifactId>kotlin-maven-plugin</artifactId>
+ <groupId>org.jetbrains.kotlin</groupId>
+ ... your configuration ...
+ <configuration>
+ <args>
+ <arg>-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi</arg>
+ </args>
+ </configuration>
+</plugin>
+```
+
+
+<!--- MODULE kotlinx-coroutines-core -->
+<!--- INDEX kotlinx.coroutines.flow -->
+[Flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html
+<!--- INDEX kotlinx.coroutines -->
+[ExperimentalCoroutinesApi]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-experimental-coroutines-api/index.html
+[FlowPreview]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-flow-preview/index.html
+[ObsoleteCoroutinesApi]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-obsolete-coroutines-api/index.html
+[InternalCoroutinesApi]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-internal-coroutines-api/index.html
+<!--- END -->
diff --git a/docs/composing-suspending-functions.md b/docs/composing-suspending-functions.md
index 4318c4ee..81b6f53c 100644
--- a/docs/composing-suspending-functions.md
+++ b/docs/composing-suspending-functions.md
@@ -1,3 +1,435 @@
-The documentation has been moved to the [https://kotlinlang.org/docs/composing-suspending-functions.html](https://kotlinlang.org/docs/composing-suspending-functions.html) page.
+<!--- TEST_NAME ComposingGuideTest -->
-To edit the documentation, open the [topics/composing-suspending-functions.md](topics/composing-suspending-functions.md) page. \ No newline at end of file
+**Table of contents**
+
+<!--- TOC -->
+
+* [Composing Suspending Functions](#composing-suspending-functions)
+ * [Sequential by default](#sequential-by-default)
+ * [Concurrent using async](#concurrent-using-async)
+ * [Lazily started async](#lazily-started-async)
+ * [Async-style functions](#async-style-functions)
+ * [Structured concurrency with async](#structured-concurrency-with-async)
+
+<!--- END -->
+
+## Composing Suspending Functions
+
+This section covers various approaches to composition of suspending functions.
+
+### Sequential by default
+
+Assume that we have two suspending functions defined elsewhere that do something useful like some kind of
+remote service call or computation. We just pretend they are useful, but actually each one just
+delays for a second for the purpose of this example:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+suspend fun doSomethingUsefulOne(): Int {
+ delay(1000L) // pretend we are doing something useful here
+ return 13
+}
+
+suspend fun doSomethingUsefulTwo(): Int {
+ delay(1000L) // pretend we are doing something useful here, too
+ return 29
+}
+```
+
+</div>
+
+
+What do we do if we need them to be invoked _sequentially_ &mdash; first `doSomethingUsefulOne` _and then_
+`doSomethingUsefulTwo`, and compute the sum of their results?
+In practice we do this if we use the result of the first function to make a decision on whether we need
+to invoke the second one or to decide on how to invoke it.
+
+We use a normal sequential invocation, because the code in the coroutine, just like in the regular
+code, is _sequential_ by default. The following example demonstrates it by measuring the total
+time it takes to execute both suspending functions:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlin.system.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val time = measureTimeMillis {
+ val one = doSomethingUsefulOne()
+ val two = doSomethingUsefulTwo()
+ println("The answer is ${one + two}")
+ }
+ println("Completed in $time ms")
+//sampleEnd
+}
+
+suspend fun doSomethingUsefulOne(): Int {
+ delay(1000L) // pretend we are doing something useful here
+ return 13
+}
+
+suspend fun doSomethingUsefulTwo(): Int {
+ delay(1000L) // pretend we are doing something useful here, too
+ return 29
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-compose-01.kt).
+
+It produces something like this:
+
+```text
+The answer is 42
+Completed in 2017 ms
+```
+
+<!--- TEST ARBITRARY_TIME -->
+
+### Concurrent using async
+
+What if there are no dependencies between invocations of `doSomethingUsefulOne` and `doSomethingUsefulTwo` and
+we want to get the answer faster, by doing both _concurrently_? This is where [async] comes to help.
+
+Conceptually, [async] is just like [launch]. It starts a separate coroutine which is a light-weight thread
+that works concurrently with all the other coroutines. The difference is that `launch` returns a [Job] and
+does not carry any resulting value, while `async` returns a [Deferred] &mdash; a light-weight non-blocking future
+that represents a promise to provide a result later. You can use `.await()` on a deferred value to get its eventual result,
+but `Deferred` is also a `Job`, so you can cancel it if needed.
+
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlin.system.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val time = measureTimeMillis {
+ val one = async { doSomethingUsefulOne() }
+ val two = async { doSomethingUsefulTwo() }
+ println("The answer is ${one.await() + two.await()}")
+ }
+ println("Completed in $time ms")
+//sampleEnd
+}
+
+suspend fun doSomethingUsefulOne(): Int {
+ delay(1000L) // pretend we are doing something useful here
+ return 13
+}
+
+suspend fun doSomethingUsefulTwo(): Int {
+ delay(1000L) // pretend we are doing something useful here, too
+ return 29
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-compose-02.kt).
+
+It produces something like this:
+
+```text
+The answer is 42
+Completed in 1017 ms
+```
+
+<!--- TEST ARBITRARY_TIME -->
+
+This is twice as fast, because the two coroutines execute concurrently.
+Note that concurrency with coroutines is always explicit.
+
+### Lazily started async
+
+Optionally, [async] can be made lazy by setting its `start` parameter to [CoroutineStart.LAZY].
+In this mode it only starts the coroutine when its result is required by
+[await][Deferred.await], or if its `Job`'s [start][Job.start] function
+is invoked. Run the following example:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlin.system.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val time = measureTimeMillis {
+ val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
+ val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
+ // some computation
+ one.start() // start the first one
+ two.start() // start the second one
+ println("The answer is ${one.await() + two.await()}")
+ }
+ println("Completed in $time ms")
+//sampleEnd
+}
+
+suspend fun doSomethingUsefulOne(): Int {
+ delay(1000L) // pretend we are doing something useful here
+ return 13
+}
+
+suspend fun doSomethingUsefulTwo(): Int {
+ delay(1000L) // pretend we are doing something useful here, too
+ return 29
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-compose-03.kt).
+
+It produces something like this:
+
+```text
+The answer is 42
+Completed in 1017 ms
+```
+
+<!--- TEST ARBITRARY_TIME -->
+
+So, here the two coroutines are defined but not executed as in the previous example, but the control is given to
+the programmer on when exactly to start the execution by calling [start][Job.start]. We first
+start `one`, then start `two`, and then await for the individual coroutines to finish.
+
+Note that if we just call [await][Deferred.await] in `println` without first calling [start][Job.start] on individual
+coroutines, this will lead to sequential behavior, since [await][Deferred.await] starts the coroutine
+execution and waits for its finish, which is not the intended use-case for laziness.
+The use-case for `async(start = CoroutineStart.LAZY)` is a replacement for the
+standard `lazy` function in cases when computation of the value involves suspending functions.
+
+### Async-style functions
+
+We can define async-style functions that invoke `doSomethingUsefulOne` and `doSomethingUsefulTwo`
+_asynchronously_ using the [async] coroutine builder with an explicit [GlobalScope] reference.
+We name such functions with the
+"...Async" suffix to highlight the fact that they only start asynchronous computation and one needs
+to use the resulting deferred value to get the result.
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+// The result type of somethingUsefulOneAsync is Deferred<Int>
+fun somethingUsefulOneAsync() = GlobalScope.async {
+ doSomethingUsefulOne()
+}
+
+// The result type of somethingUsefulTwoAsync is Deferred<Int>
+fun somethingUsefulTwoAsync() = GlobalScope.async {
+ doSomethingUsefulTwo()
+}
+```
+
+</div>
+
+Note that these `xxxAsync` functions are **not** _suspending_ functions. They can be used from anywhere.
+However, their use always implies asynchronous (here meaning _concurrent_) execution of their action
+with the invoking code.
+
+The following example shows their use outside of coroutine:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlin.system.*
+
+//sampleStart
+// note that we don't have `runBlocking` to the right of `main` in this example
+fun main() {
+ val time = measureTimeMillis {
+ // we can initiate async actions outside of a coroutine
+ val one = somethingUsefulOneAsync()
+ val two = somethingUsefulTwoAsync()
+ // but waiting for a result must involve either suspending or blocking.
+ // here we use `runBlocking { ... }` to block the main thread while waiting for the result
+ runBlocking {
+ println("The answer is ${one.await() + two.await()}")
+ }
+ }
+ println("Completed in $time ms")
+}
+//sampleEnd
+
+fun somethingUsefulOneAsync() = GlobalScope.async {
+ doSomethingUsefulOne()
+}
+
+fun somethingUsefulTwoAsync() = GlobalScope.async {
+ doSomethingUsefulTwo()
+}
+
+suspend fun doSomethingUsefulOne(): Int {
+ delay(1000L) // pretend we are doing something useful here
+ return 13
+}
+
+suspend fun doSomethingUsefulTwo(): Int {
+ delay(1000L) // pretend we are doing something useful here, too
+ return 29
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-compose-04.kt).
+
+<!--- TEST ARBITRARY_TIME
+The answer is 42
+Completed in 1085 ms
+-->
+
+> This programming style with async functions is provided here only for illustration, because it is a popular style
+in other programming languages. Using this style with Kotlin coroutines is **strongly discouraged** for the
+reasons explained below.
+
+Consider what happens if between the `val one = somethingUsefulOneAsync()` line and `one.await()` expression there is some logic
+error in the code and the program throws an exception and the operation that was being performed by the program aborts.
+Normally, a global error-handler could catch this exception, log and report the error for developers, but the program
+could otherwise continue doing other operations. But here we have `somethingUsefulOneAsync` still running in the background,
+even though the operation that initiated it was aborted. This problem does not happen with structured
+concurrency, as shown in the section below.
+
+### Structured concurrency with async
+
+Let us take the [Concurrent using async](#concurrent-using-async) example and extract a function that
+concurrently performs `doSomethingUsefulOne` and `doSomethingUsefulTwo` and returns the sum of their results.
+Because the [async] coroutine builder is defined as an extension on [CoroutineScope], we need to have it in the
+scope and that is what the [coroutineScope][_coroutineScope] function provides:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+suspend fun concurrentSum(): Int = coroutineScope {
+ val one = async { doSomethingUsefulOne() }
+ val two = async { doSomethingUsefulTwo() }
+ one.await() + two.await()
+}
+```
+
+</div>
+
+This way, if something goes wrong inside the code of the `concurrentSum` function and it throws an exception,
+all the coroutines that were launched in its scope will be cancelled.
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlin.system.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val time = measureTimeMillis {
+ println("The answer is ${concurrentSum()}")
+ }
+ println("Completed in $time ms")
+//sampleEnd
+}
+
+suspend fun concurrentSum(): Int = coroutineScope {
+ val one = async { doSomethingUsefulOne() }
+ val two = async { doSomethingUsefulTwo() }
+ one.await() + two.await()
+}
+
+suspend fun doSomethingUsefulOne(): Int {
+ delay(1000L) // pretend we are doing something useful here
+ return 13
+}
+
+suspend fun doSomethingUsefulTwo(): Int {
+ delay(1000L) // pretend we are doing something useful here, too
+ return 29
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-compose-05.kt).
+
+We still have concurrent execution of both operations, as evident from the output of the above `main` function:
+
+```text
+The answer is 42
+Completed in 1017 ms
+```
+
+<!--- TEST ARBITRARY_TIME -->
+
+Cancellation is always propagated through coroutines hierarchy:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking<Unit> {
+ try {
+ failedConcurrentSum()
+ } catch(e: ArithmeticException) {
+ println("Computation failed with ArithmeticException")
+ }
+}
+
+suspend fun failedConcurrentSum(): Int = coroutineScope {
+ val one = async<Int> {
+ try {
+ delay(Long.MAX_VALUE) // Emulates very long computation
+ 42
+ } finally {
+ println("First child was cancelled")
+ }
+ }
+ val two = async<Int> {
+ println("Second child throws an exception")
+ throw ArithmeticException()
+ }
+ one.await() + two.await()
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-compose-06.kt).
+
+Note how both the first `async` and the awaiting parent are cancelled on failure of one of the children
+(namely, `two`):
+```text
+Second child throws an exception
+First child was cancelled
+Computation failed with ArithmeticException
+```
+
+<!--- TEST -->
+
+<!--- MODULE kotlinx-coroutines-core -->
+<!--- INDEX kotlinx.coroutines -->
+[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
+[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
+[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
+[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html
+[CoroutineStart.LAZY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/-l-a-z-y.html
+[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/await.html
+[Job.start]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/start.html
+[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
+[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
+[_coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
+<!--- END -->
diff --git a/docs/coroutine-context-and-dispatchers.md b/docs/coroutine-context-and-dispatchers.md
index f8ba1283..36e049db 100644
--- a/docs/coroutine-context-and-dispatchers.md
+++ b/docs/coroutine-context-and-dispatchers.md
@@ -1,3 +1,712 @@
-The documentation has been moved to the [https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html](https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html) page.
+<!--- TEST_NAME DispatcherGuideTest -->
-To edit the documentation, open the [topics/coroutine-context-and-dispatchers.md](topics/coroutine-context-and-dispatchers.md) page. \ No newline at end of file
+**Table of contents**
+
+<!--- TOC -->
+
+* [Coroutine Context and Dispatchers](#coroutine-context-and-dispatchers)
+ * [Dispatchers and threads](#dispatchers-and-threads)
+ * [Unconfined vs confined dispatcher](#unconfined-vs-confined-dispatcher)
+ * [Debugging coroutines and threads](#debugging-coroutines-and-threads)
+ * [Debugging with IDEA](#debugging-with-idea)
+ * [Debugging using logging](#debugging-using-logging)
+ * [Jumping between threads](#jumping-between-threads)
+ * [Job in the context](#job-in-the-context)
+ * [Children of a coroutine](#children-of-a-coroutine)
+ * [Parental responsibilities](#parental-responsibilities)
+ * [Naming coroutines for debugging](#naming-coroutines-for-debugging)
+ * [Combining context elements](#combining-context-elements)
+ * [Coroutine scope](#coroutine-scope)
+ * [Thread-local data](#thread-local-data)
+
+<!--- END -->
+
+## Coroutine Context and Dispatchers
+
+Coroutines always execute in some context represented by a value of the
+[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/)
+type, defined in the Kotlin standard library.
+
+The coroutine context is a set of various elements. The main elements are the [Job] of the coroutine,
+which we've seen before, and its dispatcher, which is covered in this section.
+
+### Dispatchers and threads
+
+The coroutine context includes a _coroutine dispatcher_ (see [CoroutineDispatcher]) that determines what thread or threads
+the corresponding coroutine uses for its execution. The coroutine dispatcher can confine coroutine execution
+to a specific thread, dispatch it to a thread pool, or let it run unconfined.
+
+All coroutine builders like [launch] and [async] accept an optional
+[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/)
+parameter that can be used to explicitly specify the dispatcher for the new coroutine and other context elements.
+
+Try the following example:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ launch { // context of the parent, main runBlocking coroutine
+ println("main runBlocking : I'm working in thread ${Thread.currentThread().name}")
+ }
+ launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
+ println("Unconfined : I'm working in thread ${Thread.currentThread().name}")
+ }
+ launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher
+ println("Default : I'm working in thread ${Thread.currentThread().name}")
+ }
+ launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
+ println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
+ }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-01.kt).
+
+It produces the following output (maybe in different order):
+
+```text
+Unconfined : I'm working in thread main
+Default : I'm working in thread DefaultDispatcher-worker-1
+newSingleThreadContext: I'm working in thread MyOwnThread
+main runBlocking : I'm working in thread main
+```
+
+<!--- TEST LINES_START_UNORDERED -->
+
+When `launch { ... }` is used without parameters, it inherits the context (and thus dispatcher)
+from the [CoroutineScope] it is being launched from. In this case, it inherits the
+context of the main `runBlocking` coroutine which runs in the `main` thread.
+
+[Dispatchers.Unconfined] is a special dispatcher that also appears to run in the `main` thread, but it is,
+in fact, a different mechanism that is explained later.
+
+The default dispatcher that is used when coroutines are launched in [GlobalScope]
+is represented by [Dispatchers.Default] and uses a shared background pool of threads,
+so `launch(Dispatchers.Default) { ... }` uses the same dispatcher as `GlobalScope.launch { ... }`.
+
+[newSingleThreadContext] creates a thread for the coroutine to run.
+A dedicated thread is a very expensive resource.
+In a real application it must be either released, when no longer needed, using the [close][ExecutorCoroutineDispatcher.close]
+function, or stored in a top-level variable and reused throughout the application.
+
+### Unconfined vs confined dispatcher
+
+The [Dispatchers.Unconfined] coroutine dispatcher starts a coroutine in the caller thread, but only until the
+first suspension point. After suspension it resumes the coroutine in the thread that is fully determined by the
+suspending function that was invoked. The unconfined dispatcher is appropriate for coroutines which neither
+consume CPU time nor update any shared data (like UI) confined to a specific thread.
+
+On the other side, the dispatcher is inherited from the outer [CoroutineScope] by default.
+The default dispatcher for the [runBlocking] coroutine, in particular,
+is confined to the invoker thread, so inheriting it has the effect of confining execution to
+this thread with predictable FIFO scheduling.
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
+ println("Unconfined : I'm working in thread ${Thread.currentThread().name}")
+ delay(500)
+ println("Unconfined : After delay in thread ${Thread.currentThread().name}")
+ }
+ launch { // context of the parent, main runBlocking coroutine
+ println("main runBlocking: I'm working in thread ${Thread.currentThread().name}")
+ delay(1000)
+ println("main runBlocking: After delay in thread ${Thread.currentThread().name}")
+ }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-02.kt).
+
+Produces the output:
+
+```text
+Unconfined : I'm working in thread main
+main runBlocking: I'm working in thread main
+Unconfined : After delay in thread kotlinx.coroutines.DefaultExecutor
+main runBlocking: After delay in thread main
+```
+
+<!--- TEST LINES_START -->
+
+So, the coroutine with the context inherited from `runBlocking {...}` continues to execute
+in the `main` thread, while the unconfined one resumes in the default executor thread that the [delay]
+function is using.
+
+> The unconfined dispatcher is an advanced mechanism that can be helpful in certain corner cases where
+dispatching of a coroutine for its execution later is not needed or produces undesirable side-effects,
+because some operation in a coroutine must be performed right away.
+The unconfined dispatcher should not be used in general code.
+
+### Debugging coroutines and threads
+
+Coroutines can suspend on one thread and resume on another thread.
+Even with a single-threaded dispatcher it might be hard to
+figure out what the coroutine was doing, where, and when if you don't have special tooling.
+
+#### Debugging with IDEA
+
+The Coroutine Debugger of the Kotlin plugin simplifies debugging coroutines in IntelliJ IDEA.
+
+> Debugging works for versions 1.3.8 or later of `kotlinx-coroutines-core`.
+
+The **Debug** tool window contains the **Coroutines** tab. In this tab, you can find information about both currently running and suspended coroutines.
+The coroutines are grouped by the dispatcher they are running on.
+
+![Debugging coroutines](images/coroutine-idea-debugging-1.png)
+
+With the coroutine debugger, you can:
+* Check the state of each coroutine.
+* See the values of local and captured variables for both running and suspended coroutines.
+* See a full coroutine creation stack, as well as a call stack inside the coroutine. The stack includes all frames with
+variable values, even those that would be lost during standard debugging.
+* Get a full report that contains the state of each coroutine and its stack. To obtain it, right-click inside the **Coroutines** tab, and then click **Get Coroutines Dump**.
+
+To start coroutine debugging, you just need to set breakpoints and run the application in debug mode.
+
+Learn more about coroutines debugging in the [tutorial](https://kotlinlang.org/docs/tutorials/coroutines/debug-coroutines-with-idea.html).
+
+#### Debugging using logging
+
+Another approach to debugging applications with
+threads without Coroutine Debugger is to print the thread name in the log file on each log statement. This feature is universally supported
+by logging frameworks. When using coroutines, the thread name alone does not give much of a context, so
+`kotlinx.coroutines` includes debugging facilities to make it easier.
+
+Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val a = async {
+ log("I'm computing a piece of the answer")
+ 6
+ }
+ val b = async {
+ log("I'm computing another piece of the answer")
+ 7
+ }
+ log("The answer is ${a.await() * b.await()}")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-03.kt).
+
+There are three coroutines. The main coroutine (#1) inside `runBlocking`
+and two coroutines computing the deferred values `a` (#2) and `b` (#3).
+They are all executing in the context of `runBlocking` and are confined to the main thread.
+The output of this code is:
+
+```text
+[main @coroutine#2] I'm computing a piece of the answer
+[main @coroutine#3] I'm computing another piece of the answer
+[main @coroutine#1] The answer is 42
+```
+
+<!--- TEST FLEXIBLE_THREAD -->
+
+The `log` function prints the name of the thread in square brackets, and you can see that it is the `main`
+thread with the identifier of the currently executing coroutine appended to it. This identifier
+is consecutively assigned to all created coroutines when the debugging mode is on.
+
+> Debugging mode is also turned on when JVM is run with `-ea` option.
+You can read more about debugging facilities in the documentation of the [DEBUG_PROPERTY_NAME] property.
+
+### Jumping between threads
+
+Run the following code with the `-Dkotlinx.coroutines.debug` JVM option (see [debug](#debugging-coroutines-and-threads)):
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
+
+fun main() {
+//sampleStart
+ newSingleThreadContext("Ctx1").use { ctx1 ->
+ newSingleThreadContext("Ctx2").use { ctx2 ->
+ runBlocking(ctx1) {
+ log("Started in ctx1")
+ withContext(ctx2) {
+ log("Working in ctx2")
+ }
+ log("Back to ctx1")
+ }
+ }
+ }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-04.kt).
+
+It demonstrates several new techniques. One is using [runBlocking] with an explicitly specified context, and
+the other one is using the [withContext] function to change the context of a coroutine while still staying in the
+same coroutine, as you can see in the output below:
+
+```text
+[Ctx1 @coroutine#1] Started in ctx1
+[Ctx2 @coroutine#1] Working in ctx2
+[Ctx1 @coroutine#1] Back to ctx1
+```
+
+<!--- TEST -->
+
+Note that this example also uses the `use` function from the Kotlin standard library to release threads
+created with [newSingleThreadContext] when they are no longer needed.
+
+### Job in the context
+
+The coroutine's [Job] is part of its context, and can be retrieved from it
+using the `coroutineContext[Job]` expression:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ println("My job is ${coroutineContext[Job]}")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-05.kt).
+
+In the [debug mode](#debugging-coroutines-and-threads), it outputs something like this:
+
+```
+My job is "coroutine#1":BlockingCoroutine{Active}@6d311334
+```
+
+<!--- TEST lines.size == 1 && lines[0].startsWith("My job is \"coroutine#1\":BlockingCoroutine{Active}@") -->
+
+Note that [isActive] in [CoroutineScope] is just a convenient shortcut for
+`coroutineContext[Job]?.isActive == true`.
+
+### Children of a coroutine
+
+When a coroutine is launched in the [CoroutineScope] of another coroutine,
+it inherits its context via [CoroutineScope.coroutineContext] and
+the [Job] of the new coroutine becomes
+a _child_ of the parent coroutine's job. When the parent coroutine is cancelled, all its children
+are recursively cancelled, too.
+
+However, when [GlobalScope] is used to launch a coroutine, there is no parent for the job of the new coroutine.
+It is therefore not tied to the scope it was launched from and operates independently.
+
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ // launch a coroutine to process some kind of incoming request
+ val request = launch {
+ // it spawns two other jobs, one with GlobalScope
+ GlobalScope.launch {
+ println("job1: I run in GlobalScope and execute independently!")
+ delay(1000)
+ println("job1: I am not affected by cancellation of the request")
+ }
+ // and the other inherits the parent context
+ launch {
+ delay(100)
+ println("job2: I am a child of the request coroutine")
+ delay(1000)
+ println("job2: I will not execute this line if my parent request is cancelled")
+ }
+ }
+ delay(500)
+ request.cancel() // cancel processing of the request
+ delay(1000) // delay a second to see what happens
+ println("main: Who has survived request cancellation?")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-06.kt).
+
+The output of this code is:
+
+```text
+job1: I run in GlobalScope and execute independently!
+job2: I am a child of the request coroutine
+job1: I am not affected by cancellation of the request
+main: Who has survived request cancellation?
+```
+
+<!--- TEST -->
+
+### Parental responsibilities
+
+A parent coroutine always waits for completion of all its children. A parent does not have to explicitly track
+all the children it launches, and it does not have to use [Job.join] to wait for them at the end:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ // launch a coroutine to process some kind of incoming request
+ val request = launch {
+ repeat(3) { i -> // launch a few children jobs
+ launch {
+ delay((i + 1) * 200L) // variable delay 200ms, 400ms, 600ms
+ println("Coroutine $i is done")
+ }
+ }
+ println("request: I'm done and I don't explicitly join my children that are still active")
+ }
+ request.join() // wait for completion of the request, including all its children
+ println("Now processing of the request is complete")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-07.kt).
+
+The result is going to be:
+
+```text
+request: I'm done and I don't explicitly join my children that are still active
+Coroutine 0 is done
+Coroutine 1 is done
+Coroutine 2 is done
+Now processing of the request is complete
+```
+
+<!--- TEST -->
+
+### Naming coroutines for debugging
+
+Automatically assigned ids are good when coroutines log often and you just need to correlate log records
+coming from the same coroutine. However, when a coroutine is tied to the processing of a specific request
+or doing some specific background task, it is better to name it explicitly for debugging purposes.
+The [CoroutineName] context element serves the same purpose as the thread name. It is included in the thread name that
+is executing this coroutine when the [debugging mode](#debugging-coroutines-and-threads) is turned on.
+
+The following example demonstrates this concept:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
+
+fun main() = runBlocking(CoroutineName("main")) {
+//sampleStart
+ log("Started main coroutine")
+ // run two background value computations
+ val v1 = async(CoroutineName("v1coroutine")) {
+ delay(500)
+ log("Computing v1")
+ 252
+ }
+ val v2 = async(CoroutineName("v2coroutine")) {
+ delay(1000)
+ log("Computing v2")
+ 6
+ }
+ log("The answer for v1 / v2 = ${v1.await() / v2.await()}")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-08.kt).
+
+The output it produces with `-Dkotlinx.coroutines.debug` JVM option is similar to:
+
+```text
+[main @main#1] Started main coroutine
+[main @v1coroutine#2] Computing v1
+[main @v2coroutine#3] Computing v2
+[main @main#1] The answer for v1 / v2 = 42
+```
+
+<!--- TEST FLEXIBLE_THREAD -->
+
+### Combining context elements
+
+Sometimes we need to define multiple elements for a coroutine context. We can use the `+` operator for that.
+For example, we can launch a coroutine with an explicitly specified dispatcher and an explicitly specified
+name at the same time:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ launch(Dispatchers.Default + CoroutineName("test")) {
+ println("I'm working in thread ${Thread.currentThread().name}")
+ }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-09.kt).
+
+The output of this code with the `-Dkotlinx.coroutines.debug` JVM option is:
+
+```text
+I'm working in thread DefaultDispatcher-worker-1 @test#2
+```
+
+<!--- TEST FLEXIBLE_THREAD -->
+
+### Coroutine scope
+
+Let us put our knowledge about contexts, children and jobs together. Assume that our application has
+an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application
+and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch
+and update data, do animations, etc. All of these coroutines must be cancelled when the activity is destroyed
+to avoid memory leaks. We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity
+and its coroutines, but `kotlinx.coroutines` provides an abstraction encapsulating that: [CoroutineScope].
+You should be already familiar with the coroutine scope as all coroutine builders are declared as extensions on it.
+
+We manage the lifecycles of our coroutines by creating an instance of [CoroutineScope] tied to
+the lifecycle of our activity. A `CoroutineScope` instance can be created by the [CoroutineScope()] or [MainScope()]
+factory functions. The former creates a general-purpose scope, while the latter creates a scope for UI applications and uses
+[Dispatchers.Main] as the default dispatcher:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+class Activity {
+ private val mainScope = MainScope()
+
+ fun destroy() {
+ mainScope.cancel()
+ }
+ // to be continued ...
+```
+
+</div>
+
+Now, we can launch coroutines in the scope of this `Activity` using the defined `scope`.
+For the demo, we launch ten coroutines that delay for a different time:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+ // class Activity continues
+ fun doSomething() {
+ // launch ten coroutines for a demo, each working for a different time
+ repeat(10) { i ->
+ mainScope.launch {
+ delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
+ println("Coroutine $i is done")
+ }
+ }
+ }
+} // class Activity ends
+```
+
+</div>
+
+In our main function we create the activity, call our test `doSomething` function, and destroy the activity after 500ms.
+This cancels all the coroutines that were launched from `doSomething`. We can see that because after the destruction
+of the activity no more messages are printed, even if we wait a little longer.
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+class Activity {
+ private val mainScope = CoroutineScope(Dispatchers.Default) // use Default for test purposes
+
+ fun destroy() {
+ mainScope.cancel()
+ }
+
+ fun doSomething() {
+ // launch ten coroutines for a demo, each working for a different time
+ repeat(10) { i ->
+ mainScope.launch {
+ delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
+ println("Coroutine $i is done")
+ }
+ }
+ }
+} // class Activity ends
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val activity = Activity()
+ activity.doSomething() // run test function
+ println("Launched coroutines")
+ delay(500L) // delay for half a second
+ println("Destroying activity!")
+ activity.destroy() // cancels all coroutines
+ delay(1000) // visually confirm that they don't work
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-10.kt).
+
+The output of this example is:
+
+```text
+Launched coroutines
+Coroutine 0 is done
+Coroutine 1 is done
+Destroying activity!
+```
+
+<!--- TEST -->
+
+As you can see, only the first two coroutines print a message and the others are cancelled
+by a single invocation of `job.cancel()` in `Activity.destroy()`.
+
+> Note, that Android has first-party support for coroutine scope in all entities with the lifecycle.
+See [the corresponding documentation](https://developer.android.com/topic/libraries/architecture/coroutines#lifecyclescope).
+
+### Thread-local data
+
+Sometimes it is convenient to have an ability to pass some thread-local data to or between coroutines.
+However, since they are not bound to any particular thread, this will likely lead to boilerplate if done manually.
+
+For [`ThreadLocal`](https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html),
+the [asContextElement] extension function is here for the rescue. It creates an additional context element
+which keeps the value of the given `ThreadLocal` and restores it every time the coroutine switches its context.
+
+It is easy to demonstrate it in action:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+val threadLocal = ThreadLocal<String?>() // declare thread-local variable
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ threadLocal.set("main")
+ println("Pre-main, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
+ val job = launch(Dispatchers.Default + threadLocal.asContextElement(value = "launch")) {
+ println("Launch start, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
+ yield()
+ println("After yield, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
+ }
+ job.join()
+ println("Post-main, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-context-11.kt).
+
+In this example we launch a new coroutine in a background thread pool using [Dispatchers.Default], so
+it works on a different thread from the thread pool, but it still has the value of the thread local variable
+that we specified using `threadLocal.asContextElement(value = "launch")`,
+no matter which thread the coroutine is executed on.
+Thus, the output (with [debug](#debugging-coroutines-and-threads)) is:
+
+```text
+Pre-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'
+Launch start, current thread: Thread[DefaultDispatcher-worker-1 @coroutine#2,5,main], thread local value: 'launch'
+After yield, current thread: Thread[DefaultDispatcher-worker-2 @coroutine#2,5,main], thread local value: 'launch'
+Post-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'
+```
+
+<!--- TEST FLEXIBLE_THREAD -->
+
+It's easy to forget to set the corresponding context element. The thread-local variable accessed from the coroutine may
+then have an unexpected value, if the thread running the coroutine is different.
+To avoid such situations, it is recommended to use the [ensurePresent] method
+and fail-fast on improper usages.
+
+`ThreadLocal` has first-class support and can be used with any primitive `kotlinx.coroutines` provides.
+It has one key limitation, though: when a thread-local is mutated, a new value is not propagated to the coroutine caller
+(because a context element cannot track all `ThreadLocal` object accesses), and the updated value is lost on the next suspension.
+Use [withContext] to update the value of the thread-local in a coroutine, see [asContextElement] for more details.
+
+Alternatively, a value can be stored in a mutable box like `class Counter(var i: Int)`, which is, in turn,
+stored in a thread-local variable. However, in this case you are fully responsible to synchronize
+potentially concurrent modifications to the variable in this mutable box.
+
+For advanced usage, for example for integration with logging MDC, transactional contexts or any other libraries
+which internally use thread-locals for passing data, see the documentation of the [ThreadContextElement] interface
+that should be implemented.
+
+<!--- MODULE kotlinx-coroutines-core -->
+<!--- INDEX kotlinx.coroutines -->
+[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
+[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html
+[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
+[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
+[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
+[Dispatchers.Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html
+[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
+[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html
+[newSingleThreadContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/new-single-thread-context.html
+[ExecutorCoroutineDispatcher.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-executor-coroutine-dispatcher/close.html
+[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
+[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
+[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
+[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
+[isActive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/is-active.html
+[CoroutineScope.coroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html
+[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
+[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-name/index.html
+[CoroutineScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
+[MainScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-scope.html
+[Dispatchers.Main]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html
+[asContextElement]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/java.lang.-thread-local/as-context-element.html
+[ensurePresent]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/java.lang.-thread-local/ensure-present.html
+[ThreadContextElement]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-thread-context-element/index.html
+<!--- END -->
diff --git a/docs/coroutines-guide.md b/docs/coroutines-guide.md
index e2caa750..2d15a7bb 100644
--- a/docs/coroutines-guide.md
+++ b/docs/coroutines-guide.md
@@ -1,3 +1,32 @@
-The documentation has been moved to the [https://kotlinlang.org/docs/coroutines-guide.html](https://kotlinlang.org/docs/coroutines-guide.html) page.
-To edit the documentation, open the [topics/coroutines-guide.md](topics/coroutines-guide.md) page. \ No newline at end of file
+Kotlin, as a language, provides only minimal low-level APIs in its standard library to enable various other
+libraries to utilize coroutines. Unlike many other languages with similar capabilities, `async` and `await`
+are not keywords in Kotlin and are not even part of its standard library. Moreover, Kotlin's concept
+of _suspending function_ provides a safer and less error-prone abstraction for asynchronous
+operations than futures and promises.
+
+`kotlinx.coroutines` is a rich library for coroutines developed by JetBrains. It contains a number of high-level
+coroutine-enabled primitives that this guide covers, including `launch`, `async` and others.
+
+This is a guide on core features of `kotlinx.coroutines` with a series of examples, divided up into different topics.
+
+In order to use coroutines as well as follow the examples in this guide, you need to add a dependency on the `kotlinx-coroutines-core` module as explained
+[in the project README](../README.md#using-in-your-projects).
+
+## Table of contents
+
+* [Basics](basics.md)
+* [Cancellation and Timeouts](cancellation-and-timeouts.md)
+* [Composing Suspending Functions](composing-suspending-functions.md)
+* [Coroutine Context and Dispatchers](coroutine-context-and-dispatchers.md)
+* [Asynchronous Flow](flow.md)
+* [Channels](channels.md)
+* [Exception Handling and Supervision](exception-handling.md)
+* [Shared Mutable State and Concurrency](shared-mutable-state-and-concurrency.md)
+* [Select Expression (experimental)](select-expression.md)
+
+## Additional references
+
+* [Guide to UI programming with coroutines](../ui/coroutines-guide-ui.md)
+* [Coroutines design document (KEEP)](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md)
+* [Full kotlinx.coroutines API reference](https://kotlin.github.io/kotlinx.coroutines)
diff --git a/docs/debugging.md b/docs/debugging.md
index a5dab630..6c846f23 100644
--- a/docs/debugging.md
+++ b/docs/debugging.md
@@ -1 +1,106 @@
-The documentation has been moved to the [topics/debugging.md](topics/debugging.md). \ No newline at end of file
+**Table of contents**
+
+<!--- TOC -->
+
+* [Debugging coroutines](#debugging-coroutines)
+* [Debug mode](#debug-mode)
+* [Stacktrace recovery](#stacktrace-recovery)
+ * [Stacktrace recovery machinery](#stacktrace-recovery-machinery)
+* [Debug agent](#debug-agent)
+ * [Debug agent and Android](#debug-agent-and-android)
+* [Android optimization](#android-optimization)
+
+<!--- END -->
+
+## Debugging coroutines
+
+Debugging asynchronous programs is challenging, because multiple concurrent coroutines are typically working at the same time.
+To help with that, `kotlinx.coroutines` comes with additional features for debugging: debug mode, stacktrace recovery
+and debug agent.
+
+## Debug mode
+
+The first debugging feature of `kotlinx.coroutines` is debug mode.
+It can be enabled either by setting system property [DEBUG_PROPERTY_NAME] or by running Java with enabled assertions (`-ea` flag).
+The latter is helpful to have debug mode enabled by default in unit tests.
+
+Debug mode attaches a unique [name][CoroutineName] to every launched coroutine.
+Coroutine name can be seen in a regular Java debugger,
+in a string representation of the coroutine or in the thread name executing named coroutine.
+Overhead of this feature is negligible and it can be safely turned on by default to simplify logging and diagnostic.
+
+## Stacktrace recovery
+
+Stacktrace recovery is another useful feature of debug mode. It is enabled by default in the debug mode,
+but can be separately disabled by setting `kotlinx.coroutines.stacktrace.recovery` system property to `false`.
+
+Stacktrace recovery tries to stitch asynchronous exception stacktrace with a stacktrace of the receiver by copying it, providing
+not only information where an exception was thrown, but also where it was asynchronously rethrown or caught.
+
+It is easy to demonstrate with actual stacktraces of the same program that awaits asynchronous operation in `main` function
+(runnable code is [here](../kotlinx-coroutines-debug/test/RecoveryExample.kt)):
+
+| Without recovery | With recovery |
+| - | - |
+| ![before](images/before.png "before") | ![after](images/after.png "after") |
+
+The only downside of this approach is losing referential transparency of the exception.
+
+### Stacktrace recovery machinery
+
+This section explains the inner mechanism of stacktrace recovery and can be skipped.
+
+When an exception is rethrown between coroutines (e.g. through `withContext` or `Deferred.await` boundary), stacktrace recovery
+machinery tries to create a copy of the original exception (with the original exception as the cause), then rewrite stacktrace
+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-))
+and then throws the resulting exception instead of the original one.
+
+Exception copy logic is straightforward:
+ 1) If the exception class implements [CopyableThrowable], [CopyableThrowable.createCopy] is used.
+ `null` can be returned from `createCopy` to opt-out specific exception from being recovered.
+ 2) If the exception class has class-specific fields not inherited from Throwable, the exception is not copied.
+ 3) Otherwise, one of the public exception's constructor is invoked reflectively with an optional `initCause` call.
+
+## Debug agent
+
+[kotlinx-coroutines-debug](../kotlinx-coroutines-debug) module provides one of the most powerful debug capabilities in `kotlinx.coroutines`.
+
+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,
+additionally enhancing stacktraces with information where coroutine was created.
+
+The full tutorial of how to use debug agent can be found in the corresponding [readme](../kotlinx-coroutines-debug/README.md).
+
+### Debug agent and Android
+
+Unfortunately, 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;`.
+
+Nevertheless, 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
+
+<!---
+Make an exception googlable
+java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/ManagementFactory;
+ at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent$ProcessProvider$ForCurrentVm$ForLegacyVm.resolve(ByteBuddyAgent.java:1055)
+ at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent$ProcessProvider$ForCurrentVm.resolve(ByteBuddyAgent.java:1038)
+ at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:374)
+ at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:342)
+ at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:328)
+ at kotlinx.coroutines.debug.internal.DebugProbesImpl.install(DebugProbesImpl.kt:39)
+ at kotlinx.coroutines.debug.DebugProbes.install(DebugProbes.kt:49)
+-->
+
+## Android optimization
+
+In optimized (release) builds with R8 version 1.6.0 or later both
+[Debugging mode](../../docs/debugging.md#debug-mode) and
+[Stacktrace recovery](../../docs/debugging.md#stacktrace-recovery)
+are permanently turned off.
+For more details see ["Optimization" section for Android](../ui/kotlinx-coroutines-android/README.md#optimization).
+
+<!--- MODULE kotlinx-coroutines-core -->
+<!--- INDEX kotlinx.coroutines -->
+[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
+[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-name/index.html
+[CopyableThrowable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/index.html
+[CopyableThrowable.createCopy]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/create-copy.html
+<!--- MODULE kotlinx-coroutines-debug -->
+<!--- END -->
diff --git a/docs/exception-handling.md b/docs/exception-handling.md
index 77dbac98..a3070213 100644
--- a/docs/exception-handling.md
+++ b/docs/exception-handling.md
@@ -1,3 +1,526 @@
-The documentation has been moved to the [https://kotlinlang.org/docs/exception-handling.html](https://kotlinlang.org/docs/exception-handling.html) page.
+<!--- TEST_NAME ExceptionsGuideTest -->
-To edit the documentation, open the [topics/exception-handling.md](topics/exception-handling.md) page. \ No newline at end of file
+**Table of contents**
+
+<!--- TOC -->
+
+* [Exception Handling](#exception-handling)
+ * [Exception propagation](#exception-propagation)
+ * [CoroutineExceptionHandler](#coroutineexceptionhandler)
+ * [Cancellation and exceptions](#cancellation-and-exceptions)
+ * [Exceptions aggregation](#exceptions-aggregation)
+ * [Supervision](#supervision)
+ * [Supervision job](#supervision-job)
+ * [Supervision scope](#supervision-scope)
+ * [Exceptions in supervised coroutines](#exceptions-in-supervised-coroutines)
+
+<!--- END -->
+
+## Exception Handling
+
+This section covers exception handling and cancellation on exceptions.
+We already know that a cancelled coroutine throws [CancellationException] in suspension points and that it
+is ignored by the coroutines' machinery. Here we look at what happens if an exception is thrown during cancellation or multiple children of the same
+coroutine throw an exception.
+
+### Exception propagation
+
+Coroutine builders come in two flavors: propagating exceptions automatically ([launch] and [actor]) or
+exposing them to users ([async] and [produce]).
+When these builders are used to create a _root_ coroutine, that is not a _child_ of another coroutine,
+the former builders treat exceptions as **uncaught** exceptions, similar to Java's `Thread.uncaughtExceptionHandler`,
+while the latter are relying on the user to consume the final
+exception, for example via [await][Deferred.await] or [receive][ReceiveChannel.receive]
+([produce] and [receive][ReceiveChannel.receive] are covered later in [Channels](https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/channels.md) section).
+
+It can be demonstrated by a simple example that creates root coroutines using the [GlobalScope]:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+ val job = GlobalScope.launch { // root coroutine with launch
+ println("Throwing exception from launch")
+ throw IndexOutOfBoundsException() // Will be printed to the console by Thread.defaultUncaughtExceptionHandler
+ }
+ job.join()
+ println("Joined failed job")
+ val deferred = GlobalScope.async { // root coroutine with async
+ println("Throwing exception from async")
+ throw ArithmeticException() // Nothing is printed, relying on user to call await
+ }
+ try {
+ deferred.await()
+ println("Unreached")
+ } catch (e: ArithmeticException) {
+ println("Caught ArithmeticException")
+ }
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-01.kt).
+
+The output of this code is (with [debug](https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/coroutine-context-and-dispatchers.md#debugging-coroutines-and-threads)):
+
+```text
+Throwing exception from launch
+Exception in thread "DefaultDispatcher-worker-2 @coroutine#2" java.lang.IndexOutOfBoundsException
+Joined failed job
+Throwing exception from async
+Caught ArithmeticException
+```
+
+<!--- TEST EXCEPTION-->
+
+### CoroutineExceptionHandler
+
+It is possible to customize the default behavior of printing **uncaught** exceptions to the console.
+[CoroutineExceptionHandler] context element on a _root_ coroutine can be used as generic `catch` block for
+this root coroutine and all its children where custom exception handling may take place.
+It is similar to [`Thread.uncaughtExceptionHandler`](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler)).
+You cannot recover from the exception in the `CoroutineExceptionHandler`. The coroutine had already completed
+with the corresponding exception when the handler is called. Normally, the handler is used to
+log the exception, show some kind of error message, terminate, and/or restart the application.
+
+On JVM it is possible to redefine global exception handler for all coroutines by registering [CoroutineExceptionHandler] via
+[`ServiceLoader`](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html).
+Global exception handler is similar to
+[`Thread.defaultUncaughtExceptionHandler`](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler))
+which is used when no more specific handlers are registered.
+On Android, `uncaughtExceptionPreHandler` is installed as a global coroutine exception handler.
+
+`CoroutineExceptionHandler` is invoked only on **uncaught** exceptions &mdash; exceptions that were not handled in any other way.
+In particular, all _children_ coroutines (coroutines created in the context of another [Job]) delegate handling of
+their exceptions to their parent coroutine, which also delegates to the parent, and so on until the root,
+so the `CoroutineExceptionHandler` installed in their context is never used.
+In addition to that, [async] builder always catches all exceptions and represents them in the resulting [Deferred] object,
+so its `CoroutineExceptionHandler` has no effect either.
+
+> Coroutines running in supervision scope do not propagate exceptions to their parent and are
+excluded from this rule. A further [Supervision](#supervision) section of this document gives more details.
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+//sampleStart
+ val handler = CoroutineExceptionHandler { _, exception ->
+ println("CoroutineExceptionHandler got $exception")
+ }
+ val job = GlobalScope.launch(handler) { // root coroutine, running in GlobalScope
+ throw AssertionError()
+ }
+ val deferred = GlobalScope.async(handler) { // also root, but async instead of launch
+ throw ArithmeticException() // Nothing will be printed, relying on user to call deferred.await()
+ }
+ joinAll(job, deferred)
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-02.kt).
+
+The output of this code is:
+
+```text
+CoroutineExceptionHandler got java.lang.AssertionError
+```
+
+<!--- TEST-->
+
+### Cancellation and exceptions
+
+Cancellation is closely related to exceptions. Coroutines internally use `CancellationException` for cancellation, these
+exceptions are ignored by all handlers, so they should be used only as the source of additional debug information, which can
+be obtained by `catch` block.
+When a coroutine is cancelled using [Job.cancel], it terminates, but it does not cancel its parent.
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+//sampleStart
+ val job = launch {
+ val child = launch {
+ try {
+ delay(Long.MAX_VALUE)
+ } finally {
+ println("Child is cancelled")
+ }
+ }
+ yield()
+ println("Cancelling child")
+ child.cancel()
+ child.join()
+ yield()
+ println("Parent is not cancelled")
+ }
+ job.join()
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-03.kt).
+
+The output of this code is:
+
+```text
+Cancelling child
+Child is cancelled
+Parent is not cancelled
+```
+
+<!--- TEST-->
+
+If a coroutine encounters an exception other than `CancellationException`, it cancels its parent with that exception.
+This behaviour cannot be overridden and is used to provide stable coroutines hierarchies for
+[structured concurrency](https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/composing-suspending-functions.md#structured-concurrency-with-async).
+[CoroutineExceptionHandler] implementation is not used for child coroutines.
+
+> In these examples [CoroutineExceptionHandler] is always installed to a coroutine
+that is created in [GlobalScope]. It does not make sense to install an exception handler to a coroutine that
+is launched in the scope of the main [runBlocking], since the main coroutine is going to be always cancelled
+when its child completes with exception despite the installed handler.
+
+The original exception is handled by the parent only when all its children terminate,
+which is demonstrated by the following example.
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+//sampleStart
+ val handler = CoroutineExceptionHandler { _, exception ->
+ println("CoroutineExceptionHandler got $exception")
+ }
+ val job = GlobalScope.launch(handler) {
+ launch { // the first child
+ try {
+ delay(Long.MAX_VALUE)
+ } finally {
+ withContext(NonCancellable) {
+ println("Children are cancelled, but exception is not handled until all children terminate")
+ delay(100)
+ println("The first child finished its non cancellable block")
+ }
+ }
+ }
+ launch { // the second child
+ delay(10)
+ println("Second child throws an exception")
+ throw ArithmeticException()
+ }
+ }
+ job.join()
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-04.kt).
+
+The output of this code is:
+
+```text
+Second child throws an exception
+Children are cancelled, but exception is not handled until all children terminate
+The first child finished its non cancellable block
+CoroutineExceptionHandler got java.lang.ArithmeticException
+```
+<!--- TEST-->
+
+### Exceptions aggregation
+
+When multiple children of a coroutine fail with an exception, the
+general rule is "the first exception wins", so the first exception gets handled.
+All additional exceptions that happen after the first one are attached to the first exception as suppressed ones.
+
+<!--- INCLUDE
+import kotlinx.coroutines.exceptions.*
+-->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import java.io.*
+
+fun main() = runBlocking {
+ val handler = CoroutineExceptionHandler { _, exception ->
+ println("CoroutineExceptionHandler got $exception with suppressed ${exception.suppressed.contentToString()}")
+ }
+ val job = GlobalScope.launch(handler) {
+ launch {
+ try {
+ delay(Long.MAX_VALUE) // it gets cancelled when another sibling fails with IOException
+ } finally {
+ throw ArithmeticException() // the second exception
+ }
+ }
+ launch {
+ delay(100)
+ throw IOException() // the first exception
+ }
+ delay(Long.MAX_VALUE)
+ }
+ job.join()
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-05.kt).
+
+> Note: This above code will work properly only on JDK7+ that supports `suppressed` exceptions
+
+The output of this code is:
+
+```text
+CoroutineExceptionHandler got java.io.IOException with suppressed [java.lang.ArithmeticException]
+```
+
+<!--- TEST-->
+
+> Note that this mechanism currently only works on Java version 1.7+.
+The JS and Native restrictions are temporary and will be lifted in the future.
+
+Cancellation exceptions are transparent and are unwrapped by default:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import java.io.*
+
+fun main() = runBlocking {
+//sampleStart
+ val handler = CoroutineExceptionHandler { _, exception ->
+ println("CoroutineExceptionHandler got $exception")
+ }
+ val job = GlobalScope.launch(handler) {
+ val inner = launch { // all this stack of coroutines will get cancelled
+ launch {
+ launch {
+ throw IOException() // the original exception
+ }
+ }
+ }
+ try {
+ inner.join()
+ } catch (e: CancellationException) {
+ println("Rethrowing CancellationException with original cause")
+ throw e // cancellation exception is rethrown, yet the original IOException gets to the handler
+ }
+ }
+ job.join()
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-06.kt).
+
+The output of this code is:
+
+```text
+Rethrowing CancellationException with original cause
+CoroutineExceptionHandler got java.io.IOException
+```
+<!--- TEST-->
+
+### Supervision
+
+As we have studied before, cancellation is a bidirectional relationship propagating through the whole
+hierarchy of coroutines. Let us take a look at the case when unidirectional cancellation is required.
+
+A good example of such a requirement is a UI component with the job defined in its scope. If any of the UI's child tasks
+have failed, it is not always necessary to cancel (effectively kill) the whole UI component,
+but if UI component is destroyed (and its job is cancelled), then it is necessary to fail all child jobs as their results are no longer needed.
+
+Another example is a server process that spawns multiple child jobs and needs to _supervise_
+their execution, tracking their failures and only restarting the failed ones.
+
+#### Supervision job
+
+The [SupervisorJob][SupervisorJob()] can be used for these purposes.
+It is similar to a regular [Job][Job()] with the only exception that cancellation is propagated
+only downwards. This can easily be demonstrated using the following example:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+ val supervisor = SupervisorJob()
+ with(CoroutineScope(coroutineContext + supervisor)) {
+ // launch the first child -- its exception is ignored for this example (don't do this in practice!)
+ val firstChild = launch(CoroutineExceptionHandler { _, _ -> }) {
+ println("The first child is failing")
+ throw AssertionError("The first child is cancelled")
+ }
+ // launch the second child
+ val secondChild = launch {
+ firstChild.join()
+ // Cancellation of the first child is not propagated to the second child
+ println("The first child is cancelled: ${firstChild.isCancelled}, but the second one is still active")
+ try {
+ delay(Long.MAX_VALUE)
+ } finally {
+ // But cancellation of the supervisor is propagated
+ println("The second child is cancelled because the supervisor was cancelled")
+ }
+ }
+ // wait until the first child fails & completes
+ firstChild.join()
+ println("Cancelling the supervisor")
+ supervisor.cancel()
+ secondChild.join()
+ }
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-supervision-01.kt).
+
+The output of this code is:
+
+```text
+The first child is failing
+The first child is cancelled: true, but the second one is still active
+Cancelling the supervisor
+The second child is cancelled because the supervisor was cancelled
+```
+<!--- TEST-->
+
+
+#### Supervision scope
+
+Instead of [coroutineScope][_coroutineScope], we can use [supervisorScope][_supervisorScope] for _scoped_ concurrency. It propagates the cancellation
+in one direction only and cancels all its children only if it failed itself. It also waits for all children before completion
+just like [coroutineScope][_coroutineScope] does.
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+import kotlin.coroutines.*
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+ try {
+ supervisorScope {
+ val child = launch {
+ try {
+ println("The child is sleeping")
+ delay(Long.MAX_VALUE)
+ } finally {
+ println("The child is cancelled")
+ }
+ }
+ // Give our child a chance to execute and print using yield
+ yield()
+ println("Throwing an exception from the scope")
+ throw AssertionError()
+ }
+ } catch(e: AssertionError) {
+ println("Caught an assertion error")
+ }
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-supervision-02.kt).
+
+The output of this code is:
+
+```text
+The child is sleeping
+Throwing an exception from the scope
+The child is cancelled
+Caught an assertion error
+```
+<!--- TEST-->
+
+#### Exceptions in supervised coroutines
+
+Another crucial difference between regular and supervisor jobs is exception handling.
+Every child should handle its exceptions by itself via the exception handling mechanism.
+This difference comes from the fact that child's failure does not propagate to the parent.
+It means that coroutines launched directly inside the [supervisorScope][_supervisorScope] _do_ use the [CoroutineExceptionHandler]
+that is installed in their scope in the same way as root coroutines do
+(see the [CoroutineExceptionHandler](#coroutineexceptionhandler) section for details).
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+import kotlin.coroutines.*
+import kotlinx.coroutines.*
+
+fun main() = runBlocking {
+ val handler = CoroutineExceptionHandler { _, exception ->
+ println("CoroutineExceptionHandler got $exception")
+ }
+ supervisorScope {
+ val child = launch(handler) {
+ println("The child throws an exception")
+ throw AssertionError()
+ }
+ println("The scope is completing")
+ }
+ println("The scope is completed")
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-supervision-03.kt).
+
+The output of this code is:
+
+```text
+The scope is completing
+The child throws an exception
+CoroutineExceptionHandler got java.lang.AssertionError
+The scope is completed
+```
+<!--- TEST-->
+
+<!--- MODULE kotlinx-coroutines-core -->
+<!--- INDEX kotlinx.coroutines -->
+[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html
+[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
+[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
+[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/await.html
+[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
+[CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-exception-handler/index.html
+[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
+[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html
+[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html
+[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
+[SupervisorJob()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-supervisor-job.html
+[Job()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job.html
+[_coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
+[_supervisorScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/supervisor-scope.html
+<!--- INDEX kotlinx.coroutines.channels -->
+[actor]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/actor.html
+[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/produce.html
+[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive.html
+<!--- END -->
diff --git a/docs/flow.md b/docs/flow.md
index 400a15f1..4374e7aa 100644
--- a/docs/flow.md
+++ b/docs/flow.md
@@ -1,3 +1,1979 @@
-The documentation has been moved to the [https://kotlinlang.org/docs/flow.html](https://kotlinlang.org/docs/flow.html) page.
+<!--- TEST_NAME FlowGuideTest -->
-To edit the documentation, open the [topics/flow.md](topics/flow.md) page. \ No newline at end of file
+**Table of contents**
+
+<!--- TOC -->
+
+* [Asynchronous Flow](#asynchronous-flow)
+ * [Representing multiple values](#representing-multiple-values)
+ * [Sequences](#sequences)
+ * [Suspending functions](#suspending-functions)
+ * [Flows](#flows)
+ * [Flows are cold](#flows-are-cold)
+ * [Flow cancellation basics](#flow-cancellation-basics)
+ * [Flow builders](#flow-builders)
+ * [Intermediate flow operators](#intermediate-flow-operators)
+ * [Transform operator](#transform-operator)
+ * [Size-limiting operators](#size-limiting-operators)
+ * [Terminal flow operators](#terminal-flow-operators)
+ * [Flows are sequential](#flows-are-sequential)
+ * [Flow context](#flow-context)
+ * [Wrong emission withContext](#wrong-emission-withcontext)
+ * [flowOn operator](#flowon-operator)
+ * [Buffering](#buffering)
+ * [Conflation](#conflation)
+ * [Processing the latest value](#processing-the-latest-value)
+ * [Composing multiple flows](#composing-multiple-flows)
+ * [Zip](#zip)
+ * [Combine](#combine)
+ * [Flattening flows](#flattening-flows)
+ * [flatMapConcat](#flatmapconcat)
+ * [flatMapMerge](#flatmapmerge)
+ * [flatMapLatest](#flatmaplatest)
+ * [Flow exceptions](#flow-exceptions)
+ * [Collector try and catch](#collector-try-and-catch)
+ * [Everything is caught](#everything-is-caught)
+ * [Exception transparency](#exception-transparency)
+ * [Transparent catch](#transparent-catch)
+ * [Catching declaratively](#catching-declaratively)
+ * [Flow completion](#flow-completion)
+ * [Imperative finally block](#imperative-finally-block)
+ * [Declarative handling](#declarative-handling)
+ * [Successful completion](#successful-completion)
+ * [Imperative versus declarative](#imperative-versus-declarative)
+ * [Launching flow](#launching-flow)
+ * [Flow cancellation checks](#flow-cancellation-checks)
+ * [Making busy flow cancellable](#making-busy-flow-cancellable)
+ * [Flow and Reactive Streams](#flow-and-reactive-streams)
+
+<!--- END -->
+
+## Asynchronous Flow
+
+A suspending function asynchronously returns a single value, but how can we return
+multiple asynchronously computed values? This is where Kotlin Flows come in.
+
+### Representing multiple values
+
+Multiple values can be represented in Kotlin using [collections].
+For example, we can have a `simple` function that returns a [List]
+of three numbers and then print them all using [forEach]:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+fun simple(): List<Int> = listOf(1, 2, 3)
+
+fun main() {
+ simple().forEach { value -> println(value) }
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-01.kt).
+
+This code outputs:
+
+```text
+1
+2
+3
+```
+
+<!--- TEST -->
+
+#### Sequences
+
+If we are computing the numbers with some CPU-consuming blocking code
+(each computation taking 100ms), then we can represent the numbers using a [Sequence]:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+fun simple(): Sequence<Int> = sequence { // sequence builder
+ for (i in 1..3) {
+ Thread.sleep(100) // pretend we are computing it
+ yield(i) // yield next value
+ }
+}
+
+fun main() {
+ simple().forEach { value -> println(value) }
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-02.kt).
+
+This code outputs the same numbers, but it waits 100ms before printing each one.
+
+<!--- TEST
+1
+2
+3
+-->
+
+#### Suspending functions
+
+However, this computation blocks the main thread that is running the code.
+When these values are computed by asynchronous code we can mark the `simple` function with a `suspend` modifier,
+so that it can perform its work without blocking and return the result as a list:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+
+//sampleStart
+suspend fun simple(): List<Int> {
+ delay(1000) // pretend we are doing something asynchronous here
+ return listOf(1, 2, 3)
+}
+
+fun main() = runBlocking<Unit> {
+ simple().forEach { value -> println(value) }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-03.kt).
+
+This code prints the numbers after waiting for a second.
+
+<!--- TEST
+1
+2
+3
+-->
+
+#### Flows
+
+Using the `List<Int>` result type, means we can only return all the values at once. To represent
+the stream of values that are being asynchronously computed, we can use a [`Flow<Int>`][Flow] type just like we would use the `Sequence<Int>` type for synchronously computed values:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun simple(): Flow<Int> = flow { // flow builder
+ for (i in 1..3) {
+ delay(100) // pretend we are doing something useful here
+ emit(i) // emit next value
+ }
+}
+
+fun main() = runBlocking<Unit> {
+ // Launch a concurrent coroutine to check if the main thread is blocked
+ launch {
+ for (k in 1..3) {
+ println("I'm not blocked $k")
+ delay(100)
+ }
+ }
+ // Collect the flow
+ simple().collect { value -> println(value) }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-04.kt).
+
+This code waits 100ms before printing each number without blocking the main thread. This is verified
+by printing "I'm not blocked" every 100ms from a separate coroutine that is running in the main thread:
+
+```text
+I'm not blocked 1
+1
+I'm not blocked 2
+2
+I'm not blocked 3
+3
+```
+
+<!--- TEST -->
+
+Notice the following differences in the code with the [Flow] from the earlier examples:
+
+* A builder function for [Flow] type is called [flow][_flow].
+* Code inside the `flow { ... }` builder block can suspend.
+* The `simple` function is no longer marked with `suspend` modifier.
+* Values are _emitted_ from the flow using [emit][FlowCollector.emit] function.
+* Values are _collected_ from the flow using [collect][collect] function.
+
+> We can replace [delay] with `Thread.sleep` in the body of `simple`'s `flow { ... }` and see that the main
+thread is blocked in this case.
+
+### Flows are cold
+
+Flows are _cold_ streams similar to sequences &mdash; the code inside a [flow][_flow] builder does not
+run until the flow is collected. This becomes clear in the following example:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun simple(): Flow<Int> = flow {
+ println("Flow started")
+ for (i in 1..3) {
+ delay(100)
+ emit(i)
+ }
+}
+
+fun main() = runBlocking<Unit> {
+ println("Calling simple function...")
+ val flow = simple()
+ println("Calling collect...")
+ flow.collect { value -> println(value) }
+ println("Calling collect again...")
+ flow.collect { value -> println(value) }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-05.kt).
+
+Which prints:
+
+```text
+Calling simple function...
+Calling collect...
+Flow started
+1
+2
+3
+Calling collect again...
+Flow started
+1
+2
+3
+```
+
+<!--- TEST -->
+
+This is a key reason the `simple` function (which returns a flow) is not marked with `suspend` modifier.
+By itself, `simple()` call returns quickly and does not wait for anything. The flow starts every time it is collected,
+that is why we see "Flow started" when we call `collect` again.
+
+### Flow cancellation basics
+
+Flow adheres to the general cooperative cancellation of coroutines. As usual, flow collection can be
+cancelled when the flow is suspended in a cancellable suspending function (like [delay]).
+The following example shows how the flow gets cancelled on a timeout when running in a [withTimeoutOrNull] block
+and stops executing its code:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun simple(): Flow<Int> = flow {
+ for (i in 1..3) {
+ delay(100)
+ println("Emitting $i")
+ emit(i)
+ }
+}
+
+fun main() = runBlocking<Unit> {
+ withTimeoutOrNull(250) { // Timeout after 250ms
+ simple().collect { value -> println(value) }
+ }
+ println("Done")
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-06.kt).
+
+Notice how only two numbers get emitted by the flow in the `simple` function, producing the following output:
+
+```text
+Emitting 1
+1
+Emitting 2
+2
+Done
+```
+
+<!--- TEST -->
+
+See [Flow cancellation checks](#flow-cancellation-checks) section for more details.
+
+### Flow builders
+
+The `flow { ... }` builder from the previous examples is the most basic one. There are other builders for
+easier declaration of flows:
+
+* [flowOf] builder that defines a flow emitting a fixed set of values.
+* Various collections and sequences can be converted to flows using `.asFlow()` extension functions.
+
+So, the example that prints the numbers from 1 to 3 from a flow can be written as:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ // Convert an integer range to a flow
+ (1..3).asFlow().collect { value -> println(value) }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-07.kt).
+
+<!--- TEST
+1
+2
+3
+-->
+
+### Intermediate flow operators
+
+Flows can be transformed with operators, just as you would with collections and sequences.
+Intermediate operators are applied to an upstream flow and return a downstream flow.
+These operators are cold, just like flows are. A call to such an operator is not
+a suspending function itself. It works quickly, returning the definition of a new transformed flow.
+
+The basic operators have familiar names like [map] and [filter].
+The important difference to sequences is that blocks of
+code inside these operators can call suspending functions.
+
+For example, a flow of incoming requests can be
+mapped to the results with the [map] operator, even when performing a request is a long-running
+operation that is implemented by a suspending function:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+suspend fun performRequest(request: Int): String {
+ delay(1000) // imitate long-running asynchronous work
+ return "response $request"
+}
+
+fun main() = runBlocking<Unit> {
+ (1..3).asFlow() // a flow of requests
+ .map { request -> performRequest(request) }
+ .collect { response -> println(response) }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-08.kt).
+
+It produces the following three lines, each line appearing after each second:
+
+```text
+response 1
+response 2
+response 3
+```
+
+<!--- TEST -->
+
+#### Transform operator
+
+Among the flow transformation operators, the most general one is called [transform]. It can be used to imitate
+simple transformations like [map] and [filter], as well as implement more complex transformations.
+Using the `transform` operator, we can [emit][FlowCollector.emit] arbitrary values an arbitrary number of times.
+
+For example, using `transform` we can emit a string before performing a long-running asynchronous request
+and follow it with a response:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+suspend fun performRequest(request: Int): String {
+ delay(1000) // imitate long-running asynchronous work
+ return "response $request"
+}
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ (1..3).asFlow() // a flow of requests
+ .transform { request ->
+ emit("Making request $request")
+ emit(performRequest(request))
+ }
+ .collect { response -> println(response) }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-09.kt).
+
+The output of this code is:
+
+```text
+Making request 1
+response 1
+Making request 2
+response 2
+Making request 3
+response 3
+```
+
+<!--- TEST -->
+
+#### Size-limiting operators
+
+Size-limiting intermediate operators like [take] cancel the execution of the flow when the corresponding limit
+is reached. Cancellation in coroutines is always performed by throwing an exception, so that all the resource-management
+functions (like `try { ... } finally { ... }` blocks) operate normally in case of cancellation:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun numbers(): Flow<Int> = flow {
+ try {
+ emit(1)
+ emit(2)
+ println("This line will not execute")
+ emit(3)
+ } finally {
+ println("Finally in numbers")
+ }
+}
+
+fun main() = runBlocking<Unit> {
+ numbers()
+ .take(2) // take only the first two
+ .collect { value -> println(value) }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-10.kt).
+
+The output of this code clearly shows that the execution of the `flow { ... }` body in the `numbers()` function
+stopped after emitting the second number:
+
+```text
+1
+2
+Finally in numbers
+```
+
+<!--- TEST -->
+
+### Terminal flow operators
+
+Terminal operators on flows are _suspending functions_ that start a collection of the flow.
+The [collect] operator is the most basic one, but there are other terminal operators, which can make it easier:
+
+* Conversion to various collections like [toList] and [toSet].
+* Operators to get the [first] value and to ensure that a flow emits a [single] value.
+* Reducing a flow to a value with [reduce] and [fold].
+
+For example:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val sum = (1..5).asFlow()
+ .map { it * it } // squares of numbers from 1 to 5
+ .reduce { a, b -> a + b } // sum them (terminal operator)
+ println(sum)
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-11.kt).
+
+Prints a single number:
+
+```text
+55
+```
+
+<!--- TEST -->
+
+### Flows are sequential
+
+Each individual collection of a flow is performed sequentially unless special operators that operate
+on multiple flows are used. The collection works directly in the coroutine that calls a terminal operator.
+No new coroutines are launched by default.
+Each emitted value is processed by all the intermediate operators from
+upstream to downstream and is then delivered to the terminal operator after.
+
+See the following example that filters the even integers and maps them to strings:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ (1..5).asFlow()
+ .filter {
+ println("Filter $it")
+ it % 2 == 0
+ }
+ .map {
+ println("Map $it")
+ "string $it"
+ }.collect {
+ println("Collect $it")
+ }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-12.kt).
+
+Producing:
+
+```text
+Filter 1
+Filter 2
+Map 2
+Collect string 2
+Filter 3
+Filter 4
+Map 4
+Collect string 4
+Filter 5
+```
+
+<!--- TEST -->
+
+### Flow context
+
+Collection of a flow always happens in the context of the calling coroutine. For example, if there is
+a `simple` flow, then the following code runs in the context specified
+by the author of this code, regardless of the implementation details of the `simple` flow:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+withContext(context) {
+ simple().collect { value ->
+ println(value) // run in the specified context
+ }
+}
+```
+
+</div>
+
+<!--- CLEAR -->
+
+This property of a flow is called _context preservation_.
+
+So, by default, code in the `flow { ... }` builder runs in the context that is provided by a collector
+of the corresponding flow. For example, consider the implementation of a `simple` function that prints the thread
+it is called on and emits three numbers:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
+
+//sampleStart
+fun simple(): Flow<Int> = flow {
+ log("Started simple flow")
+ for (i in 1..3) {
+ emit(i)
+ }
+}
+
+fun main() = runBlocking<Unit> {
+ simple().collect { value -> log("Collected $value") }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-13.kt).
+
+Running this code produces:
+
+```text
+[main @coroutine#1] Started simple flow
+[main @coroutine#1] Collected 1
+[main @coroutine#1] Collected 2
+[main @coroutine#1] Collected 3
+```
+
+<!--- TEST FLEXIBLE_THREAD -->
+
+Since `simple().collect` is called from the main thread, the body of `simple`'s flow is also called in the main thread.
+This is the perfect default for fast-running or asynchronous code that does not care about the execution context and
+does not block the caller.
+
+#### Wrong emission withContext
+
+However, the long-running CPU-consuming code might need to be executed in the context of [Dispatchers.Default] and UI-updating
+code might need to be executed in the context of [Dispatchers.Main]. Usually, [withContext] is used
+to change the context in the code using Kotlin coroutines, but code in the `flow { ... }` builder has to honor the context
+preservation property and is not allowed to [emit][FlowCollector.emit] from a different context.
+
+Try running the following code:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun simple(): Flow<Int> = flow {
+ // The WRONG way to change context for CPU-consuming code in flow builder
+ kotlinx.coroutines.withContext(Dispatchers.Default) {
+ for (i in 1..3) {
+ Thread.sleep(100) // pretend we are computing it in CPU-consuming way
+ emit(i) // emit next value
+ }
+ }
+}
+
+fun main() = runBlocking<Unit> {
+ simple().collect { value -> println(value) }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-14.kt).
+
+This code produces the following exception:
+
+```text
+Exception in thread "main" java.lang.IllegalStateException: Flow invariant is violated:
+ Flow was collected in [CoroutineId(1), "coroutine#1":BlockingCoroutine{Active}@5511c7f8, BlockingEventLoop@2eac3323],
+ but emission happened in [CoroutineId(1), "coroutine#1":DispatchedCoroutine{Active}@2dae0000, Dispatchers.Default].
+ Please refer to 'flow' documentation or use 'flowOn' instead
+ at ...
+```
+
+<!--- TEST EXCEPTION -->
+
+#### flowOn operator
+
+The exception refers to the [flowOn] function that shall be used to change the context of the flow emission.
+The correct way to change the context of a flow is shown in the example below, which also prints the
+names of the corresponding threads to show how it all works:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
+
+//sampleStart
+fun simple(): Flow<Int> = flow {
+ for (i in 1..3) {
+ Thread.sleep(100) // pretend we are computing it in CPU-consuming way
+ log("Emitting $i")
+ emit(i) // emit next value
+ }
+}.flowOn(Dispatchers.Default) // RIGHT way to change context for CPU-consuming code in flow builder
+
+fun main() = runBlocking<Unit> {
+ simple().collect { value ->
+ log("Collected $value")
+ }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-15.kt).
+
+Notice how `flow { ... }` works in the background thread, while collection happens in the main thread:
+
+<!--- TEST FLEXIBLE_THREAD
+[DefaultDispatcher-worker-1 @coroutine#2] Emitting 1
+[main @coroutine#1] Collected 1
+[DefaultDispatcher-worker-1 @coroutine#2] Emitting 2
+[main @coroutine#1] Collected 2
+[DefaultDispatcher-worker-1 @coroutine#2] Emitting 3
+[main @coroutine#1] Collected 3
+-->
+
+Another thing to observe here is that the [flowOn] operator has changed the default sequential nature of the flow.
+Now collection happens in one coroutine ("coroutine#1") and emission happens in another coroutine
+("coroutine#2") that is running in another thread concurrently with the collecting coroutine. The [flowOn] operator
+creates another coroutine for an upstream flow when it has to change the [CoroutineDispatcher] in its context.
+
+### Buffering
+
+Running different parts of a flow in different coroutines can be helpful from the standpoint of the overall time it takes
+to collect the flow, especially when long-running asynchronous operations are involved. For example, consider a case when
+the emission by a `simple` flow is slow, taking 100 ms to produce an element; and collector is also slow,
+taking 300 ms to process an element. Let's see how long it takes to collect such a flow with three numbers:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+import kotlin.system.*
+
+//sampleStart
+fun simple(): Flow<Int> = flow {
+ for (i in 1..3) {
+ delay(100) // pretend we are asynchronously waiting 100 ms
+ emit(i) // emit next value
+ }
+}
+
+fun main() = runBlocking<Unit> {
+ val time = measureTimeMillis {
+ simple().collect { value ->
+ delay(300) // pretend we are processing it for 300 ms
+ println(value)
+ }
+ }
+ println("Collected in $time ms")
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-16.kt).
+
+It produces something like this, with the whole collection taking around 1200 ms (three numbers, 400 ms for each):
+
+```text
+1
+2
+3
+Collected in 1220 ms
+```
+
+<!--- TEST ARBITRARY_TIME -->
+
+We can use a [buffer] operator on a flow to run emitting code of the `simple` flow concurrently with collecting code,
+as opposed to running them sequentially:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+import kotlin.system.*
+
+fun simple(): Flow<Int> = flow {
+ for (i in 1..3) {
+ delay(100) // pretend we are asynchronously waiting 100 ms
+ emit(i) // emit next value
+ }
+}
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val time = measureTimeMillis {
+ simple()
+ .buffer() // buffer emissions, don't wait
+ .collect { value ->
+ delay(300) // pretend we are processing it for 300 ms
+ println(value)
+ }
+ }
+ println("Collected in $time ms")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-17.kt).
+
+It produces the same numbers just faster, as we have effectively created a processing pipeline,
+having to only wait 100 ms for the first number and then spending only 300 ms to process
+each number. This way it takes around 1000 ms to run:
+
+```text
+1
+2
+3
+Collected in 1071 ms
+```
+
+<!--- TEST ARBITRARY_TIME -->
+
+> Note that the [flowOn] operator uses the same buffering mechanism when it has to change a [CoroutineDispatcher],
+but here we explicitly request buffering without changing the execution context.
+
+#### Conflation
+
+When a flow represents partial results of the operation or operation status updates, it may not be necessary
+to process each value, but instead, only most recent ones. In this case, the [conflate] operator can be used to skip
+intermediate values when a collector is too slow to process them. Building on the previous example:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+import kotlin.system.*
+
+fun simple(): Flow<Int> = flow {
+ for (i in 1..3) {
+ delay(100) // pretend we are asynchronously waiting 100 ms
+ emit(i) // emit next value
+ }
+}
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val time = measureTimeMillis {
+ simple()
+ .conflate() // conflate emissions, don't process each one
+ .collect { value ->
+ delay(300) // pretend we are processing it for 300 ms
+ println(value)
+ }
+ }
+ println("Collected in $time ms")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-18.kt).
+
+We see that while the first number was still being processed the second, and third were already produced, so
+the second one was _conflated_ and only the most recent (the third one) was delivered to the collector:
+
+```text
+1
+3
+Collected in 758 ms
+```
+
+<!--- TEST ARBITRARY_TIME -->
+
+#### Processing the latest value
+
+Conflation is one way to speed up processing when both the emitter and collector are slow. It does it by dropping emitted values.
+The other way is to cancel a slow collector and restart it every time a new value is emitted. There is
+a family of `xxxLatest` operators that perform the same essential logic of a `xxx` operator, but cancel the
+code in their block on a new value. Let's try changing [conflate] to [collectLatest] in the previous example:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+import kotlin.system.*
+
+fun simple(): Flow<Int> = flow {
+ for (i in 1..3) {
+ delay(100) // pretend we are asynchronously waiting 100 ms
+ emit(i) // emit next value
+ }
+}
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val time = measureTimeMillis {
+ simple()
+ .collectLatest { value -> // cancel & restart on the latest value
+ println("Collecting $value")
+ delay(300) // pretend we are processing it for 300 ms
+ println("Done $value")
+ }
+ }
+ println("Collected in $time ms")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-19.kt).
+
+Since the body of [collectLatest] takes 300 ms, but new values are emitted every 100 ms, we see that the block
+is run on every value, but completes only for the last value:
+
+```text
+Collecting 1
+Collecting 2
+Collecting 3
+Done 3
+Collected in 741 ms
+```
+
+<!--- TEST ARBITRARY_TIME -->
+
+### Composing multiple flows
+
+There are lots of ways to compose multiple flows.
+
+#### Zip
+
+Just like the [Sequence.zip] extension function in the Kotlin standard library,
+flows have a [zip] operator that combines the corresponding values of two flows:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val nums = (1..3).asFlow() // numbers 1..3
+ val strs = flowOf("one", "two", "three") // strings
+ nums.zip(strs) { a, b -> "$a -> $b" } // compose a single string
+ .collect { println(it) } // collect and print
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-20.kt).
+
+This example prints:
+
+```text
+1 -> one
+2 -> two
+3 -> three
+```
+
+<!--- TEST -->
+
+#### Combine
+
+When flow represents the most recent value of a variable or operation (see also the related
+section on [conflation](#conflation)), it might be needed to perform a computation that depends on
+the most recent values of the corresponding flows and to recompute it whenever any of the upstream
+flows emit a value. The corresponding family of operators is called [combine].
+
+For example, if the numbers in the previous example update every 300ms, but strings update every 400 ms,
+then zipping them using the [zip] operator will still produce the same result,
+albeit results that are printed every 400 ms:
+
+> We use a [onEach] intermediate operator in this example to delay each element and make the code
+that emits sample flows more declarative and shorter.
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val nums = (1..3).asFlow().onEach { delay(300) } // numbers 1..3 every 300 ms
+ val strs = flowOf("one", "two", "three").onEach { delay(400) } // strings every 400 ms
+ val startTime = System.currentTimeMillis() // remember the start time
+ nums.zip(strs) { a, b -> "$a -> $b" } // compose a single string with "zip"
+ .collect { value -> // collect and print
+ println("$value at ${System.currentTimeMillis() - startTime} ms from start")
+ }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-21.kt).
+
+<!--- TEST ARBITRARY_TIME
+1 -> one at 437 ms from start
+2 -> two at 837 ms from start
+3 -> three at 1243 ms from start
+-->
+
+However, when using a [combine] operator here instead of a [zip]:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val nums = (1..3).asFlow().onEach { delay(300) } // numbers 1..3 every 300 ms
+ val strs = flowOf("one", "two", "three").onEach { delay(400) } // strings every 400 ms
+ val startTime = System.currentTimeMillis() // remember the start time
+ nums.combine(strs) { a, b -> "$a -> $b" } // compose a single string with "combine"
+ .collect { value -> // collect and print
+ println("$value at ${System.currentTimeMillis() - startTime} ms from start")
+ }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-22.kt).
+
+We get quite a different output, where a line is printed at each emission from either `nums` or `strs` flows:
+
+```text
+1 -> one at 452 ms from start
+2 -> one at 651 ms from start
+2 -> two at 854 ms from start
+3 -> two at 952 ms from start
+3 -> three at 1256 ms from start
+```
+
+<!--- TEST ARBITRARY_TIME -->
+
+### Flattening flows
+
+Flows represent asynchronously received sequences of values, so it is quite easy to get in a situation where
+each value triggers a request for another sequence of values. For example, we can have the following
+function that returns a flow of two strings 500 ms apart:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun requestFlow(i: Int): Flow<String> = flow {
+ emit("$i: First")
+ delay(500) // wait 500 ms
+ emit("$i: Second")
+}
+```
+
+</div>
+
+<!--- CLEAR -->
+
+Now if we have a flow of three integers and call `requestFlow` for each of them like this:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+(1..3).asFlow().map { requestFlow(it) }
+```
+
+</div>
+
+<!--- CLEAR -->
+
+Then we end up with a flow of flows (`Flow<Flow<String>>`) that needs to be _flattened_ into a single flow for
+further processing. Collections and sequences have [flatten][Sequence.flatten] and [flatMap][Sequence.flatMap]
+operators for this. However, due to the asynchronous nature of flows they call for different _modes_ of flattening,
+as such, there is a family of flattening operators on flows.
+
+#### flatMapConcat
+
+Concatenating mode is implemented by [flatMapConcat] and [flattenConcat] operators. They are the most direct
+analogues of the corresponding sequence operators. They wait for the inner flow to complete before
+starting to collect the next one as the following example shows:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun requestFlow(i: Int): Flow<String> = flow {
+ emit("$i: First")
+ delay(500) // wait 500 ms
+ emit("$i: Second")
+}
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val startTime = System.currentTimeMillis() // remember the start time
+ (1..3).asFlow().onEach { delay(100) } // a number every 100 ms
+ .flatMapConcat { requestFlow(it) }
+ .collect { value -> // collect and print
+ println("$value at ${System.currentTimeMillis() - startTime} ms from start")
+ }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-23.kt).
+
+The sequential nature of [flatMapConcat] is clearly seen in the output:
+
+```text
+1: First at 121 ms from start
+1: Second at 622 ms from start
+2: First at 727 ms from start
+2: Second at 1227 ms from start
+3: First at 1328 ms from start
+3: Second at 1829 ms from start
+```
+
+<!--- TEST ARBITRARY_TIME -->
+
+#### flatMapMerge
+
+Another flattening mode is to concurrently collect all the incoming flows and merge their values into
+a single flow so that values are emitted as soon as possible.
+It is implemented by [flatMapMerge] and [flattenMerge] operators. They both accept an optional
+`concurrency` parameter that limits the number of concurrent flows that are collected at the same time
+(it is equal to [DEFAULT_CONCURRENCY] by default).
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun requestFlow(i: Int): Flow<String> = flow {
+ emit("$i: First")
+ delay(500) // wait 500 ms
+ emit("$i: Second")
+}
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val startTime = System.currentTimeMillis() // remember the start time
+ (1..3).asFlow().onEach { delay(100) } // a number every 100 ms
+ .flatMapMerge { requestFlow(it) }
+ .collect { value -> // collect and print
+ println("$value at ${System.currentTimeMillis() - startTime} ms from start")
+ }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-24.kt).
+
+The concurrent nature of [flatMapMerge] is obvious:
+
+```text
+1: First at 136 ms from start
+2: First at 231 ms from start
+3: First at 333 ms from start
+1: Second at 639 ms from start
+2: Second at 732 ms from start
+3: Second at 833 ms from start
+```
+
+<!--- TEST ARBITRARY_TIME -->
+
+> Note that the [flatMapMerge] calls its block of code (`{ requestFlow(it) }` in this example) sequentially, but
+collects the resulting flows concurrently, it is the equivalent of performing a sequential
+`map { requestFlow(it) }` first and then calling [flattenMerge] on the result.
+
+#### flatMapLatest
+
+In a similar way to the [collectLatest] operator, that was shown in
+["Processing the latest value"](#processing-the-latest-value) section, there is the corresponding "Latest"
+flattening mode where a collection of the previous flow is cancelled as soon as new flow is emitted.
+It is implemented by the [flatMapLatest] operator.
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun requestFlow(i: Int): Flow<String> = flow {
+ emit("$i: First")
+ delay(500) // wait 500 ms
+ emit("$i: Second")
+}
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val startTime = System.currentTimeMillis() // remember the start time
+ (1..3).asFlow().onEach { delay(100) } // a number every 100 ms
+ .flatMapLatest { requestFlow(it) }
+ .collect { value -> // collect and print
+ println("$value at ${System.currentTimeMillis() - startTime} ms from start")
+ }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-25.kt).
+
+The output here in this example is a good demonstration of how [flatMapLatest] works:
+
+```text
+1: First at 142 ms from start
+2: First at 322 ms from start
+3: First at 425 ms from start
+3: Second at 931 ms from start
+```
+
+<!--- TEST ARBITRARY_TIME -->
+
+> Note that [flatMapLatest] cancels all the code in its block (`{ requestFlow(it) }` in this example) on a new value.
+It makes no difference in this particular example, because the call to `requestFlow` itself is fast, not-suspending,
+and cannot be cancelled. However, it would show up if we were to use suspending functions like `delay` in there.
+
+### Flow exceptions
+
+Flow collection can complete with an exception when an emitter or code inside the operators throw an exception.
+There are several ways to handle these exceptions.
+
+#### Collector try and catch
+
+A collector can use Kotlin's [`try/catch`][exceptions] block to handle exceptions:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun simple(): Flow<Int> = flow {
+ for (i in 1..3) {
+ println("Emitting $i")
+ emit(i) // emit next value
+ }
+}
+
+fun main() = runBlocking<Unit> {
+ try {
+ simple().collect { value ->
+ println(value)
+ check(value <= 1) { "Collected $value" }
+ }
+ } catch (e: Throwable) {
+ println("Caught $e")
+ }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-26.kt).
+
+This code successfully catches an exception in [collect] terminal operator and,
+as we see, no more values are emitted after that:
+
+```text
+Emitting 1
+1
+Emitting 2
+2
+Caught java.lang.IllegalStateException: Collected 2
+```
+
+<!--- TEST -->
+
+#### Everything is caught
+
+The previous example actually catches any exception happening in the emitter or in any intermediate or terminal operators.
+For example, let's change the code so that emitted values are [mapped][map] to strings,
+but the corresponding code produces an exception:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun simple(): Flow<String> =
+ flow {
+ for (i in 1..3) {
+ println("Emitting $i")
+ emit(i) // emit next value
+ }
+ }
+ .map { value ->
+ check(value <= 1) { "Crashed on $value" }
+ "string $value"
+ }
+
+fun main() = runBlocking<Unit> {
+ try {
+ simple().collect { value -> println(value) }
+ } catch (e: Throwable) {
+ println("Caught $e")
+ }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-27.kt).
+
+This exception is still caught and collection is stopped:
+
+```text
+Emitting 1
+string 1
+Emitting 2
+Caught java.lang.IllegalStateException: Crashed on 2
+```
+
+<!--- TEST -->
+
+### Exception transparency
+
+But how can code of the emitter encapsulate its exception handling behavior?
+
+Flows must be _transparent to exceptions_ and it is a violation of the exception transparency to [emit][FlowCollector.emit] values in the
+`flow { ... }` builder from inside of a `try/catch` block. This guarantees that a collector throwing an exception
+can always catch it using `try/catch` as in the previous example.
+
+The emitter can use a [catch] operator that preserves this exception transparency and allows encapsulation
+of its exception handling. The body of the `catch` operator can analyze an exception
+and react to it in different ways depending on which exception was caught:
+
+* Exceptions can be rethrown using `throw`.
+* Exceptions can be turned into emission of values using [emit][FlowCollector.emit] from the body of [catch].
+* Exceptions can be ignored, logged, or processed by some other code.
+
+For example, let us emit the text on catching an exception:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun simple(): Flow<String> =
+ flow {
+ for (i in 1..3) {
+ println("Emitting $i")
+ emit(i) // emit next value
+ }
+ }
+ .map { value ->
+ check(value <= 1) { "Crashed on $value" }
+ "string $value"
+ }
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ simple()
+ .catch { e -> emit("Caught $e") } // emit on exception
+ .collect { value -> println(value) }
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-28.kt).
+
+The output of the example is the same, even though we do not have `try/catch` around the code anymore.
+
+<!--- TEST
+Emitting 1
+string 1
+Emitting 2
+Caught java.lang.IllegalStateException: Crashed on 2
+-->
+
+#### Transparent catch
+
+The [catch] intermediate operator, honoring exception transparency, catches only upstream exceptions
+(that is an exception from all the operators above `catch`, but not below it).
+If the block in `collect { ... }` (placed below `catch`) throws an exception then it escapes:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun simple(): Flow<Int> = flow {
+ for (i in 1..3) {
+ println("Emitting $i")
+ emit(i)
+ }
+}
+
+fun main() = runBlocking<Unit> {
+ simple()
+ .catch { e -> println("Caught $e") } // does not catch downstream exceptions
+ .collect { value ->
+ check(value <= 1) { "Collected $value" }
+ println(value)
+ }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-29.kt).
+
+A "Caught ..." message is not printed despite there being a `catch` operator:
+
+```text
+Emitting 1
+1
+Emitting 2
+Exception in thread "main" java.lang.IllegalStateException: Collected 2
+ at ...
+```
+
+<!--- TEST EXCEPTION -->
+
+#### Catching declaratively
+
+We can combine the declarative nature of the [catch] operator with a desire to handle all the exceptions, by moving the body
+of the [collect] operator into [onEach] and putting it before the `catch` operator. Collection of this flow must
+be triggered by a call to `collect()` without parameters:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun simple(): Flow<Int> = flow {
+ for (i in 1..3) {
+ println("Emitting $i")
+ emit(i)
+ }
+}
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ simple()
+ .onEach { value ->
+ check(value <= 1) { "Collected $value" }
+ println(value)
+ }
+ .catch { e -> println("Caught $e") }
+ .collect()
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-30.kt).
+
+Now we can see that a "Caught ..." message is printed and so we can catch all the exceptions without explicitly
+using a `try/catch` block:
+
+```text
+Emitting 1
+1
+Emitting 2
+Caught java.lang.IllegalStateException: Collected 2
+```
+
+<!--- TEST EXCEPTION -->
+
+### Flow completion
+
+When flow collection completes (normally or exceptionally) it may need to execute an action.
+As you may have already noticed, it can be done in two ways: imperative or declarative.
+
+#### Imperative finally block
+
+In addition to `try`/`catch`, a collector can also use a `finally` block to execute an action
+upon `collect` completion.
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun simple(): Flow<Int> = (1..3).asFlow()
+
+fun main() = runBlocking<Unit> {
+ try {
+ simple().collect { value -> println(value) }
+ } finally {
+ println("Done")
+ }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-31.kt).
+
+This code prints three numbers produced by the `simple` flow followed by a "Done" string:
+
+```text
+1
+2
+3
+Done
+```
+
+<!--- TEST -->
+
+#### Declarative handling
+
+For the declarative approach, flow has [onCompletion] intermediate operator that is invoked
+when the flow has completely collected.
+
+The previous example can be rewritten using an [onCompletion] operator and produces the same output:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+fun simple(): Flow<Int> = (1..3).asFlow()
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ simple()
+ .onCompletion { println("Done") }
+ .collect { value -> println(value) }
+//sampleEnd
+}
+```
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-32.kt).
+
+<!--- TEST
+1
+2
+3
+Done
+-->
+
+The key advantage of [onCompletion] is a nullable `Throwable` parameter of the lambda that can be used
+to determine whether the flow collection was completed normally or exceptionally. In the following
+example the `simple` flow throws an exception after emitting the number 1:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun simple(): Flow<Int> = flow {
+ emit(1)
+ throw RuntimeException()
+}
+
+fun main() = runBlocking<Unit> {
+ simple()
+ .onCompletion { cause -> if (cause != null) println("Flow completed exceptionally") }
+ .catch { cause -> println("Caught exception") }
+ .collect { value -> println(value) }
+}
+//sampleEnd
+```
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-33.kt).
+
+As you may expect, it prints:
+
+```text
+1
+Flow completed exceptionally
+Caught exception
+```
+
+<!--- TEST -->
+
+The [onCompletion] operator, unlike [catch], does not handle the exception. As we can see from the above
+example code, the exception still flows downstream. It will be delivered to further `onCompletion` operators
+and can be handled with a `catch` operator.
+
+#### Successful completion
+
+Another difference with [catch] operator is that [onCompletion] sees all exceptions and receives
+a `null` exception only on successful completion of the upstream flow (without cancellation or failure).
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun simple(): Flow<Int> = (1..3).asFlow()
+
+fun main() = runBlocking<Unit> {
+ simple()
+ .onCompletion { cause -> println("Flow completed with $cause") }
+ .collect { value ->
+ check(value <= 1) { "Collected $value" }
+ println(value)
+ }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-34.kt).
+
+We can see the completion cause is not null, because the flow was aborted due to downstream exception:
+
+```text
+1
+Flow completed with java.lang.IllegalStateException: Collected 2
+Exception in thread "main" java.lang.IllegalStateException: Collected 2
+```
+
+<!--- TEST EXCEPTION -->
+
+### Imperative versus declarative
+
+Now we know how to collect flow, and handle its completion and exceptions in both imperative and declarative ways.
+The natural question here is, which approach is preferred and why?
+As a library, we do not advocate for any particular approach and believe that both options
+are valid and should be selected according to your own preferences and code style.
+
+### Launching flow
+
+It is easy to use flows to represent asynchronous events that are coming from some source.
+In this case, we need an analogue of the `addEventListener` function that registers a piece of code with a reaction
+for incoming events and continues further work. The [onEach] operator can serve this role.
+However, `onEach` is an intermediate operator. We also need a terminal operator to collect the flow.
+Otherwise, just calling `onEach` has no effect.
+
+If we use the [collect] terminal operator after `onEach`, then the code after it will wait until the flow is collected:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+// Imitate a flow of events
+fun events(): Flow<Int> = (1..3).asFlow().onEach { delay(100) }
+
+fun main() = runBlocking<Unit> {
+ events()
+ .onEach { event -> println("Event: $event") }
+ .collect() // <--- Collecting the flow waits
+ println("Done")
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-35.kt).
+
+As you can see, it prints:
+
+```text
+Event: 1
+Event: 2
+Event: 3
+Done
+```
+
+<!--- TEST -->
+
+The [launchIn] terminal operator comes in handy here. By replacing `collect` with `launchIn` we can
+launch a collection of the flow in a separate coroutine, so that execution of further code
+immediately continues:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+// Imitate a flow of events
+fun events(): Flow<Int> = (1..3).asFlow().onEach { delay(100) }
+
+//sampleStart
+fun main() = runBlocking<Unit> {
+ events()
+ .onEach { event -> println("Event: $event") }
+ .launchIn(this) // <--- Launching the flow in a separate coroutine
+ println("Done")
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-36.kt).
+
+It prints:
+
+```text
+Done
+Event: 1
+Event: 2
+Event: 3
+```
+
+<!--- TEST -->
+
+The required parameter to `launchIn` must specify a [CoroutineScope] in which the coroutine to collect the flow is
+launched. In the above example this scope comes from the [runBlocking]
+coroutine builder, so while the flow is running, this [runBlocking] scope waits for completion of its child coroutine
+and keeps the main function from returning and terminating this example.
+
+In actual applications a scope will come from an entity with a limited
+lifetime. As soon as the lifetime of this entity is terminated the corresponding scope is cancelled, cancelling
+the collection of the corresponding flow. This way the pair of `onEach { ... }.launchIn(scope)` works
+like the `addEventListener`. However, there is no need for the corresponding `removeEventListener` function,
+as cancellation and structured concurrency serve this purpose.
+
+Note that [launchIn] also returns a [Job], which can be used to [cancel][Job.cancel] the corresponding flow collection
+coroutine only without cancelling the whole scope or to [join][Job.join] it.
+
+### Flow cancellation checks
+
+For convenience, the [flow][_flow] builder performs additional [ensureActive] checks for cancellation on each emitted value.
+It means that a busy loop emitting from a `flow { ... }` is cancellable:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun foo(): Flow<Int> = flow {
+ for (i in 1..5) {
+ println("Emitting $i")
+ emit(i)
+ }
+}
+
+fun main() = runBlocking<Unit> {
+ foo().collect { value ->
+ if (value == 3) cancel()
+ println(value)
+ }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-37.kt).
+
+We get only numbers up to 3 and a [CancellationException] after trying to emit number 4:
+
+```text
+Emitting 1
+1
+Emitting 2
+2
+Emitting 3
+3
+Emitting 4
+Exception in thread "main" kotlinx.coroutines.JobCancellationException: BlockingCoroutine was cancelled; job="coroutine#1":BlockingCoroutine{Cancelled}@6d7b4f4c
+```
+
+<!--- TEST EXCEPTION -->
+
+However, most other flow operators do not do additional cancellation checks on their own for performance reasons.
+For example, if you use [IntRange.asFlow] extension to write the same busy loop and don't suspend anywhere,
+then there are no checks for cancellation:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun main() = runBlocking<Unit> {
+ (1..5).asFlow().collect { value ->
+ if (value == 3) cancel()
+ println(value)
+ }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-38.kt).
+
+All numbers from 1 to 5 are collected and cancellation gets detected only before return from `runBlocking`:
+
+```text
+1
+2
+3
+4
+5
+Exception in thread "main" kotlinx.coroutines.JobCancellationException: BlockingCoroutine was cancelled; job="coroutine#1":BlockingCoroutine{Cancelled}@3327bd23
+```
+
+<!--- TEST EXCEPTION -->
+
+#### Making busy flow cancellable
+
+In the case where you have a busy loop with coroutines you must explicitly check for cancellation.
+You can add `.onEach { currentCoroutineContext().ensureActive() }`, but there is a ready-to-use
+[cancellable] operator provided to do that:
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+
+//sampleStart
+fun main() = runBlocking<Unit> {
+ (1..5).asFlow().cancellable().collect { value ->
+ if (value == 3) cancel()
+ println(value)
+ }
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-39.kt).
+
+With the `cancellable` operator only the numbers from 1 to 3 are collected:
+
+```text
+1
+2
+3
+Exception in thread "main" kotlinx.coroutines.JobCancellationException: BlockingCoroutine was cancelled; job="coroutine#1":BlockingCoroutine{Cancelled}@5ec0a365
+```
+
+<!--- TEST EXCEPTION -->
+
+### Flow and Reactive Streams
+
+For those who are familiar with [Reactive Streams](https://www.reactive-streams.org/) or reactive frameworks such as RxJava and project Reactor,
+design of the Flow may look very familiar.
+
+Indeed, its design was inspired by Reactive Streams and its various implementations. But Flow main goal is to have as simple design as possible,
+be Kotlin and suspension friendly and respect structured concurrency. Achieving this goal would be impossible without reactive pioneers and their tremendous work. You can read the complete story in [Reactive Streams and Kotlin Flows](https://medium.com/@elizarov/reactive-streams-and-kotlin-flows-bfd12772cda4) article.
+
+While being different, conceptually, Flow *is* a reactive stream and it is possible to convert it to the reactive (spec and TCK compliant) Publisher and vice versa.
+Such converters are provided by `kotlinx.coroutines` out-of-the-box and can be found in corresponding reactive modules (`kotlinx-coroutines-reactive` for Reactive Streams, `kotlinx-coroutines-reactor` for Project Reactor and `kotlinx-coroutines-rx2`/`kotlinx-coroutines-rx3` for RxJava2/RxJava3).
+Integration modules include conversions from and to `Flow`, integration with Reactor's `Context` and suspension-friendly ways to work with various reactive entities.
+
+<!-- stdlib references -->
+
+[collections]: https://kotlinlang.org/docs/reference/collections-overview.html
+[List]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html
+[forEach]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/for-each.html
+[Sequence]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/index.html
+[Sequence.zip]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/zip.html
+[Sequence.flatten]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/flatten.html
+[Sequence.flatMap]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/flat-map.html
+[exceptions]: https://kotlinlang.org/docs/reference/exceptions.html
+
+<!--- MODULE kotlinx-coroutines-core -->
+<!--- INDEX kotlinx.coroutines -->
+[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
+[withTimeoutOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout-or-null.html
+[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html
+[Dispatchers.Main]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html
+[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
+[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html
+[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
+[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
+[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
+[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html
+[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
+[ensureActive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-active.html
+[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html
+<!--- INDEX kotlinx.coroutines.flow -->
+[Flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html
+[_flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow.html
+[FlowCollector.emit]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow-collector/emit.html
+[collect]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/collect.html
+[flowOf]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow-of.html
+[map]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/map.html
+[filter]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/filter.html
+[transform]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/transform.html
+[take]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/take.html
+[toList]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/to-list.html
+[toSet]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/to-set.html
+[first]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/first.html
+[single]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/single.html
+[reduce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/reduce.html
+[fold]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/fold.html
+[flowOn]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow-on.html
+[buffer]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/buffer.html
+[conflate]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/conflate.html
+[collectLatest]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/collect-latest.html
+[zip]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/zip.html
+[combine]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/combine.html
+[onEach]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/on-each.html
+[flatMapConcat]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flat-map-concat.html
+[flattenConcat]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flatten-concat.html
+[flatMapMerge]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flat-map-merge.html
+[flattenMerge]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flatten-merge.html
+[DEFAULT_CONCURRENCY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-d-e-f-a-u-l-t_-c-o-n-c-u-r-r-e-n-c-y.html
+[flatMapLatest]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flat-map-latest.html
+[catch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/catch.html
+[onCompletion]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/on-completion.html
+[launchIn]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/launch-in.html
+[IntRange.asFlow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/kotlin.ranges.-int-range/as-flow.html
+[cancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/cancellable.html
+<!--- END -->
diff --git a/docs/images/coroutine-breakpoint.png b/docs/images/coroutine-breakpoint.png
deleted file mode 100644
index b547e77d..00000000
--- a/docs/images/coroutine-breakpoint.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/coroutine-debug-1.png b/docs/images/coroutine-debug-1.png
deleted file mode 100644
index d92d0ff1..00000000
--- a/docs/images/coroutine-debug-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/coroutine-debug-2.png b/docs/images/coroutine-debug-2.png
deleted file mode 100644
index 56f19c3d..00000000
--- a/docs/images/coroutine-debug-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/coroutine-debug-3.png b/docs/images/coroutine-debug-3.png
deleted file mode 100644
index 43a1460a..00000000
--- a/docs/images/coroutine-debug-3.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/flow-breakpoint.png b/docs/images/flow-breakpoint.png
deleted file mode 100644
index aa98e18e..00000000
--- a/docs/images/flow-breakpoint.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/flow-build-project.png b/docs/images/flow-build-project.png
deleted file mode 100644
index 22186213..00000000
--- a/docs/images/flow-build-project.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/flow-debug-1.png b/docs/images/flow-debug-1.png
deleted file mode 100644
index 8a16984a..00000000
--- a/docs/images/flow-debug-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/flow-debug-2.png b/docs/images/flow-debug-2.png
deleted file mode 100644
index d06c86bf..00000000
--- a/docs/images/flow-debug-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/flow-debug-3.png b/docs/images/flow-debug-3.png
deleted file mode 100644
index af082c05..00000000
--- a/docs/images/flow-debug-3.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/flow-debug-4.png b/docs/images/flow-debug-4.png
deleted file mode 100644
index 8d1c42df..00000000
--- a/docs/images/flow-debug-4.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/flow-debug-project.png b/docs/images/flow-debug-project.png
deleted file mode 100644
index 98d392e2..00000000
--- a/docs/images/flow-debug-project.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/flow-resume-debug.png b/docs/images/flow-resume-debug.png
deleted file mode 100644
index adb12494..00000000
--- a/docs/images/flow-resume-debug.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/new-gradle-project-jvm.png b/docs/images/new-gradle-project-jvm.png
deleted file mode 100644
index 108ce758..00000000
--- a/docs/images/new-gradle-project-jvm.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/new-mvn-project-jvm.png b/docs/images/new-mvn-project-jvm.png
deleted file mode 100644
index 2154a3df..00000000
--- a/docs/images/new-mvn-project-jvm.png
+++ /dev/null
Binary files differ
diff --git a/docs/kc.tree b/docs/kc.tree
deleted file mode 100644
index 9cc0a28c..00000000
--- a/docs/kc.tree
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!DOCTYPE product-profile
- SYSTEM "http://helpserver.labs.intellij.net/help/product-profile.dtd">
-
-<product-profile id="kc"
- name="Kotlin coroutines"
- start-page="coroutines-guide.md">
-
- <toc-element id="coroutines-guide.md"/>
- <toc-element id="async-programming.md"/>
- <toc-element id="coroutines-basics.md"/>
- <toc-element id="coroutines-basic-jvm.md"/>
- <toc-element toc-title="Intro to coroutines and channels – hands-on tutorial" href="https://play.kotlinlang.org/hands-on/Introduction%20to%20Coroutines%20and%20Channels/"/>
- <toc-element id="cancellation-and-timeouts.md"/>
- <toc-element id="composing-suspending-functions.md"/>
- <toc-element id="coroutine-context-and-dispatchers.md"/>
- <toc-element id="flow.md"/>
- <toc-element id="channels.md"/>
- <toc-element id="exception-handling.md"/>
- <toc-element id="shared-mutable-state-and-concurrency.md"/>
- <toc-element id="select-expression.md"/>
- <toc-element id="debug-coroutines-with-idea.md"/>
- <toc-element id="debug-flow-with-idea.md"/>
-
-</product-profile>
diff --git a/docs/knit.properties b/docs/knit.properties
new file mode 100644
index 00000000..2028ecb4
--- /dev/null
+++ b/docs/knit.properties
@@ -0,0 +1,10 @@
+#
+# Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+knit.package=kotlinx.coroutines.guide
+knit.dir=../kotlinx-coroutines-core/jvm/test/guide/
+
+test.package=kotlinx.coroutines.guide.test
+test.dir=../kotlinx-coroutines-core/jvm/test/guide/test/
+
diff --git a/docs/project.ihp b/docs/project.ihp
deleted file mode 100644
index 80859c4b..00000000
--- a/docs/project.ihp
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE ihp SYSTEM "http://helpserver.labs.intellij.net/help/ihp.dtd">
-
-<ihp version="2.0">
- <categories src="c.list"/>
- <topics dir="topics"/>
- <images dir="images" web-path="/img/kotlin-coroutines/"/>
- <vars src="v.list"/>
- <product version="%coroutinesVersion%" id="help/kotlin-coroutines" src="kc.tree" web-path="/kotlin-coroutines/"/>
- <settings>
- <default-property element-name="toc-element" property-name="show-structure-depth" value="2"/>
- </settings>
-</ihp> \ No newline at end of file
diff --git a/docs/select-expression.md b/docs/select-expression.md
index d0451680..f0e5ae46 100644
--- a/docs/select-expression.md
+++ b/docs/select-expression.md
@@ -1,3 +1,549 @@
-The documentation has been moved to the [https://kotlinlang.org/docs/select-expression.html](https://kotlinlang.org/docs/select-expression.html) page.
+<!--- TEST_NAME SelectGuideTest -->
-To edit the documentation, open the [topics/select-expression.md](topics/select-expression.md) page. \ No newline at end of file
+**Table of contents**
+
+<!--- TOC -->
+
+* [Select Expression (experimental)](#select-expression-experimental)
+ * [Selecting from channels](#selecting-from-channels)
+ * [Selecting on close](#selecting-on-close)
+ * [Selecting to send](#selecting-to-send)
+ * [Selecting deferred values](#selecting-deferred-values)
+ * [Switch over a channel of deferred values](#switch-over-a-channel-of-deferred-values)
+
+<!--- END -->
+
+## Select Expression (experimental)
+
+Select expression makes it possible to await multiple suspending functions simultaneously and _select_
+the first one that becomes available.
+
+> Select expressions are an experimental feature of `kotlinx.coroutines`. Their API is expected to
+evolve in the upcoming updates of the `kotlinx.coroutines` library with potentially
+breaking changes.
+
+### Selecting from channels
+
+Let us have two producers of strings: `fizz` and `buzz`. The `fizz` produces "Fizz" string every 300 ms:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.fizz() = produce<String> {
+ while (true) { // sends "Fizz" every 300 ms
+ delay(300)
+ send("Fizz")
+ }
+}
+```
+
+</div>
+
+And the `buzz` produces "Buzz!" string every 500 ms:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.buzz() = produce<String> {
+ while (true) { // sends "Buzz!" every 500 ms
+ delay(500)
+ send("Buzz!")
+ }
+}
+```
+
+</div>
+
+Using [receive][ReceiveChannel.receive] suspending function we can receive _either_ from one channel or the
+other. But [select] expression allows us to receive from _both_ simultaneously using its
+[onReceive][ReceiveChannel.onReceive] clauses:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+suspend fun selectFizzBuzz(fizz: ReceiveChannel<String>, buzz: ReceiveChannel<String>) {
+ select<Unit> { // <Unit> means that this select expression does not produce any result
+ fizz.onReceive { value -> // this is the first select clause
+ println("fizz -> '$value'")
+ }
+ buzz.onReceive { value -> // this is the second select clause
+ println("buzz -> '$value'")
+ }
+ }
+}
+```
+
+</div>
+
+Let us run it all seven times:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+import kotlinx.coroutines.selects.*
+
+fun CoroutineScope.fizz() = produce<String> {
+ while (true) { // sends "Fizz" every 300 ms
+ delay(300)
+ send("Fizz")
+ }
+}
+
+fun CoroutineScope.buzz() = produce<String> {
+ while (true) { // sends "Buzz!" every 500 ms
+ delay(500)
+ send("Buzz!")
+ }
+}
+
+suspend fun selectFizzBuzz(fizz: ReceiveChannel<String>, buzz: ReceiveChannel<String>) {
+ select<Unit> { // <Unit> means that this select expression does not produce any result
+ fizz.onReceive { value -> // this is the first select clause
+ println("fizz -> '$value'")
+ }
+ buzz.onReceive { value -> // this is the second select clause
+ println("buzz -> '$value'")
+ }
+ }
+}
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val fizz = fizz()
+ val buzz = buzz()
+ repeat(7) {
+ selectFizzBuzz(fizz, buzz)
+ }
+ coroutineContext.cancelChildren() // cancel fizz & buzz coroutines
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-select-01.kt).
+
+The result of this code is:
+
+```text
+fizz -> 'Fizz'
+buzz -> 'Buzz!'
+fizz -> 'Fizz'
+fizz -> 'Fizz'
+buzz -> 'Buzz!'
+fizz -> 'Fizz'
+buzz -> 'Buzz!'
+```
+
+<!--- TEST -->
+
+### Selecting on close
+
+The [onReceive][ReceiveChannel.onReceive] clause in `select` fails when the channel is closed causing the corresponding
+`select` to throw an exception. We can use [onReceiveOrNull][onReceiveOrNull] clause to perform a
+specific action when the channel is closed. The following example also shows that `select` is an expression that returns
+the result of its selected clause:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+suspend fun selectAorB(a: ReceiveChannel<String>, b: ReceiveChannel<String>): String =
+ select<String> {
+ a.onReceiveOrNull { value ->
+ if (value == null)
+ "Channel 'a' is closed"
+ else
+ "a -> '$value'"
+ }
+ b.onReceiveOrNull { value ->
+ if (value == null)
+ "Channel 'b' is closed"
+ else
+ "b -> '$value'"
+ }
+ }
+```
+
+</div>
+
+Note that [onReceiveOrNull][onReceiveOrNull] is an extension function defined only
+for channels with non-nullable elements so that there is no accidental confusion between a closed channel
+and a null value.
+
+Let's use it with channel `a` that produces "Hello" string four times and
+channel `b` that produces "World" four times:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+import kotlinx.coroutines.selects.*
+
+suspend fun selectAorB(a: ReceiveChannel<String>, b: ReceiveChannel<String>): String =
+ select<String> {
+ a.onReceiveOrNull { value ->
+ if (value == null)
+ "Channel 'a' is closed"
+ else
+ "a -> '$value'"
+ }
+ b.onReceiveOrNull { value ->
+ if (value == null)
+ "Channel 'b' is closed"
+ else
+ "b -> '$value'"
+ }
+ }
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val a = produce<String> {
+ repeat(4) { send("Hello $it") }
+ }
+ val b = produce<String> {
+ repeat(4) { send("World $it") }
+ }
+ repeat(8) { // print first eight results
+ println(selectAorB(a, b))
+ }
+ coroutineContext.cancelChildren()
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-select-02.kt).
+
+The result of this code is quite interesting, so we'll analyze it in mode detail:
+
+```text
+a -> 'Hello 0'
+a -> 'Hello 1'
+b -> 'World 0'
+a -> 'Hello 2'
+a -> 'Hello 3'
+b -> 'World 1'
+Channel 'a' is closed
+Channel 'a' is closed
+```
+
+<!--- TEST -->
+
+There are couple of observations to make out of it.
+
+First of all, `select` is _biased_ to the first clause. When several clauses are selectable at the same time,
+the first one among them gets selected. Here, both channels are constantly producing strings, so `a` channel,
+being the first clause in select, wins. However, because we are using unbuffered channel, the `a` gets suspended from
+time to time on its [send][SendChannel.send] invocation and gives a chance for `b` to send, too.
+
+The second observation, is that [onReceiveOrNull][onReceiveOrNull] gets immediately selected when the
+channel is already closed.
+
+### Selecting to send
+
+Select expression has [onSend][SendChannel.onSend] clause that can be used for a great good in combination
+with a biased nature of selection.
+
+Let us write an example of producer of integers that sends its values to a `side` channel when
+the consumers on its primary channel cannot keep up with it:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.produceNumbers(side: SendChannel<Int>) = produce<Int> {
+ for (num in 1..10) { // produce 10 numbers from 1 to 10
+ delay(100) // every 100 ms
+ select<Unit> {
+ onSend(num) {} // Send to the primary channel
+ side.onSend(num) {} // or to the side channel
+ }
+ }
+}
+```
+
+</div>
+
+Consumer is going to be quite slow, taking 250 ms to process each number:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+import kotlinx.coroutines.selects.*
+
+fun CoroutineScope.produceNumbers(side: SendChannel<Int>) = produce<Int> {
+ for (num in 1..10) { // produce 10 numbers from 1 to 10
+ delay(100) // every 100 ms
+ select<Unit> {
+ onSend(num) {} // Send to the primary channel
+ side.onSend(num) {} // or to the side channel
+ }
+ }
+}
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val side = Channel<Int>() // allocate side channel
+ launch { // this is a very fast consumer for the side channel
+ side.consumeEach { println("Side channel has $it") }
+ }
+ produceNumbers(side).consumeEach {
+ println("Consuming $it")
+ delay(250) // let us digest the consumed number properly, do not hurry
+ }
+ println("Done consuming")
+ coroutineContext.cancelChildren()
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-select-03.kt).
+
+So let us see what happens:
+
+```text
+Consuming 1
+Side channel has 2
+Side channel has 3
+Consuming 4
+Side channel has 5
+Side channel has 6
+Consuming 7
+Side channel has 8
+Side channel has 9
+Consuming 10
+Done consuming
+```
+
+<!--- TEST -->
+
+### Selecting deferred values
+
+Deferred values can be selected using [onAwait][Deferred.onAwait] clause.
+Let us start with an async function that returns a deferred string value after
+a random delay:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.asyncString(time: Int) = async {
+ delay(time.toLong())
+ "Waited for $time ms"
+}
+```
+
+</div>
+
+Let us start a dozen of them with a random delay.
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.asyncStringsList(): List<Deferred<String>> {
+ val random = Random(3)
+ return List(12) { asyncString(random.nextInt(1000)) }
+}
+```
+
+</div>
+
+Now the main function awaits for the first of them to complete and counts the number of deferred values
+that are still active. Note that we've used here the fact that `select` expression is a Kotlin DSL,
+so we can provide clauses for it using an arbitrary code. In this case we iterate over a list
+of deferred values to provide `onAwait` clause for each deferred value.
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.selects.*
+import java.util.*
+
+fun CoroutineScope.asyncString(time: Int) = async {
+ delay(time.toLong())
+ "Waited for $time ms"
+}
+
+fun CoroutineScope.asyncStringsList(): List<Deferred<String>> {
+ val random = Random(3)
+ return List(12) { asyncString(random.nextInt(1000)) }
+}
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val list = asyncStringsList()
+ val result = select<String> {
+ list.withIndex().forEach { (index, deferred) ->
+ deferred.onAwait { answer ->
+ "Deferred $index produced answer '$answer'"
+ }
+ }
+ }
+ println(result)
+ val countActive = list.count { it.isActive }
+ println("$countActive coroutines are still active")
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-select-04.kt).
+
+The output is:
+
+```text
+Deferred 4 produced answer 'Waited for 128 ms'
+11 coroutines are still active
+```
+
+<!--- TEST -->
+
+### Switch over a channel of deferred values
+
+Let us write a channel producer function that consumes a channel of deferred string values, waits for each received
+deferred value, but only until the next deferred value comes over or the channel is closed. This example puts together
+[onReceiveOrNull][onReceiveOrNull] and [onAwait][Deferred.onAwait] clauses in the same `select`:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.switchMapDeferreds(input: ReceiveChannel<Deferred<String>>) = produce<String> {
+ var current = input.receive() // start with first received deferred value
+ while (isActive) { // loop while not cancelled/closed
+ val next = select<Deferred<String>?> { // return next deferred value from this select or null
+ input.onReceiveOrNull { update ->
+ update // replaces next value to wait
+ }
+ current.onAwait { value ->
+ send(value) // send value that current deferred has produced
+ input.receiveOrNull() // and use the next deferred from the input channel
+ }
+ }
+ if (next == null) {
+ println("Channel was closed")
+ break // out of loop
+ } else {
+ current = next
+ }
+ }
+}
+```
+
+</div>
+
+To test it, we'll use a simple async function that resolves to a specified string after a specified time:
+
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+fun CoroutineScope.asyncString(str: String, time: Long) = async {
+ delay(time)
+ str
+}
+```
+
+</div>
+
+The main function just launches a coroutine to print results of `switchMapDeferreds` and sends some test
+data to it:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+import kotlinx.coroutines.selects.*
+
+fun CoroutineScope.switchMapDeferreds(input: ReceiveChannel<Deferred<String>>) = produce<String> {
+ var current = input.receive() // start with first received deferred value
+ while (isActive) { // loop while not cancelled/closed
+ val next = select<Deferred<String>?> { // return next deferred value from this select or null
+ input.onReceiveOrNull { update ->
+ update // replaces next value to wait
+ }
+ current.onAwait { value ->
+ send(value) // send value that current deferred has produced
+ input.receiveOrNull() // and use the next deferred from the input channel
+ }
+ }
+ if (next == null) {
+ println("Channel was closed")
+ break // out of loop
+ } else {
+ current = next
+ }
+ }
+}
+
+fun CoroutineScope.asyncString(str: String, time: Long) = async {
+ delay(time)
+ str
+}
+
+fun main() = runBlocking<Unit> {
+//sampleStart
+ val chan = Channel<Deferred<String>>() // the channel for test
+ launch { // launch printing coroutine
+ for (s in switchMapDeferreds(chan))
+ println(s) // print each received string
+ }
+ chan.send(asyncString("BEGIN", 100))
+ delay(200) // enough time for "BEGIN" to be produced
+ chan.send(asyncString("Slow", 500))
+ delay(100) // not enough time to produce slow
+ chan.send(asyncString("Replace", 100))
+ delay(500) // give it time before the last one
+ chan.send(asyncString("END", 500))
+ delay(1000) // give it time to process
+ chan.close() // close the channel ...
+ delay(500) // and wait some time to let it finish
+//sampleEnd
+}
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-select-05.kt).
+
+The result of this code:
+
+```text
+BEGIN
+Replace
+END
+Channel was closed
+```
+
+<!--- TEST -->
+
+<!--- MODULE kotlinx-coroutines-core -->
+<!--- INDEX kotlinx.coroutines -->
+[Deferred.onAwait]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/on-await.html
+<!--- INDEX kotlinx.coroutines.channels -->
+[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive.html
+[ReceiveChannel.onReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive.html
+[onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/on-receive-or-null.html
+[SendChannel.send]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/send.html
+[SendChannel.onSend]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/on-send.html
+<!--- INDEX kotlinx.coroutines.selects -->
+[select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html
+<!--- END -->
diff --git a/docs/shared-mutable-state-and-concurrency.md b/docs/shared-mutable-state-and-concurrency.md
index ca054368..8b83ad0b 100644
--- a/docs/shared-mutable-state-and-concurrency.md
+++ b/docs/shared-mutable-state-and-concurrency.md
@@ -1,3 +1,539 @@
-The documentation has been moved to the [https://kotlinlang.org/docs/shared-mutable-state-and-concurrency.html](https://kotlinlang.org/docs/shared-mutable-state-and-concurrency.html) page.
+<!--- TEST_NAME SharedStateGuideTest -->
+
+**Table of contents**
-To edit the documentation, open the [topics/shared-mutable-state-and-concurrency.md](topics/shared-mutable-state-and-concurrency.md) page. \ No newline at end of file
+<!--- TOC -->
+
+* [Shared mutable state and concurrency](#shared-mutable-state-and-concurrency)
+ * [The problem](#the-problem)
+ * [Volatiles are of no help](#volatiles-are-of-no-help)
+ * [Thread-safe data structures](#thread-safe-data-structures)
+ * [Thread confinement fine-grained](#thread-confinement-fine-grained)
+ * [Thread confinement coarse-grained](#thread-confinement-coarse-grained)
+ * [Mutual exclusion](#mutual-exclusion)
+ * [Actors](#actors)
+
+<!--- END -->
+
+## Shared mutable state and concurrency
+
+Coroutines can be executed concurrently using a multi-threaded dispatcher like the [Dispatchers.Default]. It presents
+all the usual concurrency problems. The main problem being synchronization of access to **shared mutable state**.
+Some solutions to this problem in the land of coroutines are similar to the solutions in the multi-threaded world,
+but others are unique.
+
+### The problem
+
+Let us launch a hundred coroutines all doing the same action a thousand times.
+We'll also measure their completion time for further comparisons:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+suspend fun massiveRun(action: suspend () -> Unit) {
+ val n = 100 // number of coroutines to launch
+ val k = 1000 // times an action is repeated by each coroutine
+ val time = measureTimeMillis {
+ coroutineScope { // scope for coroutines
+ repeat(n) {
+ launch {
+ repeat(k) { action() }
+ }
+ }
+ }
+ }
+ println("Completed ${n * k} actions in $time ms")
+}
+```
+
+</div>
+
+We start with a very simple action that increments a shared mutable variable using
+multi-threaded [Dispatchers.Default].
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlin.system.*
+
+suspend fun massiveRun(action: suspend () -> Unit) {
+ val n = 100 // number of coroutines to launch
+ val k = 1000 // times an action is repeated by each coroutine
+ val time = measureTimeMillis {
+ coroutineScope { // scope for coroutines
+ repeat(n) {
+ launch {
+ repeat(k) { action() }
+ }
+ }
+ }
+ }
+ println("Completed ${n * k} actions in $time ms")
+}
+
+//sampleStart
+var counter = 0
+
+fun main() = runBlocking {
+ withContext(Dispatchers.Default) {
+ massiveRun {
+ counter++
+ }
+ }
+ println("Counter = $counter")
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-sync-01.kt).
+
+<!--- TEST LINES_START
+Completed 100000 actions in
+Counter =
+-->
+
+What does it print at the end? It is highly unlikely to ever print "Counter = 100000", because a hundred coroutines
+increment the `counter` concurrently from multiple threads without any synchronization.
+
+### Volatiles are of no help
+
+There is a common misconception that making a variable `volatile` solves concurrency problem. Let us try it:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlin.system.*
+
+suspend fun massiveRun(action: suspend () -> Unit) {
+ val n = 100 // number of coroutines to launch
+ val k = 1000 // times an action is repeated by each coroutine
+ val time = measureTimeMillis {
+ coroutineScope { // scope for coroutines
+ repeat(n) {
+ launch {
+ repeat(k) { action() }
+ }
+ }
+ }
+ }
+ println("Completed ${n * k} actions in $time ms")
+}
+
+//sampleStart
+@Volatile // in Kotlin `volatile` is an annotation
+var counter = 0
+
+fun main() = runBlocking {
+ withContext(Dispatchers.Default) {
+ massiveRun {
+ counter++
+ }
+ }
+ println("Counter = $counter")
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-sync-02.kt).
+
+<!--- TEST LINES_START
+Completed 100000 actions in
+Counter =
+-->
+
+This code works slower, but we still don't get "Counter = 100000" at the end, because volatile variables guarantee
+linearizable (this is a technical term for "atomic") reads and writes to the corresponding variable, but
+do not provide atomicity of larger actions (increment in our case).
+
+### Thread-safe data structures
+
+The general solution that works both for threads and for coroutines is to use a thread-safe (aka synchronized,
+linearizable, or atomic) data structure that provides all the necessary synchronization for the corresponding
+operations that needs to be performed on a shared state.
+In the case of a simple counter we can use `AtomicInteger` class which has atomic `incrementAndGet` operations:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import java.util.concurrent.atomic.*
+import kotlin.system.*
+
+suspend fun massiveRun(action: suspend () -> Unit) {
+ val n = 100 // number of coroutines to launch
+ val k = 1000 // times an action is repeated by each coroutine
+ val time = measureTimeMillis {
+ coroutineScope { // scope for coroutines
+ repeat(n) {
+ launch {
+ repeat(k) { action() }
+ }
+ }
+ }
+ }
+ println("Completed ${n * k} actions in $time ms")
+}
+
+//sampleStart
+val counter = AtomicInteger()
+
+fun main() = runBlocking {
+ withContext(Dispatchers.Default) {
+ massiveRun {
+ counter.incrementAndGet()
+ }
+ }
+ println("Counter = $counter")
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-sync-03.kt).
+
+<!--- TEST ARBITRARY_TIME
+Completed 100000 actions in xxx ms
+Counter = 100000
+-->
+
+This is the fastest solution for this particular problem. It works for plain counters, collections, queues and other
+standard data structures and basic operations on them. However, it does not easily scale to complex
+state or to complex operations that do not have ready-to-use thread-safe implementations.
+
+### Thread confinement fine-grained
+
+_Thread confinement_ is an approach to the problem of shared mutable state where all access to the particular shared
+state is confined to a single thread. It is typically used in UI applications, where all UI state is confined to
+the single event-dispatch/application thread. It is easy to apply with coroutines by using a
+single-threaded context.
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlin.system.*
+
+suspend fun massiveRun(action: suspend () -> Unit) {
+ val n = 100 // number of coroutines to launch
+ val k = 1000 // times an action is repeated by each coroutine
+ val time = measureTimeMillis {
+ coroutineScope { // scope for coroutines
+ repeat(n) {
+ launch {
+ repeat(k) { action() }
+ }
+ }
+ }
+ }
+ println("Completed ${n * k} actions in $time ms")
+}
+
+//sampleStart
+val counterContext = newSingleThreadContext("CounterContext")
+var counter = 0
+
+fun main() = runBlocking {
+ withContext(Dispatchers.Default) {
+ massiveRun {
+ // confine each increment to a single-threaded context
+ withContext(counterContext) {
+ counter++
+ }
+ }
+ }
+ println("Counter = $counter")
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-sync-04.kt).
+
+<!--- TEST ARBITRARY_TIME
+Completed 100000 actions in xxx ms
+Counter = 100000
+-->
+
+This code works very slowly, because it does _fine-grained_ thread-confinement. Each individual increment switches
+from multi-threaded [Dispatchers.Default] context to the single-threaded context using
+[withContext(counterContext)][withContext] block.
+
+### Thread confinement coarse-grained
+
+In practice, thread confinement is performed in large chunks, e.g. big pieces of state-updating business logic
+are confined to the single thread. The following example does it like that, running each coroutine in
+the single-threaded context to start with.
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlin.system.*
+
+suspend fun massiveRun(action: suspend () -> Unit) {
+ val n = 100 // number of coroutines to launch
+ val k = 1000 // times an action is repeated by each coroutine
+ val time = measureTimeMillis {
+ coroutineScope { // scope for coroutines
+ repeat(n) {
+ launch {
+ repeat(k) { action() }
+ }
+ }
+ }
+ }
+ println("Completed ${n * k} actions in $time ms")
+}
+
+//sampleStart
+val counterContext = newSingleThreadContext("CounterContext")
+var counter = 0
+
+fun main() = runBlocking {
+ // confine everything to a single-threaded context
+ withContext(counterContext) {
+ massiveRun {
+ counter++
+ }
+ }
+ println("Counter = $counter")
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-sync-05.kt).
+
+<!--- TEST ARBITRARY_TIME
+Completed 100000 actions in xxx ms
+Counter = 100000
+-->
+
+This now works much faster and produces correct result.
+
+### Mutual exclusion
+
+Mutual exclusion solution to the problem is to protect all modifications of the shared state with a _critical section_
+that is never executed concurrently. In a blocking world you'd typically use `synchronized` or `ReentrantLock` for that.
+Coroutine's alternative is called [Mutex]. It has [lock][Mutex.lock] and [unlock][Mutex.unlock] functions to
+delimit a critical section. The key difference is that `Mutex.lock()` is a suspending function. It does not block a thread.
+
+There is also [withLock] extension function that conveniently represents
+`mutex.lock(); try { ... } finally { mutex.unlock() }` pattern:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.sync.*
+import kotlin.system.*
+
+suspend fun massiveRun(action: suspend () -> Unit) {
+ val n = 100 // number of coroutines to launch
+ val k = 1000 // times an action is repeated by each coroutine
+ val time = measureTimeMillis {
+ coroutineScope { // scope for coroutines
+ repeat(n) {
+ launch {
+ repeat(k) { action() }
+ }
+ }
+ }
+ }
+ println("Completed ${n * k} actions in $time ms")
+}
+
+//sampleStart
+val mutex = Mutex()
+var counter = 0
+
+fun main() = runBlocking {
+ withContext(Dispatchers.Default) {
+ massiveRun {
+ // protect each increment with lock
+ mutex.withLock {
+ counter++
+ }
+ }
+ }
+ println("Counter = $counter")
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-sync-06.kt).
+
+<!--- TEST ARBITRARY_TIME
+Completed 100000 actions in xxx ms
+Counter = 100000
+-->
+
+The locking in this example is fine-grained, so it pays the price. However, it is a good choice for some situations
+where you absolutely must modify some shared state periodically, but there is no natural thread that this state
+is confined to.
+
+### Actors
+
+An [actor](https://en.wikipedia.org/wiki/Actor_model) is an entity made up of a combination of a coroutine,
+the state that is confined and encapsulated into this coroutine,
+and a channel to communicate with other coroutines. A simple actor can be written as a function,
+but an actor with a complex state is better suited for a class.
+
+There is an [actor] coroutine builder that conveniently combines actor's mailbox channel into its
+scope to receive messages from and combines the send channel into the resulting job object, so that a
+single reference to the actor can be carried around as its handle.
+
+The first step of using an actor is to define a class of messages that an actor is going to process.
+Kotlin's [sealed classes](https://kotlinlang.org/docs/reference/sealed-classes.html) are well suited for that purpose.
+We define `CounterMsg` sealed class with `IncCounter` message to increment a counter and `GetCounter` message
+to get its value. The later needs to send a response. A [CompletableDeferred] communication
+primitive, that represents a single value that will be known (communicated) in the future,
+is used here for that purpose.
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+// Message types for counterActor
+sealed class CounterMsg
+object IncCounter : CounterMsg() // one-way message to increment counter
+class GetCounter(val response: CompletableDeferred<Int>) : CounterMsg() // a request with reply
+```
+
+</div>
+
+Then we define a function that launches an actor using an [actor] coroutine builder:
+
+<div class="sample" markdown="1" theme="idea" data-highlight-only>
+
+```kotlin
+// This function launches a new counter actor
+fun CoroutineScope.counterActor() = actor<CounterMsg> {
+ var counter = 0 // actor state
+ for (msg in channel) { // iterate over incoming messages
+ when (msg) {
+ is IncCounter -> counter++
+ is GetCounter -> msg.response.complete(counter)
+ }
+ }
+}
+```
+
+</div>
+
+The main code is straightforward:
+
+<!--- CLEAR -->
+
+<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
+
+```kotlin
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+import kotlin.system.*
+
+suspend fun massiveRun(action: suspend () -> Unit) {
+ val n = 100 // number of coroutines to launch
+ val k = 1000 // times an action is repeated by each coroutine
+ val time = measureTimeMillis {
+ coroutineScope { // scope for coroutines
+ repeat(n) {
+ launch {
+ repeat(k) { action() }
+ }
+ }
+ }
+ }
+ println("Completed ${n * k} actions in $time ms")
+}
+
+// Message types for counterActor
+sealed class CounterMsg
+object IncCounter : CounterMsg() // one-way message to increment counter
+class GetCounter(val response: CompletableDeferred<Int>) : CounterMsg() // a request with reply
+
+// This function launches a new counter actor
+fun CoroutineScope.counterActor() = actor<CounterMsg> {
+ var counter = 0 // actor state
+ for (msg in channel) { // iterate over incoming messages
+ when (msg) {
+ is IncCounter -> counter++
+ is GetCounter -> msg.response.complete(counter)
+ }
+ }
+}
+
+//sampleStart
+fun main() = runBlocking<Unit> {
+ val counter = counterActor() // create the actor
+ withContext(Dispatchers.Default) {
+ massiveRun {
+ counter.send(IncCounter)
+ }
+ }
+ // send a message to get a counter value from an actor
+ val response = CompletableDeferred<Int>()
+ counter.send(GetCounter(response))
+ println("Counter = ${response.await()}")
+ counter.close() // shutdown the actor
+}
+//sampleEnd
+```
+
+</div>
+
+> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-sync-07.kt).
+
+<!--- TEST ARBITRARY_TIME
+Completed 100000 actions in xxx ms
+Counter = 100000
+-->
+
+It does not matter (for correctness) what context the actor itself is executed in. An actor is
+a coroutine and a coroutine is executed sequentially, so confinement of the state to the specific coroutine
+works as a solution to the problem of shared mutable state. Indeed, actors may modify their own private state,
+but can only affect each other through messages (avoiding the need for any locks).
+
+Actor is more efficient than locking under load, because in this case it always has work to do and it does not
+have to switch to a different context at all.
+
+> Note that an [actor] coroutine builder is a dual of [produce] coroutine builder. An actor is associated
+ with the channel that it receives messages from, while a producer is associated with the channel that it
+ sends elements to.
+
+<!--- MODULE kotlinx-coroutines-core -->
+<!--- INDEX kotlinx.coroutines -->
+[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html
+[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
+[CompletableDeferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-completable-deferred/index.html
+<!--- INDEX kotlinx.coroutines.sync -->
+[Mutex]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/index.html
+[Mutex.lock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/lock.html
+[Mutex.unlock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/unlock.html
+[withLock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/with-lock.html
+<!--- INDEX kotlinx.coroutines.channels -->
+[actor]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/actor.html
+[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/produce.html
+<!--- END -->
diff --git a/docs/topics/cancellation-and-timeouts.md b/docs/topics/cancellation-and-timeouts.md
deleted file mode 100644
index 7aa51e26..00000000
--- a/docs/topics/cancellation-and-timeouts.md
+++ /dev/null
@@ -1,461 +0,0 @@
-<!--- TEST_NAME CancellationGuideTest -->
-
-[//]: # (title: Cancellation and timeouts)
-
-This section covers coroutine cancellation and timeouts.
-
-## Cancelling coroutine execution
-
-In a long-running application you might need fine-grained control on your background coroutines.
-For example, a user might have closed the page that launched a coroutine and now its result
-is no longer needed and its operation can be cancelled.
-The [launch] function returns a [Job] that can be used to cancel the running coroutine:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
-//sampleStart
- val job = launch {
- repeat(1000) { i ->
- println("job: I'm sleeping $i ...")
- delay(500L)
- }
- }
- delay(1300L) // delay a bit
- println("main: I'm tired of waiting!")
- job.cancel() // cancels the job
- job.join() // waits for job's completion
- println("main: Now I can quit.")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-cancel-01.kt).
->
-{type="note"}
-
-It produces the following output:
-
-```text
-job: I'm sleeping 0 ...
-job: I'm sleeping 1 ...
-job: I'm sleeping 2 ...
-main: I'm tired of waiting!
-main: Now I can quit.
-```
-
-<!--- TEST -->
-
-As soon as main invokes `job.cancel`, we don't see any output from the other coroutine because it was cancelled.
-There is also a [Job] extension function [cancelAndJoin]
-that combines [cancel][Job.cancel] and [join][Job.join] invocations.
-
-## Cancellation is cooperative
-
-Coroutine cancellation is _cooperative_. A coroutine code has to cooperate to be cancellable.
-All the suspending functions in `kotlinx.coroutines` are _cancellable_. They check for cancellation of
-coroutine and throw [CancellationException] when cancelled. However, if a coroutine is working in
-a computation and does not check for cancellation, then it cannot be cancelled, like the following
-example shows:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
-//sampleStart
- val startTime = System.currentTimeMillis()
- val job = launch(Dispatchers.Default) {
- var nextPrintTime = startTime
- var i = 0
- while (i < 5) { // computation loop, just wastes CPU
- // print a message twice a second
- if (System.currentTimeMillis() >= nextPrintTime) {
- println("job: I'm sleeping ${i++} ...")
- nextPrintTime += 500L
- }
- }
- }
- delay(1300L) // delay a bit
- println("main: I'm tired of waiting!")
- job.cancelAndJoin() // cancels the job and waits for its completion
- println("main: Now I can quit.")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-cancel-02.kt).
->
-{type="note"}
-
-Run it to see that it continues to print "I'm sleeping" even after cancellation
-until the job completes by itself after five iterations.
-
-<!--- TEST
-job: I'm sleeping 0 ...
-job: I'm sleeping 1 ...
-job: I'm sleeping 2 ...
-main: I'm tired of waiting!
-job: I'm sleeping 3 ...
-job: I'm sleeping 4 ...
-main: Now I can quit.
--->
-
-## Making computation code cancellable
-
-There are two approaches to making computation code cancellable. The first one is to periodically
-invoke a suspending function that checks for cancellation. There is a [yield] function that is a good choice for that purpose.
-The other one is to explicitly check the cancellation status. Let us try the latter approach.
-
-Replace `while (i < 5)` in the previous example with `while (isActive)` and rerun it.
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
-//sampleStart
- val startTime = System.currentTimeMillis()
- val job = launch(Dispatchers.Default) {
- var nextPrintTime = startTime
- var i = 0
- while (isActive) { // cancellable computation loop
- // print a message twice a second
- if (System.currentTimeMillis() >= nextPrintTime) {
- println("job: I'm sleeping ${i++} ...")
- nextPrintTime += 500L
- }
- }
- }
- delay(1300L) // delay a bit
- println("main: I'm tired of waiting!")
- job.cancelAndJoin() // cancels the job and waits for its completion
- println("main: Now I can quit.")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-cancel-03.kt).
->
-{type="note"}
-
-As you can see, now this loop is cancelled. [isActive] is an extension property
-available inside the coroutine via the [CoroutineScope] object.
-
-<!--- TEST
-job: I'm sleeping 0 ...
-job: I'm sleeping 1 ...
-job: I'm sleeping 2 ...
-main: I'm tired of waiting!
-main: Now I can quit.
--->
-
-## Closing resources with `finally`
-
-Cancellable suspending functions throw [CancellationException] on cancellation which can be handled in
-the usual way. For example, `try {...} finally {...}` expression and Kotlin `use` function execute their
-finalization actions normally when a coroutine is cancelled:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
-//sampleStart
- val job = launch {
- try {
- repeat(1000) { i ->
- println("job: I'm sleeping $i ...")
- delay(500L)
- }
- } finally {
- println("job: I'm running finally")
- }
- }
- delay(1300L) // delay a bit
- println("main: I'm tired of waiting!")
- job.cancelAndJoin() // cancels the job and waits for its completion
- println("main: Now I can quit.")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt).
->
-{type="note"}
-
-Both [join][Job.join] and [cancelAndJoin] wait for all finalization actions to complete,
-so the example above produces the following output:
-
-```text
-job: I'm sleeping 0 ...
-job: I'm sleeping 1 ...
-job: I'm sleeping 2 ...
-main: I'm tired of waiting!
-job: I'm running finally
-main: Now I can quit.
-```
-
-<!--- TEST -->
-
-## Run non-cancellable block
-
-Any attempt to use a suspending function in the `finally` block of the previous example causes
-[CancellationException], because the coroutine running this code is cancelled. Usually, this is not a
-problem, since all well-behaving closing operations (closing a file, cancelling a job, or closing any kind of a
-communication channel) are usually non-blocking and do not involve any suspending functions. However, in the
-rare case when you need to suspend in a cancelled coroutine you can wrap the corresponding code in
-`withContext(NonCancellable) {...}` using [withContext] function and [NonCancellable] context as the following example shows:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
-//sampleStart
- val job = launch {
- try {
- repeat(1000) { i ->
- println("job: I'm sleeping $i ...")
- delay(500L)
- }
- } finally {
- withContext(NonCancellable) {
- println("job: I'm running finally")
- delay(1000L)
- println("job: And I've just delayed for 1 sec because I'm non-cancellable")
- }
- }
- }
- delay(1300L) // delay a bit
- println("main: I'm tired of waiting!")
- job.cancelAndJoin() // cancels the job and waits for its completion
- println("main: Now I can quit.")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-cancel-05.kt).
->
-{type="note"}
-
-<!--- TEST
-job: I'm sleeping 0 ...
-job: I'm sleeping 1 ...
-job: I'm sleeping 2 ...
-main: I'm tired of waiting!
-job: I'm running finally
-job: And I've just delayed for 1 sec because I'm non-cancellable
-main: Now I can quit.
--->
-
-## Timeout
-
-The most obvious practical reason to cancel execution of a coroutine
-is because its execution time has exceeded some timeout.
-While you can manually track the reference to the corresponding [Job] and launch a separate coroutine to cancel
-the tracked one after delay, there is a ready to use [withTimeout] function that does it.
-Look at the following example:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
-//sampleStart
- withTimeout(1300L) {
- repeat(1000) { i ->
- println("I'm sleeping $i ...")
- delay(500L)
- }
- }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-cancel-06.kt).
->
-{type="note"}
-
-It produces the following output:
-
-```text
-I'm sleeping 0 ...
-I'm sleeping 1 ...
-I'm sleeping 2 ...
-Exception in thread "main" kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 1300 ms
-```
-
-<!--- TEST STARTS_WITH -->
-
-The `TimeoutCancellationException` that is thrown by [withTimeout] is a subclass of [CancellationException].
-We have not seen its stack trace printed on the console before. That is because
-inside a cancelled coroutine `CancellationException` is considered to be a normal reason for coroutine completion.
-However, in this example we have used `withTimeout` right inside the `main` function.
-
-Since cancellation is just an exception, all resources are closed in the usual way.
-You can wrap the code with timeout in a `try {...} catch (e: TimeoutCancellationException) {...}` block if
-you need to do some additional action specifically on any kind of timeout or use the [withTimeoutOrNull] function
-that is similar to [withTimeout] but returns `null` on timeout instead of throwing an exception:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
-//sampleStart
- val result = withTimeoutOrNull(1300L) {
- repeat(1000) { i ->
- println("I'm sleeping $i ...")
- delay(500L)
- }
- "Done" // will get cancelled before it produces this result
- }
- println("Result is $result")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-cancel-07.kt).
->
-{type="note"}
-
-There is no longer an exception when running this code:
-
-```text
-I'm sleeping 0 ...
-I'm sleeping 1 ...
-I'm sleeping 2 ...
-Result is null
-```
-
-<!--- TEST -->
-
-## Asynchronous timeout and resources
-
-<!--
- NOTE: Don't change this section name. It is being referenced to from within KDoc of withTimeout functions.
--->
-
-The timeout event in [withTimeout] is asynchronous with respect to the code running in its block and may happen at any time,
-even right before the return from inside of the timeout block. Keep this in mind if you open or acquire some
-resource inside the block that needs closing or release outside of the block.
-
-For example, here we imitate a closeable resource with the `Resource` class, that simply keeps track of how many times
-it was created by incrementing the `acquired` counter and decrementing this counter from its `close` function.
-Let us run a lot of coroutines with the small timeout try acquire this resource from inside
-of the `withTimeout` block after a bit of delay and release it from outside.
-
-```kotlin
-import kotlinx.coroutines.*
-
-//sampleStart
-var acquired = 0
-
-class Resource {
- init { acquired++ } // Acquire the resource
- fun close() { acquired-- } // Release the resource
-}
-
-fun main() {
- runBlocking {
- repeat(100_000) { // Launch 100K coroutines
- launch {
- val resource = withTimeout(60) { // Timeout of 60 ms
- delay(50) // Delay for 50 ms
- Resource() // Acquire a resource and return it from withTimeout block
- }
- resource.close() // Release the resource
- }
- }
- }
- // Outside of runBlocking all coroutines have completed
- println(acquired) // Print the number of resources still acquired
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-cancel-08.kt).
->
-{type="note"}
-
-<!--- CLEAR -->
-
-If you run the above code you'll see that it does not always print zero, though it may depend on the timings
-of your machine you may need to tweak timeouts in this example to actually see non-zero values.
-
-> Note, that incrementing and decrementing `acquired` counter here from 100K coroutines is completely safe,
-> since it always happens from the same main thread. More on that will be explained in the next chapter
-> on coroutine context.
->
-{type="note"}
-
-To workaround this problem you can store a reference to the resource in the variable as opposed to returning it
-from the `withTimeout` block.
-
-```kotlin
-import kotlinx.coroutines.*
-
-var acquired = 0
-
-class Resource {
- init { acquired++ } // Acquire the resource
- fun close() { acquired-- } // Release the resource
-}
-
-fun main() {
-//sampleStart
- runBlocking {
- repeat(100_000) { // Launch 100K coroutines
- launch {
- var resource: Resource? = null // Not acquired yet
- try {
- withTimeout(60) { // Timeout of 60 ms
- delay(50) // Delay for 50 ms
- resource = Resource() // Store a resource to the variable if acquired
- }
- // We can do something else with the resource here
- } finally {
- resource?.close() // Release the resource if it was acquired
- }
- }
- }
- }
- // Outside of runBlocking all coroutines have completed
- println(acquired) // Print the number of resources still acquired
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-cancel-09.kt).
->
-{type="note"}
-
-This example always prints zero. Resources do not leak.
-
-<!--- TEST
-0
--->
-
-<!--- MODULE kotlinx-coroutines-core -->
-<!--- INDEX kotlinx.coroutines -->
-
-[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
-[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
-[cancelAndJoin]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel-and-join.html
-[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html
-[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
-[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html
-[yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/yield.html
-[isActive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/is-active.html
-[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
-[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
-[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable.html
-[withTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout.html
-[withTimeoutOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout-or-null.html
-
-<!--- END --> \ No newline at end of file
diff --git a/docs/topics/channels.md b/docs/topics/channels.md
deleted file mode 100644
index 9380b2bd..00000000
--- a/docs/topics/channels.md
+++ /dev/null
@@ -1,649 +0,0 @@
-<!--- TEST_NAME ChannelsGuideTest -->
-
-[//]: # (title: Channels)
-
-Deferred values provide a convenient way to transfer a single value between coroutines.
-Channels provide a way to transfer a stream of values.
-
-## Channel basics
-
-A [Channel] is conceptually very similar to `BlockingQueue`. One key difference is that
-instead of a blocking `put` operation it has a suspending [send][SendChannel.send], and instead of
-a blocking `take` operation it has a suspending [receive][ReceiveChannel.receive].
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-
-fun main() = runBlocking {
-//sampleStart
- val channel = Channel<Int>()
- launch {
- // this might be heavy CPU-consuming computation or async logic, we'll just send five squares
- for (x in 1..5) channel.send(x * x)
- }
- // here we print five received integers:
- repeat(5) { println(channel.receive()) }
- println("Done!")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-channel-01.kt).
->
-{type="note"}
-
-The output of this code is:
-
-```text
-1
-4
-9
-16
-25
-Done!
-```
-
-<!--- TEST -->
-
-## Closing and iteration over channels
-
-Unlike a queue, a channel can be closed to indicate that no more elements are coming.
-On the receiver side it is convenient to use a regular `for` loop to receive elements
-from the channel.
-
-Conceptually, a [close][SendChannel.close] is like sending a special close token to the channel.
-The iteration stops as soon as this close token is received, so there is a guarantee
-that all previously sent elements before the close are received:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-
-fun main() = runBlocking {
-//sampleStart
- val channel = Channel<Int>()
- launch {
- for (x in 1..5) channel.send(x * x)
- channel.close() // we're done sending
- }
- // here we print received values using `for` loop (until the channel is closed)
- for (y in channel) println(y)
- println("Done!")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-channel-02.kt).
->
-{type="note"}
-
-<!--- TEST
-1
-4
-9
-16
-25
-Done!
--->
-
-## Building channel producers
-
-The pattern where a coroutine is producing a sequence of elements is quite common.
-This is a part of _producer-consumer_ pattern that is often found in concurrent code.
-You could abstract such a producer into a function that takes channel as its parameter, but this goes contrary
-to common sense that results must be returned from functions.
-
-There is a convenient coroutine builder named [produce] that makes it easy to do it right on producer side,
-and an extension function [consumeEach], that replaces a `for` loop on the consumer side:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-
-fun CoroutineScope.produceSquares(): ReceiveChannel<Int> = produce {
- for (x in 1..5) send(x * x)
-}
-
-fun main() = runBlocking {
-//sampleStart
- val squares = produceSquares()
- squares.consumeEach { println(it) }
- println("Done!")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-channel-03.kt).
->
-{type="note"}
-
-<!--- TEST
-1
-4
-9
-16
-25
-Done!
--->
-
-## Pipelines
-
-A pipeline is a pattern where one coroutine is producing, possibly infinite, stream of values:
-
-```kotlin
-fun CoroutineScope.produceNumbers() = produce<Int> {
- var x = 1
- while (true) send(x++) // infinite stream of integers starting from 1
-}
-```
-
-And another coroutine or coroutines are consuming that stream, doing some processing, and producing some other results.
-In the example below, the numbers are just squared:
-
-```kotlin
-fun CoroutineScope.square(numbers: ReceiveChannel<Int>): ReceiveChannel<Int> = produce {
- for (x in numbers) send(x * x)
-}
-```
-
-The main code starts and connects the whole pipeline:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-
-fun main() = runBlocking {
-//sampleStart
- val numbers = produceNumbers() // produces integers from 1 and on
- val squares = square(numbers) // squares integers
- repeat(5) {
- println(squares.receive()) // print first five
- }
- println("Done!") // we are done
- coroutineContext.cancelChildren() // cancel children coroutines
-//sampleEnd
-}
-
-fun CoroutineScope.produceNumbers() = produce<Int> {
- var x = 1
- while (true) send(x++) // infinite stream of integers starting from 1
-}
-
-fun CoroutineScope.square(numbers: ReceiveChannel<Int>): ReceiveChannel<Int> = produce {
- for (x in numbers) send(x * x)
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-channel-04.kt).
->
-{type="note"}
-
-<!--- TEST
-1
-4
-9
-16
-25
-Done!
--->
-
-> All functions that create coroutines are defined as extensions on [CoroutineScope],
-> so that we can rely on [structured concurrency](composing-suspending-functions.md#structured-concurrency-with-async) to make
-> sure that we don't have lingering global coroutines in our application.
->
-{type="note"}
-
-## Prime numbers with pipeline
-
-Let's take pipelines to the extreme with an example that generates prime numbers using a pipeline
-of coroutines. We start with an infinite sequence of numbers.
-
-```kotlin
-fun CoroutineScope.numbersFrom(start: Int) = produce<Int> {
- var x = start
- while (true) send(x++) // infinite stream of integers from start
-}
-```
-
-The following pipeline stage filters an incoming stream of numbers, removing all the numbers
-that are divisible by the given prime number:
-
-```kotlin
-fun CoroutineScope.filter(numbers: ReceiveChannel<Int>, prime: Int) = produce<Int> {
- for (x in numbers) if (x % prime != 0) send(x)
-}
-```
-
-Now we build our pipeline by starting a stream of numbers from 2, taking a prime number from the current channel,
-and launching new pipeline stage for each prime number found:
-
-```Plain Text
-numbersFrom(2) -> filter(2) -> filter(3) -> filter(5) -> filter(7) ...
-```
-
-The following example prints the first ten prime numbers,
-running the whole pipeline in the context of the main thread. Since all the coroutines are launched in
-the scope of the main [runBlocking] coroutine
-we don't have to keep an explicit list of all the coroutines we have started.
-We use [cancelChildren][kotlin.coroutines.CoroutineContext.cancelChildren]
-extension function to cancel all the children coroutines after we have printed
-the first ten prime numbers.
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-
-fun main() = runBlocking {
-//sampleStart
- var cur = numbersFrom(2)
- repeat(10) {
- val prime = cur.receive()
- println(prime)
- cur = filter(cur, prime)
- }
- coroutineContext.cancelChildren() // cancel all children to let main finish
-//sampleEnd
-}
-
-fun CoroutineScope.numbersFrom(start: Int) = produce<Int> {
- var x = start
- while (true) send(x++) // infinite stream of integers from start
-}
-
-fun CoroutineScope.filter(numbers: ReceiveChannel<Int>, prime: Int) = produce<Int> {
- for (x in numbers) if (x % prime != 0) send(x)
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-channel-05.kt).
->
-{type="note"}
-
-The output of this code is:
-
-```text
-2
-3
-5
-7
-11
-13
-17
-19
-23
-29
-```
-
-<!--- TEST -->
-
-Note that you can build the same pipeline using
-[`iterator`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/iterator.html)
-coroutine builder from the standard library.
-Replace `produce` with `iterator`, `send` with `yield`, `receive` with `next`,
-`ReceiveChannel` with `Iterator`, and get rid of the coroutine scope. You will not need `runBlocking` either.
-However, the benefit of a pipeline that uses channels as shown above is that it can actually use
-multiple CPU cores if you run it in [Dispatchers.Default] context.
-
-Anyway, this is an extremely impractical way to find prime numbers. In practice, pipelines do involve some
-other suspending invocations (like asynchronous calls to remote services) and these pipelines cannot be
-built using `sequence`/`iterator`, because they do not allow arbitrary suspension, unlike
-`produce`, which is fully asynchronous.
-
-## Fan-out
-
-Multiple coroutines may receive from the same channel, distributing work between themselves.
-Let us start with a producer coroutine that is periodically producing integers
-(ten numbers per second):
-
-```kotlin
-fun CoroutineScope.produceNumbers() = produce<Int> {
- var x = 1 // start from 1
- while (true) {
- send(x++) // produce next
- delay(100) // wait 0.1s
- }
-}
-```
-
-Then we can have several processor coroutines. In this example, they just print their id and
-received number:
-
-```kotlin
-fun CoroutineScope.launchProcessor(id: Int, channel: ReceiveChannel<Int>) = launch {
- for (msg in channel) {
- println("Processor #$id received $msg")
- }
-}
-```
-
-Now let us launch five processors and let them work for almost a second. See what happens:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val producer = produceNumbers()
- repeat(5) { launchProcessor(it, producer) }
- delay(950)
- producer.cancel() // cancel producer coroutine and thus kill them all
-//sampleEnd
-}
-
-fun CoroutineScope.produceNumbers() = produce<Int> {
- var x = 1 // start from 1
- while (true) {
- send(x++) // produce next
- delay(100) // wait 0.1s
- }
-}
-
-fun CoroutineScope.launchProcessor(id: Int, channel: ReceiveChannel<Int>) = launch {
- for (msg in channel) {
- println("Processor #$id received $msg")
- }
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-channel-06.kt).
->
-{type="note"}
-
-The output will be similar to the the following one, albeit the processor ids that receive
-each specific integer may be different:
-
-```text
-Processor #2 received 1
-Processor #4 received 2
-Processor #0 received 3
-Processor #1 received 4
-Processor #3 received 5
-Processor #2 received 6
-Processor #4 received 7
-Processor #0 received 8
-Processor #1 received 9
-Processor #3 received 10
-```
-
-<!--- TEST lines.size == 10 && lines.withIndex().all { (i, line) -> line.startsWith("Processor #") && line.endsWith(" received ${i + 1}") } -->
-
-Note that cancelling a producer coroutine closes its channel, thus eventually terminating iteration
-over the channel that processor coroutines are doing.
-
-Also, pay attention to how we explicitly iterate over channel with `for` loop to perform fan-out in `launchProcessor` code.
-Unlike `consumeEach`, this `for` loop pattern is perfectly safe to use from multiple coroutines. If one of the processor
-coroutines fails, then others would still be processing the channel, while a processor that is written via `consumeEach`
-always consumes (cancels) the underlying channel on its normal or abnormal completion.
-
-## Fan-in
-
-Multiple coroutines may send to the same channel.
-For example, let us have a channel of strings, and a suspending function that
-repeatedly sends a specified string to this channel with a specified delay:
-
-```kotlin
-suspend fun sendString(channel: SendChannel<String>, s: String, time: Long) {
- while (true) {
- delay(time)
- channel.send(s)
- }
-}
-```
-
-Now, let us see what happens if we launch a couple of coroutines sending strings
-(in this example we launch them in the context of the main thread as main coroutine's children):
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-
-fun main() = runBlocking {
-//sampleStart
- val channel = Channel<String>()
- launch { sendString(channel, "foo", 200L) }
- launch { sendString(channel, "BAR!", 500L) }
- repeat(6) { // receive first six
- println(channel.receive())
- }
- coroutineContext.cancelChildren() // cancel all children to let main finish
-//sampleEnd
-}
-
-suspend fun sendString(channel: SendChannel<String>, s: String, time: Long) {
- while (true) {
- delay(time)
- channel.send(s)
- }
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-channel-07.kt).
->
-{type="note"}
-
-The output is:
-
-```text
-foo
-foo
-BAR!
-foo
-foo
-BAR!
-```
-
-<!--- TEST -->
-
-## Buffered channels
-
-The channels shown so far had no buffer. Unbuffered channels transfer elements when sender and receiver
-meet each other (aka rendezvous). If send is invoked first, then it is suspended until receive is invoked,
-if receive is invoked first, it is suspended until send is invoked.
-
-Both [Channel()] factory function and [produce] builder take an optional `capacity` parameter to
-specify _buffer size_. Buffer allows senders to send multiple elements before suspending,
-similar to the `BlockingQueue` with a specified capacity, which blocks when buffer is full.
-
-Take a look at the behavior of the following code:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val channel = Channel<Int>(4) // create buffered channel
- val sender = launch { // launch sender coroutine
- repeat(10) {
- println("Sending $it") // print before sending each element
- channel.send(it) // will suspend when buffer is full
- }
- }
- // don't receive anything... just wait....
- delay(1000)
- sender.cancel() // cancel sender coroutine
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-channel-08.kt).
->
-{type="note"}
-
-It prints "sending" _five_ times using a buffered channel with capacity of _four_:
-
-```text
-Sending 0
-Sending 1
-Sending 2
-Sending 3
-Sending 4
-```
-
-<!--- TEST -->
-
-The first four elements are added to the buffer and the sender suspends when trying to send the fifth one.
-
-## Channels are fair
-
-Send and receive operations to channels are _fair_ with respect to the order of their invocation from
-multiple coroutines. They are served in first-in first-out order, e.g. the first coroutine to invoke `receive`
-gets the element. In the following example two coroutines "ping" and "pong" are
-receiving the "ball" object from the shared "table" channel.
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-
-//sampleStart
-data class Ball(var hits: Int)
-
-fun main() = runBlocking {
- val table = Channel<Ball>() // a shared table
- launch { player("ping", table) }
- launch { player("pong", table) }
- table.send(Ball(0)) // serve the ball
- delay(1000) // delay 1 second
- coroutineContext.cancelChildren() // game over, cancel them
-}
-
-suspend fun player(name: String, table: Channel<Ball>) {
- for (ball in table) { // receive the ball in a loop
- ball.hits++
- println("$name $ball")
- delay(300) // wait a bit
- table.send(ball) // send the ball back
- }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-channel-09.kt).
->
-{type="note"}
-
-The "ping" coroutine is started first, so it is the first one to receive the ball. Even though "ping"
-coroutine immediately starts receiving the ball again after sending it back to the table, the ball gets
-received by the "pong" coroutine, because it was already waiting for it:
-
-```text
-ping Ball(hits=1)
-pong Ball(hits=2)
-ping Ball(hits=3)
-pong Ball(hits=4)
-```
-
-<!--- TEST -->
-
-Note that sometimes channels may produce executions that look unfair due to the nature of the executor
-that is being used. See [this issue](https://github.com/Kotlin/kotlinx.coroutines/issues/111) for details.
-
-## Ticker channels
-
-Ticker channel is a special rendezvous channel that produces `Unit` every time given delay passes since last consumption from this channel.
-Though it may seem to be useless standalone, it is a useful building block to create complex time-based [produce]
-pipelines and operators that do windowing and other time-dependent processing.
-Ticker channel can be used in [select] to perform "on tick" action.
-
-To create such channel use a factory method [ticker].
-To indicate that no further elements are needed use [ReceiveChannel.cancel] method on it.
-
-Now let's see how it works in practice:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-
-fun main() = runBlocking<Unit> {
- val tickerChannel = ticker(delayMillis = 100, initialDelayMillis = 0) // create ticker channel
- var nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
- println("Initial element is available immediately: $nextElement") // no initial delay
-
- nextElement = withTimeoutOrNull(50) { tickerChannel.receive() } // all subsequent elements have 100ms delay
- println("Next element is not ready in 50 ms: $nextElement")
-
- nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
- println("Next element is ready in 100 ms: $nextElement")
-
- // Emulate large consumption delays
- println("Consumer pauses for 150ms")
- delay(150)
- // Next element is available immediately
- nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
- println("Next element is available immediately after large consumer delay: $nextElement")
- // Note that the pause between `receive` calls is taken into account and next element arrives faster
- nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
- println("Next element is ready in 50ms after consumer pause in 150ms: $nextElement")
-
- tickerChannel.cancel() // indicate that no more elements are needed
-}
-```
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-channel-10.kt).
->
-{type="note"}
-
-It prints following lines:
-
-```text
-Initial element is available immediately: kotlin.Unit
-Next element is not ready in 50 ms: null
-Next element is ready in 100 ms: kotlin.Unit
-Consumer pauses for 150ms
-Next element is available immediately after large consumer delay: kotlin.Unit
-Next element is ready in 50ms after consumer pause in 150ms: kotlin.Unit
-```
-
-<!--- TEST -->
-
-Note that [ticker] is aware of possible consumer pauses and, by default, adjusts next produced element
-delay if a pause occurs, trying to maintain a fixed rate of produced elements.
-
-Optionally, a `mode` parameter equal to [TickerMode.FIXED_DELAY] can be specified to maintain a fixed
-delay between elements.
-
-<!--- MODULE kotlinx-coroutines-core -->
-<!--- INDEX kotlinx.coroutines -->
-
-[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
-[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
-[kotlin.coroutines.CoroutineContext.cancelChildren]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/kotlin.coroutines.-coroutine-context/cancel-children.html
-[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html
-
-<!--- INDEX kotlinx.coroutines.channels -->
-
-[Channel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel/index.html
-[SendChannel.send]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/send.html
-[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive.html
-[SendChannel.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/close.html
-[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/produce.html
-[consumeEach]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/consume-each.html
-[Channel()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel.html
-[ticker]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/ticker.html
-[ReceiveChannel.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/cancel.html
-[TickerMode.FIXED_DELAY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-ticker-mode/-f-i-x-e-d_-d-e-l-a-y.html
-
-<!--- INDEX kotlinx.coroutines.selects -->
-
-[select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html
-
-<!--- END -->
diff --git a/docs/topics/compatibility.md b/docs/topics/compatibility.md
deleted file mode 100644
index a9414432..00000000
--- a/docs/topics/compatibility.md
+++ /dev/null
@@ -1,129 +0,0 @@
-<!--- TOC -->
-
-* [Compatibility](#compatibility)
-* [Public API types](#public-api-types)
- * [Experimental API](#experimental-api)
- * [Flow preview API](#flow-preview-api)
- * [Obsolete API](#obsolete-api)
- * [Internal API](#internal-api)
- * [Stable API](#stable-api)
- * [Deprecation cycle](#deprecation-cycle)
-* [Using annotated API](#using-annotated-api)
- * [Programmatically](#programmatically)
- * [Gradle](#gradle)
- * [Maven](#maven)
-
-<!--- END -->
-
-## Compatibility
-This document describes the compatibility policy of `kotlinx.coroutines` library since version 1.0.0 and semantics of compatibility-specific annotations.
-
-
-## Public API types
-`kotlinx.coroutines` public API comes in five flavours: stable, experimental, obsolete, internal and deprecated.
-All public API except stable is marked with the corresponding annotation.
-
-### Experimental API
-Experimental API is marked with [@ExperimentalCoroutinesApi][ExperimentalCoroutinesApi] annotation.
-API is marked experimental when its design has potential open questions which may eventually lead to
-either semantics changes of the API or its deprecation.
-
-By default, most of the new API is marked as experimental and becomes stable in one of the next major releases if no new issues arise.
-Otherwise, either semantics is fixed without changes in ABI or API goes through deprecation cycle.
-
-When using experimental API may be dangerous:
-* You are writing a library which depends on `kotlinx.coroutines` and want to use experimental coroutines API in a stable library API.
-It may lead to undesired consequences when end users of your library update their `kotlinx.coroutines` version where experimental API
-has slightly different semantics.
-* You want to build core infrastructure of the application around experimental API.
-
-### Flow preview API
-All [Flow]-related API is marked with [@FlowPreview][FlowPreview] annotation.
-This annotation indicates that Flow API is in preview status.
-We provide no compatibility guarantees between releases for preview features, including binary, source and semantics compatibility.
-
-When using preview API may be dangerous:
-* You are writing a library/framework and want to use [Flow] API in a stable release or in a stable API.
-* You want to use [Flow] in the core infrastructure of your application.
-* You want to use [Flow] as "write-and-forget" solution and cannot afford additional maintenance cost when
- it comes to `kotlinx.coroutines` updates.
-
-
-### Obsolete API
-Obsolete API is marked with [@ObsoleteCoroutinesApi][ObsoleteCoroutinesApi] annotation.
-Obsolete API is similar to experimental, but already known to have serious design flaws and its potential replacement,
-but replacement is not yet implemented.
-
-The semantics of this API won't be changed, but it will go through a deprecation cycle as soon as the replacement is ready.
-
-### Internal API
-Internal API is marked with [@InternalCoroutinesApi][InternalCoroutinesApi] or is part of `kotlinx.coroutines.internal` package.
-This API has no guarantees on its stability, can and will be changed and/or removed in the future releases.
-If you can't avoid using internal API, please report it to [issue tracker](https://github.com/Kotlin/kotlinx.coroutines/issues/new).
-
-### Stable API
-Stable API is guaranteed to preserve its ABI and documented semantics. If at some point unfixable design flaws will be discovered,
-this API will go through a deprecation cycle and remain binary compatible as long as possible.
-
-### Deprecation cycle
-When some API is deprecated, it goes through multiple stages and there is at least one major release between stages.
-* Feature is deprecated with compilation warning. Most of the time, proper replacement
-(and corresponding `replaceWith` declaration) is provided to automatically migrate deprecated usages with a help of IntelliJ IDEA.
-* Deprecation level is increased to `error` or `hidden`. It is no longer possible to compile new code against deprecated API,
- though it is still present in the ABI.
-* API is completely removed. While we give our best efforts not to do so and have no plans of removing any API, we still are leaving
-this option in case of unforeseen problems such as security holes.
-
-## Using annotated API
-All API annotations are [kotlin.Experimental](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-experimental/index.html).
-It is done in order to produce compilation warning about using experimental or obsolete API.
-Warnings can be disabled either programmatically for a specific call site or globally for the whole module.
-
-### Programmatically
-For a specific call-site, warning can be disabled by using [UseExperimental](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-use-experimental/index.html) annotation:
-```kotlin
-@UseExperimental(ExperimentalCoroutinesApi::class) // Disables warning about experimental coroutines API
-fun experimentalApiUsage() {
- someKotlinxCoroutinesExperimentalMethod()
-}
-```
-
-### Gradle
-For the Gradle project, a warning can be disabled by passing a compiler flag in your `build.gradle` file:
-
-```groovy
-tasks.withType(org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile).all {
- kotlinOptions.freeCompilerArgs += ["-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi"]
-}
-
-```
-
-### Maven
-For the Maven project, a warning can be disabled by passing a compiler flag in your `pom.xml` file:
-```xml
-<plugin>
- <artifactId>kotlin-maven-plugin</artifactId>
- <groupId>org.jetbrains.kotlin</groupId>
- ... your configuration ...
- <configuration>
- <args>
- <arg>-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi</arg>
- </args>
- </configuration>
-</plugin>
-```
-
-
-<!--- MODULE kotlinx-coroutines-core -->
-<!--- INDEX kotlinx.coroutines.flow -->
-
-[Flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html
-
-<!--- INDEX kotlinx.coroutines -->
-
-[ExperimentalCoroutinesApi]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-experimental-coroutines-api/index.html
-[FlowPreview]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-flow-preview/index.html
-[ObsoleteCoroutinesApi]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-obsolete-coroutines-api/index.html
-[InternalCoroutinesApi]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-internal-coroutines-api/index.html
-
-<!--- END -->
diff --git a/docs/topics/composing-suspending-functions.md b/docs/topics/composing-suspending-functions.md
deleted file mode 100644
index 0af60d00..00000000
--- a/docs/topics/composing-suspending-functions.md
+++ /dev/null
@@ -1,406 +0,0 @@
-<!--- TEST_NAME ComposingGuideTest -->
-
-[//]: # (title: Composing suspending functions)
-
-This section covers various approaches to composition of suspending functions.
-
-## Sequential by default
-
-Assume that we have two suspending functions defined elsewhere that do something useful like some kind of
-remote service call or computation. We just pretend they are useful, but actually each one just
-delays for a second for the purpose of this example:
-
-```kotlin
-suspend fun doSomethingUsefulOne(): Int {
- delay(1000L) // pretend we are doing something useful here
- return 13
-}
-
-suspend fun doSomethingUsefulTwo(): Int {
- delay(1000L) // pretend we are doing something useful here, too
- return 29
-}
-```
-
-What do we do if we need them to be invoked _sequentially_ &mdash; first `doSomethingUsefulOne` _and then_
-`doSomethingUsefulTwo`, and compute the sum of their results?
-In practice we do this if we use the result of the first function to make a decision on whether we need
-to invoke the second one or to decide on how to invoke it.
-
-We use a normal sequential invocation, because the code in the coroutine, just like in the regular
-code, is _sequential_ by default. The following example demonstrates it by measuring the total
-time it takes to execute both suspending functions:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlin.system.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val time = measureTimeMillis {
- val one = doSomethingUsefulOne()
- val two = doSomethingUsefulTwo()
- println("The answer is ${one + two}")
- }
- println("Completed in $time ms")
-//sampleEnd
-}
-
-suspend fun doSomethingUsefulOne(): Int {
- delay(1000L) // pretend we are doing something useful here
- return 13
-}
-
-suspend fun doSomethingUsefulTwo(): Int {
- delay(1000L) // pretend we are doing something useful here, too
- return 29
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-compose-01.kt).
->
-{type="note"}
-
-It produces something like this:
-
-```text
-The answer is 42
-Completed in 2017 ms
-```
-
-<!--- TEST ARBITRARY_TIME -->
-
-## Concurrent using async
-
-What if there are no dependencies between invocations of `doSomethingUsefulOne` and `doSomethingUsefulTwo` and
-we want to get the answer faster, by doing both _concurrently_? This is where [async] comes to help.
-
-Conceptually, [async] is just like [launch]. It starts a separate coroutine which is a light-weight thread
-that works concurrently with all the other coroutines. The difference is that `launch` returns a [Job] and
-does not carry any resulting value, while `async` returns a [Deferred] &mdash; a light-weight non-blocking future
-that represents a promise to provide a result later. You can use `.await()` on a deferred value to get its eventual result,
-but `Deferred` is also a `Job`, so you can cancel it if needed.
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlin.system.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val time = measureTimeMillis {
- val one = async { doSomethingUsefulOne() }
- val two = async { doSomethingUsefulTwo() }
- println("The answer is ${one.await() + two.await()}")
- }
- println("Completed in $time ms")
-//sampleEnd
-}
-
-suspend fun doSomethingUsefulOne(): Int {
- delay(1000L) // pretend we are doing something useful here
- return 13
-}
-
-suspend fun doSomethingUsefulTwo(): Int {
- delay(1000L) // pretend we are doing something useful here, too
- return 29
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-compose-02.kt).
->
-{type="note"}
-
-It produces something like this:
-
-```text
-The answer is 42
-Completed in 1017 ms
-```
-
-<!--- TEST ARBITRARY_TIME -->
-
-This is twice as fast, because the two coroutines execute concurrently.
-Note that concurrency with coroutines is always explicit.
-
-## Lazily started async
-
-Optionally, [async] can be made lazy by setting its `start` parameter to [CoroutineStart.LAZY].
-In this mode it only starts the coroutine when its result is required by
-[await][Deferred.await], or if its `Job`'s [start][Job.start] function
-is invoked. Run the following example:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlin.system.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val time = measureTimeMillis {
- val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
- val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
- // some computation
- one.start() // start the first one
- two.start() // start the second one
- println("The answer is ${one.await() + two.await()}")
- }
- println("Completed in $time ms")
-//sampleEnd
-}
-
-suspend fun doSomethingUsefulOne(): Int {
- delay(1000L) // pretend we are doing something useful here
- return 13
-}
-
-suspend fun doSomethingUsefulTwo(): Int {
- delay(1000L) // pretend we are doing something useful here, too
- return 29
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-compose-03.kt).
->
-{type="note"}
-
-It produces something like this:
-
-```text
-The answer is 42
-Completed in 1017 ms
-```
-
-<!--- TEST ARBITRARY_TIME -->
-
-So, here the two coroutines are defined but not executed as in the previous example, but the control is given to
-the programmer on when exactly to start the execution by calling [start][Job.start]. We first
-start `one`, then start `two`, and then await for the individual coroutines to finish.
-
-Note that if we just call [await][Deferred.await] in `println` without first calling [start][Job.start] on individual
-coroutines, this will lead to sequential behavior, since [await][Deferred.await] starts the coroutine
-execution and waits for its finish, which is not the intended use-case for laziness.
-The use-case for `async(start = CoroutineStart.LAZY)` is a replacement for the
-standard `lazy` function in cases when computation of the value involves suspending functions.
-
-## Async-style functions
-
-We can define async-style functions that invoke `doSomethingUsefulOne` and `doSomethingUsefulTwo`
-_asynchronously_ using the [async] coroutine builder with an explicit [GlobalScope] reference.
-We name such functions with the
-"...Async" suffix to highlight the fact that they only start asynchronous computation and one needs
-to use the resulting deferred value to get the result.
-
-```kotlin
-// The result type of somethingUsefulOneAsync is Deferred<Int>
-fun somethingUsefulOneAsync() = GlobalScope.async {
- doSomethingUsefulOne()
-}
-
-// The result type of somethingUsefulTwoAsync is Deferred<Int>
-fun somethingUsefulTwoAsync() = GlobalScope.async {
- doSomethingUsefulTwo()
-}
-```
-
-Note that these `xxxAsync` functions are **not** _suspending_ functions. They can be used from anywhere.
-However, their use always implies asynchronous (here meaning _concurrent_) execution of their action
-with the invoking code.
-
-The following example shows their use outside of coroutine:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlin.system.*
-
-//sampleStart
-// note that we don't have `runBlocking` to the right of `main` in this example
-fun main() {
- val time = measureTimeMillis {
- // we can initiate async actions outside of a coroutine
- val one = somethingUsefulOneAsync()
- val two = somethingUsefulTwoAsync()
- // but waiting for a result must involve either suspending or blocking.
- // here we use `runBlocking { ... }` to block the main thread while waiting for the result
- runBlocking {
- println("The answer is ${one.await() + two.await()}")
- }
- }
- println("Completed in $time ms")
-}
-//sampleEnd
-
-fun somethingUsefulOneAsync() = GlobalScope.async {
- doSomethingUsefulOne()
-}
-
-fun somethingUsefulTwoAsync() = GlobalScope.async {
- doSomethingUsefulTwo()
-}
-
-suspend fun doSomethingUsefulOne(): Int {
- delay(1000L) // pretend we are doing something useful here
- return 13
-}
-
-suspend fun doSomethingUsefulTwo(): Int {
- delay(1000L) // pretend we are doing something useful here, too
- return 29
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-compose-04.kt).
->
-{type="note"}
-
-<!--- TEST ARBITRARY_TIME
-The answer is 42
-Completed in 1085 ms
--->
-
-> This programming style with async functions is provided here only for illustration, because it is a popular style
-> in other programming languages. Using this style with Kotlin coroutines is **strongly discouraged** for the
-> reasons explained below.
->
-{type="note"}
-
-Consider what happens if between the `val one = somethingUsefulOneAsync()` line and `one.await()` expression there is some logic
-error in the code and the program throws an exception and the operation that was being performed by the program aborts.
-Normally, a global error-handler could catch this exception, log and report the error for developers, but the program
-could otherwise continue doing other operations. But here we have `somethingUsefulOneAsync` still running in the background,
-even though the operation that initiated it was aborted. This problem does not happen with structured
-concurrency, as shown in the section below.
-
-## Structured concurrency with async
-
-Let us take the [Concurrent using async](#concurrent-using-async) example and extract a function that
-concurrently performs `doSomethingUsefulOne` and `doSomethingUsefulTwo` and returns the sum of their results.
-Because the [async] coroutine builder is defined as an extension on [CoroutineScope], we need to have it in the
-scope and that is what the [coroutineScope][_coroutineScope] function provides:
-
-```kotlin
-suspend fun concurrentSum(): Int = coroutineScope {
- val one = async { doSomethingUsefulOne() }
- val two = async { doSomethingUsefulTwo() }
- one.await() + two.await()
-}
-```
-
-This way, if something goes wrong inside the code of the `concurrentSum` function and it throws an exception,
-all the coroutines that were launched in its scope will be cancelled.
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlin.system.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val time = measureTimeMillis {
- println("The answer is ${concurrentSum()}")
- }
- println("Completed in $time ms")
-//sampleEnd
-}
-
-suspend fun concurrentSum(): Int = coroutineScope {
- val one = async { doSomethingUsefulOne() }
- val two = async { doSomethingUsefulTwo() }
- one.await() + two.await()
-}
-
-suspend fun doSomethingUsefulOne(): Int {
- delay(1000L) // pretend we are doing something useful here
- return 13
-}
-
-suspend fun doSomethingUsefulTwo(): Int {
- delay(1000L) // pretend we are doing something useful here, too
- return 29
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-compose-05.kt).
->
-{type="note"}
-
-We still have concurrent execution of both operations, as evident from the output of the above `main` function:
-
-```text
-The answer is 42
-Completed in 1017 ms
-```
-
-<!--- TEST ARBITRARY_TIME -->
-
-Cancellation is always propagated through coroutines hierarchy:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking<Unit> {
- try {
- failedConcurrentSum()
- } catch(e: ArithmeticException) {
- println("Computation failed with ArithmeticException")
- }
-}
-
-suspend fun failedConcurrentSum(): Int = coroutineScope {
- val one = async<Int> {
- try {
- delay(Long.MAX_VALUE) // Emulates very long computation
- 42
- } finally {
- println("First child was cancelled")
- }
- }
- val two = async<Int> {
- println("Second child throws an exception")
- throw ArithmeticException()
- }
- one.await() + two.await()
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-compose-06.kt).
->
-{type="note"}
-
-Note how both the first `async` and the awaiting parent are cancelled on failure of one of the children
-(namely, `two`):
-```text
-Second child throws an exception
-First child was cancelled
-Computation failed with ArithmeticException
-```
-
-<!--- TEST -->
-
-<!--- MODULE kotlinx-coroutines-core -->
-<!--- INDEX kotlinx.coroutines -->
-
-[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
-[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
-[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
-[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html
-[CoroutineStart.LAZY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/-l-a-z-y.html
-[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/await.html
-[Job.start]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/start.html
-[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
-[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
-[_coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
-
-<!--- END --> \ No newline at end of file
diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md
deleted file mode 100644
index 9aae1a7a..00000000
--- a/docs/topics/coroutine-context-and-dispatchers.md
+++ /dev/null
@@ -1,681 +0,0 @@
-<!--- TEST_NAME DispatcherGuideTest -->
-
-[//]: # (title: Coroutine context and dispatchers)
-
-Coroutines always execute in some context represented by a value of the
-[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/)
-type, defined in the Kotlin standard library.
-
-The coroutine context is a set of various elements. The main elements are the [Job] of the coroutine,
-which we've seen before, and its dispatcher, which is covered in this section.
-
-## Dispatchers and threads
-
-The coroutine context includes a _coroutine dispatcher_ (see [CoroutineDispatcher]) that determines what thread or threads
-the corresponding coroutine uses for its execution. The coroutine dispatcher can confine coroutine execution
-to a specific thread, dispatch it to a thread pool, or let it run unconfined.
-
-All coroutine builders like [launch] and [async] accept an optional
-[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/)
-parameter that can be used to explicitly specify the dispatcher for the new coroutine and other context elements.
-
-Try the following example:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- launch { // context of the parent, main runBlocking coroutine
- println("main runBlocking : I'm working in thread ${Thread.currentThread().name}")
- }
- launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
- println("Unconfined : I'm working in thread ${Thread.currentThread().name}")
- }
- launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher
- println("Default : I'm working in thread ${Thread.currentThread().name}")
- }
- launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
- println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
- }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-context-01.kt).
->
-{type="note"}
-
-It produces the following output (maybe in different order):
-
-```text
-Unconfined : I'm working in thread main
-Default : I'm working in thread DefaultDispatcher-worker-1
-newSingleThreadContext: I'm working in thread MyOwnThread
-main runBlocking : I'm working in thread main
-```
-
-<!--- TEST LINES_START_UNORDERED -->
-
-When `launch { ... }` is used without parameters, it inherits the context (and thus dispatcher)
-from the [CoroutineScope] it is being launched from. In this case, it inherits the
-context of the main `runBlocking` coroutine which runs in the `main` thread.
-
-[Dispatchers.Unconfined] is a special dispatcher that also appears to run in the `main` thread, but it is,
-in fact, a different mechanism that is explained later.
-
-The default dispatcher that is used when coroutines are launched in [GlobalScope]
-is represented by [Dispatchers.Default] and uses a shared background pool of threads,
-so `launch(Dispatchers.Default) { ... }` uses the same dispatcher as `GlobalScope.launch { ... }`.
-
-[newSingleThreadContext] creates a thread for the coroutine to run.
-A dedicated thread is a very expensive resource.
-In a real application it must be either released, when no longer needed, using the [close][ExecutorCoroutineDispatcher.close]
-function, or stored in a top-level variable and reused throughout the application.
-
-## Unconfined vs confined dispatcher
-
-The [Dispatchers.Unconfined] coroutine dispatcher starts a coroutine in the caller thread, but only until the
-first suspension point. After suspension it resumes the coroutine in the thread that is fully determined by the
-suspending function that was invoked. The unconfined dispatcher is appropriate for coroutines which neither
-consume CPU time nor update any shared data (like UI) confined to a specific thread.
-
-On the other side, the dispatcher is inherited from the outer [CoroutineScope] by default.
-The default dispatcher for the [runBlocking] coroutine, in particular,
-is confined to the invoker thread, so inheriting it has the effect of confining execution to
-this thread with predictable FIFO scheduling.
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
- println("Unconfined : I'm working in thread ${Thread.currentThread().name}")
- delay(500)
- println("Unconfined : After delay in thread ${Thread.currentThread().name}")
- }
- launch { // context of the parent, main runBlocking coroutine
- println("main runBlocking: I'm working in thread ${Thread.currentThread().name}")
- delay(1000)
- println("main runBlocking: After delay in thread ${Thread.currentThread().name}")
- }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-context-02.kt).
->
-{type="note"}
-
-Produces the output:
-
-```text
-Unconfined : I'm working in thread main
-main runBlocking: I'm working in thread main
-Unconfined : After delay in thread kotlinx.coroutines.DefaultExecutor
-main runBlocking: After delay in thread main
-```
-
-<!--- TEST LINES_START -->
-
-So, the coroutine with the context inherited from `runBlocking {...}` continues to execute
-in the `main` thread, while the unconfined one resumes in the default executor thread that the [delay]
-function is using.
-
-> The unconfined dispatcher is an advanced mechanism that can be helpful in certain corner cases where
-> dispatching of a coroutine for its execution later is not needed or produces undesirable side-effects,
-> because some operation in a coroutine must be performed right away.
-> The unconfined dispatcher should not be used in general code.
->
-{type="note"}
-
-## Debugging coroutines and threads
-
-Coroutines can suspend on one thread and resume on another thread.
-Even with a single-threaded dispatcher it might be hard to
-figure out what the coroutine was doing, where, and when if you don't have special tooling.
-
-### Debugging with IDEA
-
-The Coroutine Debugger of the Kotlin plugin simplifies debugging coroutines in IntelliJ IDEA.
-
-> Debugging works for versions 1.3.8 or later of `kotlinx-coroutines-core`.
->
-{type="note"}
-
-The **Debug** tool window contains the **Coroutines** tab. In this tab, you can find information about both currently running and suspended coroutines.
-The coroutines are grouped by the dispatcher they are running on.
-
-![Debugging coroutines](coroutine-idea-debugging-1.png)
-
-With the coroutine debugger, you can:
-* Check the state of each coroutine.
-* See the values of local and captured variables for both running and suspended coroutines.
-* See a full coroutine creation stack, as well as a call stack inside the coroutine. The stack includes all frames with
-variable values, even those that would be lost during standard debugging.
-* Get a full report that contains the state of each coroutine and its stack. To obtain it, right-click inside the **Coroutines** tab, and then click **Get Coroutines Dump**.
-
-To start coroutine debugging, you just need to set breakpoints and run the application in debug mode.
-
-Learn more about coroutines debugging in the [tutorial](https://kotlinlang.org/docs/tutorials/coroutines/debug-coroutines-with-idea.html).
-
-### Debugging using logging
-
-Another approach to debugging applications with
-threads without Coroutine Debugger is to print the thread name in the log file on each log statement. This feature is universally supported
-by logging frameworks. When using coroutines, the thread name alone does not give much of a context, so
-`kotlinx.coroutines` includes debugging facilities to make it easier.
-
-Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val a = async {
- log("I'm computing a piece of the answer")
- 6
- }
- val b = async {
- log("I'm computing another piece of the answer")
- 7
- }
- log("The answer is ${a.await() * b.await()}")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-context-03.kt).
->
-{type="note"}
-
-There are three coroutines. The main coroutine (#1) inside `runBlocking`
-and two coroutines computing the deferred values `a` (#2) and `b` (#3).
-They are all executing in the context of `runBlocking` and are confined to the main thread.
-The output of this code is:
-
-```text
-[main @coroutine#2] I'm computing a piece of the answer
-[main @coroutine#3] I'm computing another piece of the answer
-[main @coroutine#1] The answer is 42
-```
-
-<!--- TEST FLEXIBLE_THREAD -->
-
-The `log` function prints the name of the thread in square brackets, and you can see that it is the `main`
-thread with the identifier of the currently executing coroutine appended to it. This identifier
-is consecutively assigned to all created coroutines when the debugging mode is on.
-
-> Debugging mode is also turned on when JVM is run with `-ea` option.
-> You can read more about debugging facilities in the documentation of the [DEBUG_PROPERTY_NAME] property.
->
-{type="note"}
-
-## Jumping between threads
-
-Run the following code with the `-Dkotlinx.coroutines.debug` JVM option (see [debug](#debugging-coroutines-and-threads)):
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
-
-fun main() {
-//sampleStart
- newSingleThreadContext("Ctx1").use { ctx1 ->
- newSingleThreadContext("Ctx2").use { ctx2 ->
- runBlocking(ctx1) {
- log("Started in ctx1")
- withContext(ctx2) {
- log("Working in ctx2")
- }
- log("Back to ctx1")
- }
- }
- }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-context-04.kt).
->
-{type="note"}
-
-It demonstrates several new techniques. One is using [runBlocking] with an explicitly specified context, and
-the other one is using the [withContext] function to change the context of a coroutine while still staying in the
-same coroutine, as you can see in the output below:
-
-```text
-[Ctx1 @coroutine#1] Started in ctx1
-[Ctx2 @coroutine#1] Working in ctx2
-[Ctx1 @coroutine#1] Back to ctx1
-```
-
-<!--- TEST -->
-
-Note that this example also uses the `use` function from the Kotlin standard library to release threads
-created with [newSingleThreadContext] when they are no longer needed.
-
-## Job in the context
-
-The coroutine's [Job] is part of its context, and can be retrieved from it
-using the `coroutineContext[Job]` expression:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- println("My job is ${coroutineContext[Job]}")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-context-05.kt).
->
-{type="note"}
-
-In the [debug mode](#debugging-coroutines-and-threads), it outputs something like this:
-
-```
-My job is "coroutine#1":BlockingCoroutine{Active}@6d311334
-```
-
-<!--- TEST lines.size == 1 && lines[0].startsWith("My job is \"coroutine#1\":BlockingCoroutine{Active}@") -->
-
-Note that [isActive] in [CoroutineScope] is just a convenient shortcut for
-`coroutineContext[Job]?.isActive == true`.
-
-## Children of a coroutine
-
-When a coroutine is launched in the [CoroutineScope] of another coroutine,
-it inherits its context via [CoroutineScope.coroutineContext] and
-the [Job] of the new coroutine becomes
-a _child_ of the parent coroutine's job. When the parent coroutine is cancelled, all its children
-are recursively cancelled, too.
-
-However, when [GlobalScope] is used to launch a coroutine, there is no parent for the job of the new coroutine.
-It is therefore not tied to the scope it was launched from and operates independently.
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- // launch a coroutine to process some kind of incoming request
- val request = launch {
- // it spawns two other jobs, one with GlobalScope
- GlobalScope.launch {
- println("job1: I run in GlobalScope and execute independently!")
- delay(1000)
- println("job1: I am not affected by cancellation of the request")
- }
- // and the other inherits the parent context
- launch {
- delay(100)
- println("job2: I am a child of the request coroutine")
- delay(1000)
- println("job2: I will not execute this line if my parent request is cancelled")
- }
- }
- delay(500)
- request.cancel() // cancel processing of the request
- delay(1000) // delay a second to see what happens
- println("main: Who has survived request cancellation?")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-context-06.kt).
->
-{type="note"}
-
-The output of this code is:
-
-```text
-job1: I run in GlobalScope and execute independently!
-job2: I am a child of the request coroutine
-job1: I am not affected by cancellation of the request
-main: Who has survived request cancellation?
-```
-
-<!--- TEST -->
-
-## Parental responsibilities
-
-A parent coroutine always waits for completion of all its children. A parent does not have to explicitly track
-all the children it launches, and it does not have to use [Job.join] to wait for them at the end:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- // launch a coroutine to process some kind of incoming request
- val request = launch {
- repeat(3) { i -> // launch a few children jobs
- launch {
- delay((i + 1) * 200L) // variable delay 200ms, 400ms, 600ms
- println("Coroutine $i is done")
- }
- }
- println("request: I'm done and I don't explicitly join my children that are still active")
- }
- request.join() // wait for completion of the request, including all its children
- println("Now processing of the request is complete")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-context-07.kt).
->
-{type="note"}
-
-The result is going to be:
-
-```text
-request: I'm done and I don't explicitly join my children that are still active
-Coroutine 0 is done
-Coroutine 1 is done
-Coroutine 2 is done
-Now processing of the request is complete
-```
-
-<!--- TEST -->
-
-## Naming coroutines for debugging
-
-Automatically assigned ids are good when coroutines log often and you just need to correlate log records
-coming from the same coroutine. However, when a coroutine is tied to the processing of a specific request
-or doing some specific background task, it is better to name it explicitly for debugging purposes.
-The [CoroutineName] context element serves the same purpose as the thread name. It is included in the thread name that
-is executing this coroutine when the [debugging mode](#debugging-coroutines-and-threads) is turned on.
-
-The following example demonstrates this concept:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
-
-fun main() = runBlocking(CoroutineName("main")) {
-//sampleStart
- log("Started main coroutine")
- // run two background value computations
- val v1 = async(CoroutineName("v1coroutine")) {
- delay(500)
- log("Computing v1")
- 252
- }
- val v2 = async(CoroutineName("v2coroutine")) {
- delay(1000)
- log("Computing v2")
- 6
- }
- log("The answer for v1 / v2 = ${v1.await() / v2.await()}")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-context-08.kt).
->
-{type="note"}
-
-The output it produces with `-Dkotlinx.coroutines.debug` JVM option is similar to:
-
-```text
-[main @main#1] Started main coroutine
-[main @v1coroutine#2] Computing v1
-[main @v2coroutine#3] Computing v2
-[main @main#1] The answer for v1 / v2 = 42
-```
-
-<!--- TEST FLEXIBLE_THREAD -->
-
-## Combining context elements
-
-Sometimes we need to define multiple elements for a coroutine context. We can use the `+` operator for that.
-For example, we can launch a coroutine with an explicitly specified dispatcher and an explicitly specified
-name at the same time:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- launch(Dispatchers.Default + CoroutineName("test")) {
- println("I'm working in thread ${Thread.currentThread().name}")
- }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-context-09.kt).
->
-{type="note"}
-
-The output of this code with the `-Dkotlinx.coroutines.debug` JVM option is:
-
-```text
-I'm working in thread DefaultDispatcher-worker-1 @test#2
-```
-
-<!--- TEST FLEXIBLE_THREAD -->
-
-## Coroutine scope
-
-Let us put our knowledge about contexts, children and jobs together. Assume that our application has
-an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application
-and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch
-and update data, do animations, etc. All of these coroutines must be cancelled when the activity is destroyed
-to avoid memory leaks. We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity
-and its coroutines, but `kotlinx.coroutines` provides an abstraction encapsulating that: [CoroutineScope].
-You should be already familiar with the coroutine scope as all coroutine builders are declared as extensions on it.
-
-We manage the lifecycles of our coroutines by creating an instance of [CoroutineScope] tied to
-the lifecycle of our activity. A `CoroutineScope` instance can be created by the [CoroutineScope()] or [MainScope()]
-factory functions. The former creates a general-purpose scope, while the latter creates a scope for UI applications and uses
-[Dispatchers.Main] as the default dispatcher:
-
-```kotlin
-class Activity {
- private val mainScope = MainScope()
-
- fun destroy() {
- mainScope.cancel()
- }
- // to be continued ...
-```
-
-Now, we can launch coroutines in the scope of this `Activity` using the defined `scope`.
-For the demo, we launch ten coroutines that delay for a different time:
-
-```kotlin
- // class Activity continues
- fun doSomething() {
- // launch ten coroutines for a demo, each working for a different time
- repeat(10) { i ->
- mainScope.launch {
- delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
- println("Coroutine $i is done")
- }
- }
- }
-} // class Activity ends
-```
-
-In our main function we create the activity, call our test `doSomething` function, and destroy the activity after 500ms.
-This cancels all the coroutines that were launched from `doSomething`. We can see that because after the destruction
-of the activity no more messages are printed, even if we wait a little longer.
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-
-class Activity {
- private val mainScope = CoroutineScope(Dispatchers.Default) // use Default for test purposes
-
- fun destroy() {
- mainScope.cancel()
- }
-
- fun doSomething() {
- // launch ten coroutines for a demo, each working for a different time
- repeat(10) { i ->
- mainScope.launch {
- delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
- println("Coroutine $i is done")
- }
- }
- }
-} // class Activity ends
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val activity = Activity()
- activity.doSomething() // run test function
- println("Launched coroutines")
- delay(500L) // delay for half a second
- println("Destroying activity!")
- activity.destroy() // cancels all coroutines
- delay(1000) // visually confirm that they don't work
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-context-10.kt).
->
-{type="note"}
-
-The output of this example is:
-
-```text
-Launched coroutines
-Coroutine 0 is done
-Coroutine 1 is done
-Destroying activity!
-```
-
-<!--- TEST -->
-
-As you can see, only the first two coroutines print a message and the others are cancelled
-by a single invocation of `job.cancel()` in `Activity.destroy()`.
-
-> Note, that Android has first-party support for coroutine scope in all entities with the lifecycle.
-> See [the corresponding documentation](https://developer.android.com/topic/libraries/architecture/coroutines#lifecyclescope).
->
-{type="note"}
-
-### Thread-local data
-
-Sometimes it is convenient to have an ability to pass some thread-local data to or between coroutines.
-However, since they are not bound to any particular thread, this will likely lead to boilerplate if done manually.
-
-For [`ThreadLocal`](https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html),
-the [asContextElement] extension function is here for the rescue. It creates an additional context element
-which keeps the value of the given `ThreadLocal` and restores it every time the coroutine switches its context.
-
-It is easy to demonstrate it in action:
-
-```kotlin
-import kotlinx.coroutines.*
-
-val threadLocal = ThreadLocal<String?>() // declare thread-local variable
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- threadLocal.set("main")
- println("Pre-main, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
- val job = launch(Dispatchers.Default + threadLocal.asContextElement(value = "launch")) {
- println("Launch start, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
- yield()
- println("After yield, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
- }
- job.join()
- println("Post-main, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-context-11.kt).
->
-{type="note"}
-
-In this example we launch a new coroutine in a background thread pool using [Dispatchers.Default], so
-it works on a different thread from the thread pool, but it still has the value of the thread local variable
-that we specified using `threadLocal.asContextElement(value = "launch")`,
-no matter which thread the coroutine is executed on.
-Thus, the output (with [debug](#debugging-coroutines-and-threads)) is:
-
-```text
-Pre-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'
-Launch start, current thread: Thread[DefaultDispatcher-worker-1 @coroutine#2,5,main], thread local value: 'launch'
-After yield, current thread: Thread[DefaultDispatcher-worker-2 @coroutine#2,5,main], thread local value: 'launch'
-Post-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'
-```
-
-<!--- TEST FLEXIBLE_THREAD -->
-
-It's easy to forget to set the corresponding context element. The thread-local variable accessed from the coroutine may
-then have an unexpected value, if the thread running the coroutine is different.
-To avoid such situations, it is recommended to use the [ensurePresent] method
-and fail-fast on improper usages.
-
-`ThreadLocal` has first-class support and can be used with any primitive `kotlinx.coroutines` provides.
-It has one key limitation, though: when a thread-local is mutated, a new value is not propagated to the coroutine caller
-(because a context element cannot track all `ThreadLocal` object accesses), and the updated value is lost on the next suspension.
-Use [withContext] to update the value of the thread-local in a coroutine, see [asContextElement] for more details.
-
-Alternatively, a value can be stored in a mutable box like `class Counter(var i: Int)`, which is, in turn,
-stored in a thread-local variable. However, in this case you are fully responsible to synchronize
-potentially concurrent modifications to the variable in this mutable box.
-
-For advanced usage, for example for integration with logging MDC, transactional contexts or any other libraries
-which internally use thread-locals for passing data, see the documentation of the [ThreadContextElement] interface
-that should be implemented.
-
-<!--- MODULE kotlinx-coroutines-core -->
-<!--- INDEX kotlinx.coroutines -->
-
-[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
-[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html
-[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
-[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
-[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
-[Dispatchers.Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html
-[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
-[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html
-[newSingleThreadContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/new-single-thread-context.html
-[ExecutorCoroutineDispatcher.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-executor-coroutine-dispatcher/close.html
-[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
-[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
-[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
-[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
-[isActive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/is-active.html
-[CoroutineScope.coroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/coroutine-context.html
-[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
-[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-name/index.html
-[CoroutineScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
-[MainScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-scope.html
-[Dispatchers.Main]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html
-[asContextElement]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/java.lang.-thread-local/as-context-element.html
-[ensurePresent]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/java.lang.-thread-local/ensure-present.html
-[ThreadContextElement]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-thread-context-element/index.html
-
-<!--- END --> \ No newline at end of file
diff --git a/docs/topics/coroutines-basic-jvm.md b/docs/topics/coroutines-basic-jvm.md
deleted file mode 100644
index 3b067ea8..00000000
--- a/docs/topics/coroutines-basic-jvm.md
+++ /dev/null
@@ -1,267 +0,0 @@
-[//]: # (title: Create a basic coroutine – tutorial)
-
-Kotlin 1.1 introduced coroutines, a new way of writing asynchronous, non-blocking code (and much more). In this tutorial you will go through some basics of using Kotlin coroutines with the help of the `kotlinx.coroutines` library, which is a collection of helpers and wrappers for existing Java libraries.
-
-## Set up a project
-
-### Gradle
-
-In IntelliJ IDEA go to **File** \| **New** \| **Project**.:
-
-![Create a new project](new-gradle-project-jvm.png)
-
-Then follow the wizard steps. You'll have a `build.gradle` file created with Kotlin configured according to [this document](gradle.md).
-Make sure it's configured for Kotlin 1.3 or higher.
-
-Since we'll be using the [`kotlinx.coroutines`](https://github.com/Kotlin/kotlinx.coroutines), let's add its recent version to our dependencies:
-
-<tabs>
-
-```groovy
-dependencies {
- ...
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:%coroutinesVersion%'
-}
-```
-
-```kotlin
-dependencies {
- ...
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:%coroutinesVersion%")
-}
-```
-</tabs>
-
-This library is published to the [Maven Central repository](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core), so add the following:
-
-```groovy
-repositories {
- mavenCentral()
-}
-```
-
-That's it, we are good to go and write code under `src/main/kotlin`.
-
-### Maven
-
-In IntelliJ IDEA go to **File** \| **New** \| **Project** and check the **Create from archetype** box:
-
-![Create a new project](new-mvn-project-jvm.png)
-
-Then follow the wizard steps. You'll have a `pom.xml` file created with Kotlin configured according to [this document](maven.md).
-Make sure it's configured for Kotlin 1.3 or higher.
-
-```xml
-<plugin>
- <groupId>org.jetbrains.kotlin</groupId>
- <artifactId>kotlin-maven-plugin</artifactId>
- ...
- <configuration>
- <args>
- <arg>-Xcoroutines=enable</arg>
- </args>
- </configuration>
-</plugin>
-```
-
-Since we'll be using the [`kotlinx.coroutines`](https://github.com/Kotlin/kotlinx.coroutines), let's add its recent version to our dependencies:
-
-```xml
-<dependencies>
- ...
- <dependency>
- <groupId>org.jetbrains.kotlinx</groupId>
- <artifactId>kotlinx-coroutines-core</artifactId>
- <version>%coroutinesVersion%</version>
- </dependency>
-</dependencies>
-```
-
-This library is published to the [Maven Central repository](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core), which Maven will download from by default.
-
-That's it, we are good to go and write code under `src/main/kotlin`.
-
-## My first coroutine
-
-One can think of a coroutine as a light-weight thread. Like threads, coroutines can run in parallel, wait for each other and communicate.
-The biggest difference is that coroutines are very cheap, almost free: we can create thousands of them, and pay very little in terms of performance.
-True threads, on the other hand, are expensive to start and keep around. A thousand threads can be a serious challenge for a modern machine.
-
-So, how do we start a coroutine? Let's use the `launch {}` function:
-
-```kotlin
-launch {
- ...
-}
-```
-
-This starts a new coroutine. By default, coroutines are run on a shared pool of threads.
-Threads still exist in a program based on coroutines, but one thread can run many coroutines, so there's no need for
-too many threads.
-
-Let's look at a full program that uses `launch`:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main(args: Array<String>) {
-//sampleStart
- println("Start")
-
- // Start a coroutine
- GlobalScope.launch {
- delay(1000)
- println("Hello")
- }
-
- Thread.sleep(2000) // wait for 2 seconds
- println("Stop")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-Here we start a coroutine that waits for 1 second and prints `Hello`.
-
-We are using the `delay()` function that's like `Thread.sleep()`, but better: it _doesn't block a thread_, but only suspends the coroutine itself.
-The thread is returned to the pool while the coroutine is waiting, and when the waiting is done, the coroutine resumes on a free thread in the pool.
-
-The main thread (that runs the `main()` function) must wait until our coroutine completes, otherwise the program ends before `Hello` is printed.
-
-_Exercise: try removing the `sleep()` from the program above and see the result._
-
- If we try to use the same non-blocking `delay()` function directly inside `main()`, we'll get a compiler error:
-
-> Suspend functions are only allowed to be called from a coroutine or another suspend function.
->
-{type="note"}
-
-This is because we are not inside any coroutine. We can use delay if we wrap it into `runBlocking {}` that starts a coroutine and waits until it's done:
-
-```kotlin
-runBlocking {
- delay(2000)
-}
-```
-
-So, first the resulting program prints `Start`, then it runs a coroutine through `launch {}`, then it runs another one through `runBlocking {}` and blocks until it's done, then prints `Stop`. Meanwhile the first coroutine completes and prints `Hello`. Just like threads, we told you :)
-
-## Let's run a lot of them
-
-Now, let's make sure that coroutines are really cheaper than threads. How about starting a million of them? Let's try starting a million threads first:
-
-```kotlin
-val c = AtomicLong()
-
-for (i in 1..1_000_000L)
- thread(start = true) {
- c.addAndGet(i)
- }
-
-println(c.get())
-```
-
-This runs a 1'000'000 threads each of which adds to a common counter. My patience runs out before this program completes on my machine (definitely over a minute).
-
-Let's try the same with coroutines:
-
-```kotlin
-val c = AtomicLong()
-
-for (i in 1..1_000_000L)
- GlobalScope.launch {
- c.addAndGet(i)
- }
-
-println(c.get())
-```
-
-This example completes in less than a second for me, but it prints some arbitrary number, because some coroutines don't finish before `main()` prints the result. Let's fix that.
-
-We could use the same means of synchronization that are applicable to threads (a `CountDownLatch` is what crosses my mind in this case), but let's take a safer and cleaner path.
-
-## Async: returning a value from a coroutine
-
-Another way of starting a coroutine is `async {}`. It is like `launch {}`, but returns an instance of `Deferred<T>`, which has an `await()` function that returns the result of the coroutine. `Deferred<T>` is a very basic [future](https://en.wikipedia.org/wiki/Futures_and_promises) (fully-fledged JDK futures are also supported, but here we'll confine ourselves to `Deferred` for now).
-
-Let's create a million coroutines again, keeping their `Deferred` objects. Now there's no need in the atomic counter, as we can just return the numbers to be added from our coroutines:
-
-```kotlin
-val deferred = (1..1_000_000).map { n ->
- GlobalScope.async {
- n
- }
-}
-```
-
-All these have already started, all we need is collect the results:
-
-```kotlin
-val sum = deferred.sumOf { it.await().toLong() }
-```
-
-We simply take every coroutine and await its result here, then all results are added together by the standard library function `sumOf()`. But the compiler rightfully complains:
-
-> Suspend functions are only allowed to be called from a coroutine or another suspend function.
->
-{type="note"}
-
-`await()` can not be called outside a coroutine, because it needs to suspend until the computation finishes, and only coroutines can suspend in a non-blocking way. So, let's put this inside a coroutine:
-
-```kotlin
-runBlocking {
- val sum = deferred.sumOf { it.await().toLong() }
- println("Sum: $sum")
-}
-```
-
-Now it prints something sensible: `500000500000`, because all coroutines complete.
-
-Let's also make sure that our coroutines actually run in parallel. If we add a 1-second `delay()` to each of the `async`'s, the resulting program won't run for 1'000'000 seconds (over 11,5 days):
-
-```kotlin
-val deferred = (1..1_000_000).map { n ->
- GlobalScope.async {
- delay(1000)
- n
- }
-}
-```
-
-This takes about 10 seconds on my machine, so yes, coroutines do run in parallel.
-
-## Suspending functions
-
-Now, let's say we want to extract our _workload_ (which is "wait 1 second and return a number") into a separate function:
-
-```kotlin
-fun workload(n: Int): Int {
- delay(1000)
- return n
-}
-```
-
-A familiar error pops up:
-
-> Suspend functions are only allowed to be called from a coroutine or another suspend function.
->
-{type="note"}
-
-Let's dig a little into what it means. The biggest merit of coroutines is that they can _suspend_ without blocking a thread. The compiler has to emit some special code to make this possible, so we have to mark functions that _may suspend_ explicitly in the code. We use the `suspend` modifier for it:
-
-```kotlin
-suspend fun workload(n: Int): Int {
- delay(1000)
- return n
-}
-```
-
-Now when we call `workload()` from a coroutine, the compiler knows that it may suspend and will prepare accordingly:
-
-```kotlin
-GlobalScope.async {
- workload(n)
-}
-```
-
-Our `workload()` function can be called from a coroutine (or another suspending function), but _cannot_ be called from outside a coroutine. Naturally, `delay()` and `await()` that we used above are themselves declared as `suspend`, and this is why we had to put them inside `runBlocking {}`, `launch {}` or `async {}`.
diff --git a/docs/topics/coroutines-basics.md b/docs/topics/coroutines-basics.md
deleted file mode 100644
index c1c17581..00000000
--- a/docs/topics/coroutines-basics.md
+++ /dev/null
@@ -1,379 +0,0 @@
-<!--- TEST_NAME BasicsGuideTest -->
-
-[//]: # (title: Coroutines basics)
-
-This section covers basic coroutine concepts.
-
-## Your first coroutine
-
-Run the following code:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() {
- GlobalScope.launch { // launch a new coroutine in background and continue
- delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
- println("World!") // print after delay
- }
- println("Hello,") // main thread continues while coroutine is delayed
- Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt).
->
-{type="note"}
-
-You will see the following result:
-
-```text
-Hello,
-World!
-```
-
-<!--- TEST -->
-
-Essentially, coroutines are light-weight threads.
-They are launched with [launch] _coroutine builder_ in a context of some [CoroutineScope].
-Here we are launching a new coroutine in the [GlobalScope], meaning that the lifetime of the new
-coroutine is limited only by the lifetime of the whole application.
-
-You can achieve the same result by replacing
-`GlobalScope.launch { ... }` with `thread { ... }`, and `delay(...)` with `Thread.sleep(...)`.
-Try it (don't forget to import `kotlin.concurrent.thread`).
-
-If you start by replacing `GlobalScope.launch` with `thread`, the compiler produces the following error:
-
-```Plain Text
-Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
-```
-
-That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_ the
-coroutine, and it can be only used from a coroutine.
-
-## Bridging blocking and non-blocking worlds
-
-The first example mixes _non-blocking_ `delay(...)` and _blocking_ `Thread.sleep(...)` in the same code.
-It is easy to lose track of which one is blocking and which one is not.
-Let's be explicit about blocking using the [runBlocking] coroutine builder:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() {
- GlobalScope.launch { // launch a new coroutine in background and continue
- delay(1000L)
- println("World!")
- }
- println("Hello,") // main thread continues here immediately
- runBlocking { // but this expression blocks the main thread
- delay(2000L) // ... while we delay for 2 seconds to keep JVM alive
- }
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt).
->
-{type="note"}
-
-<!--- TEST
-Hello,
-World!
--->
-
-The result is the same, but this code uses only non-blocking [delay].
-The main thread invoking `runBlocking` _blocks_ until the coroutine inside `runBlocking` completes.
-
-This example can be also rewritten in a more idiomatic way, using `runBlocking` to wrap
-the execution of the main function:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking<Unit> { // start main coroutine
- GlobalScope.launch { // launch a new coroutine in background and continue
- delay(1000L)
- println("World!")
- }
- println("Hello,") // main coroutine continues here immediately
- delay(2000L) // delaying for 2 seconds to keep JVM alive
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt).
->
-{type="note"}
-
-<!--- TEST
-Hello,
-World!
--->
-
-Here `runBlocking<Unit> { ... }` works as an adaptor that is used to start the top-level main coroutine.
-We explicitly specify its `Unit` return type, because a well-formed `main` function in Kotlin has to return `Unit`.
-
-This is also a way to write unit tests for suspending functions:
-
-<!--- INCLUDE
-import kotlinx.coroutines.*
--->
-
-```kotlin
-class MyTest {
- @Test
- fun testMySuspendingFunction() = runBlocking<Unit> {
- // here we can use suspending functions using any assertion style that we like
- }
-}
-```
-
-<!--- CLEAR -->
-
-## Waiting for a job
-
-Delaying for a time while another coroutine is working is not a good approach. Let's explicitly
-wait (in a non-blocking way) until the background [Job] that we have launched is complete:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
-//sampleStart
- val job = GlobalScope.launch { // launch a new coroutine and keep a reference to its Job
- delay(1000L)
- println("World!")
- }
- println("Hello,")
- job.join() // wait until child coroutine completes
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt).
->
-{type="note"}
-
-<!--- TEST
-Hello,
-World!
--->
-
-Now the result is still the same, but the code of the main coroutine is not tied to the duration of
-the background job in any way. Much better.
-
-## Structured concurrency
-
-There is still something to be desired for practical usage of coroutines.
-When we use `GlobalScope.launch`, we create a top-level coroutine. Even though it is light-weight, it still
-consumes some memory resources while it runs. If we forget to keep a reference to the newly launched
-coroutine, it still runs. What if the code in the coroutine hangs (for example, we erroneously
-delay for too long), what if we launched too many coroutines and ran out of memory?
-Having to manually keep references to all the launched coroutines and [join][Job.join] them is error-prone.
-
-There is a better solution. We can use structured concurrency in our code.
-Instead of launching coroutines in the [GlobalScope], just like we usually do with threads (threads are always global),
-we can launch coroutines in the specific scope of the operation we are performing.
-
-In our example, we have a `main` function that is turned into a coroutine using the [runBlocking] coroutine builder.
-Every coroutine builder, including `runBlocking`, adds an instance of [CoroutineScope] to the scope of its code block.
-We can launch coroutines in this scope without having to `join` them explicitly, because
-an outer coroutine (`runBlocking` in our example) does not complete until all the coroutines launched
-in its scope complete. Thus, we can make our example simpler:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking { // this: CoroutineScope
- launch { // launch a new coroutine in the scope of runBlocking
- delay(1000L)
- println("World!")
- }
- println("Hello,")
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt).
->
-{type="note"}
-
-<!--- TEST
-Hello,
-World!
--->
-
-## Scope builder
-
-In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using the
-[coroutineScope][_coroutineScope] builder. It creates a coroutine scope and does not complete until all launched children complete.
-
-[runBlocking] and [coroutineScope][_coroutineScope] may look similar because they both wait for their body and all its children to complete.
-The main difference is that the [runBlocking] method _blocks_ the current thread for waiting,
-while [coroutineScope][_coroutineScope] just suspends, releasing the underlying thread for other usages.
-Because of that difference, [runBlocking] is a regular function and [coroutineScope][_coroutineScope] is a suspending function.
-
-It can be demonstrated by the following example:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking { // this: CoroutineScope
- launch {
- delay(200L)
- println("Task from runBlocking")
- }
-
- coroutineScope { // Creates a coroutine scope
- launch {
- delay(500L)
- println("Task from nested launch")
- }
-
- delay(100L)
- println("Task from coroutine scope") // This line will be printed before the nested launch
- }
-
- println("Coroutine scope is over") // This line is not printed until the nested launch completes
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt).
->
-{type="note"}
-
-<!--- TEST
-Task from coroutine scope
-Task from runBlocking
-Task from nested launch
-Coroutine scope is over
--->
-
-Note that right after the "Task from coroutine scope" message (while waiting for nested launch)
- "Task from runBlocking" is executed and printed — even though the [coroutineScope][_coroutineScope] is not completed yet.
-
-## Extract function refactoring
-
-Let's extract the block of code inside `launch { ... }` into a separate function. When you
-perform "Extract function" refactoring on this code, you get a new function with the `suspend` modifier.
-This is your first _suspending function_. Suspending functions can be used inside coroutines
-just like regular functions, but their additional feature is that they can, in turn,
-use other suspending functions (like `delay` in this example) to _suspend_ execution of a coroutine.
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
- launch { doWorld() }
- println("Hello,")
-}
-
-// this is your first suspending function
-suspend fun doWorld() {
- delay(1000L)
- println("World!")
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt).
->
-{type="note"}
-
-<!--- TEST
-Hello,
-World!
--->
-
-But what if the extracted function contains a coroutine builder which is invoked on the current scope?
-In this case, the `suspend` modifier on the extracted function is not enough. Making `doWorld` an extension
-method on `CoroutineScope` is one of the solutions, but it may not always be applicable as it does not make the API clearer.
-The idiomatic solution is to have either an explicit `CoroutineScope` as a field in a class containing the target function
-or an implicit one when the outer class implements `CoroutineScope`.
-As a last resort, [CoroutineScope(coroutineContext)][CoroutineScope()] can be used, but such an approach is structurally unsafe
-because you no longer have control on the scope of execution of this method. Only private APIs can use this builder.
-
-## Coroutines ARE light-weight
-
-Run the following code:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
- repeat(100_000) { // launch a lot of coroutines
- launch {
- delay(5000L)
- print(".")
- }
- }
-}
-```
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-08.kt).
->
-{type="note"}
-
-<!--- TEST lines.size == 1 && lines[0] == ".".repeat(100_000) -->
-
-It launches 100K coroutines and, after 5 seconds, each coroutine prints a dot.
-
-Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
-
-## Global coroutines are like daemon threads
-
-The following code launches a long-running coroutine in [GlobalScope] that prints "I'm sleeping" twice a second and then
-returns from the main function after some delay:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
-//sampleStart
- GlobalScope.launch {
- repeat(1000) { i ->
- println("I'm sleeping $i ...")
- delay(500L)
- }
- }
- delay(1300L) // just quit after delay
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-09.kt).
->
-{type="note"}
-
-You can run and see that it prints three lines and terminates:
-
-```text
-I'm sleeping 0 ...
-I'm sleeping 1 ...
-I'm sleeping 2 ...
-```
-
-<!--- TEST -->
-
-Active coroutines that were launched in [GlobalScope] do not keep the process alive. They are like daemon threads.
-
-<!--- MODULE kotlinx-coroutines-core -->
-<!--- INDEX kotlinx.coroutines -->
-
-[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
-[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
-[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
-[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
-[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
-[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
-[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
-[_coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
-[CoroutineScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
-
-<!--- END -->
diff --git a/docs/topics/coroutines-guide.md b/docs/topics/coroutines-guide.md
deleted file mode 100644
index 239b2a45..00000000
--- a/docs/topics/coroutines-guide.md
+++ /dev/null
@@ -1,37 +0,0 @@
-[//]: # (title: Coroutines guide)
-
-Kotlin, as a language, provides only minimal low-level APIs in its standard library to enable various other
-libraries to utilize coroutines. Unlike many other languages with similar capabilities, `async` and `await`
-are not keywords in Kotlin and are not even part of its standard library. Moreover, Kotlin's concept
-of _suspending function_ provides a safer and less error-prone abstraction for asynchronous
-operations than futures and promises.
-
-`kotlinx.coroutines` is a rich library for coroutines developed by JetBrains. It contains a number of high-level
-coroutine-enabled primitives that this guide covers, including `launch`, `async` and others.
-
-This is a guide on core features of `kotlinx.coroutines` with a series of examples, divided up into different topics.
-
-In order to use coroutines as well as follow the examples in this guide, you need to add a dependency on the `kotlinx-coroutines-core` module as explained
-[in the project README](https://github.com/Kotlin/kotlinx.coroutines/blob/master/README.md#using-in-your-projects).
-
-## Table of contents
-
-* [Coroutines basics](coroutines-basics.md)
-* [Tutorial: Create a basic coroutine](coroutines-basic-jvm.md)
-* [Hands-on: Intro to coroutines and channels](https://play.kotlinlang.org/hands-on/Introduction%20to%20Coroutines%20and%20Channels)
-* [Cancellation and timeouts](cancellation-and-timeouts.md)
-* [Composing suspending functions](composing-suspending-functions.md)
-* [Coroutine context and dispatchers](coroutine-context-and-dispatchers.md)
-* [Asynchronous Flow](flow.md)
-* [Channels](channels.md)
-* [Coroutine exceptions handling](exception-handling.md)
-* [Shared mutable state and concurrency](shared-mutable-state-and-concurrency.md)
-* [Select expression (experimental)](select-expression.md)
-* [Tutorial: Debug coroutines using IntelliJ IDEA](debug-coroutines-with-idea.md)
-* [Tutorial: Debug Kotlin Flow using IntelliJ IDEA](debug-flow-with-idea.md)
-
-## Additional references
-
-* [Guide to UI programming with coroutines](../../ui/coroutines-guide-ui.md)
-* [Coroutines design document (KEEP)](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md)
-* [Full kotlinx.coroutines API reference](https://kotlin.github.io/kotlinx.coroutines)
diff --git a/docs/topics/debug-coroutines-with-idea.md b/docs/topics/debug-coroutines-with-idea.md
deleted file mode 100644
index c44bafc1..00000000
--- a/docs/topics/debug-coroutines-with-idea.md
+++ /dev/null
@@ -1,82 +0,0 @@
-[//]: # (title: Debug coroutines using IntelliJ IDEA – tutorial)
-
-This tutorial demonstrates how to create Kotlin coroutines and debug them using IntelliJ IDEA.
-
-The tutorial assumes you have prior knowledge of the [coroutines](coroutines-guide.md) concept.
-
-> Debugging works for `kotlinx-coroutines-core` version 1.3.8 or later.
->
-{type="note"}
-
-## Create coroutines
-
-1. Open a Kotlin project in IntelliJ IDEA. If you don't have a project, [create one](jvm-get-started.md#create-an-application).
-
-2. Open the `main.kt` file in `src/main/kotlin`.
-
- The `src` directory contains Kotlin source files and resources. The `main.kt` file contains sample code that will print `Hello World!`.
-
-2. Change code in the `main()` function:
-
- * Use the [`runBlocking()`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html) block to wrap a coroutine.
- * Use the [`async()`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html) function to create coroutines that compute deferred values `a` and `b`.
- * Use the [`await()`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/await.html) function to await the computation result.
- * Use the [`println()`](https://kotlinlang.org//api/latest/jvm/stdlib/stdlib/kotlin.io/println.html) function to print computing status and the result of multiplication to the output.
-
- ```kotlin
- import kotlinx.coroutines.*
-
- fun main() = runBlocking<Unit> {
- val a = async {
- println("I'm computing part of the answer")
- 6
- }
- val b = async {
- println("I'm computing another part of the answer")
- 7
- }
- println("The answer is ${a.await() * b.await()}")
- }
- ```
-
-4. Build the code by clicking **Build Project**.
-
- ![Build an application](flow-build-project.png)
-
-## Debug coroutines
-
-1. Set breakpoints at the lines with the `println()` function call:
-
- ![Build a console application](coroutine-breakpoint.png)
-
-2. Run the code in debug mode by clicking **Debug** next to the run configuration at the top of the screen.
-
- ![Build a console application](flow-debug-project.png)
-
- The **Debug** tool window appears:
- * The **Frames** tab contains the call stack.
- * The **Variables** tab contains variables in the current context.
- * The **Coroutines** tab contains information on running or suspended coroutines. It shows that there are three coroutines.
- The first one has the **RUNNING** status, and the other two have the **CREATED** status.
-
- ![Debug the coroutine](coroutine-debug-1.png)
-
-3. Resume the debugger session by clicking **Resume program** in the **Debug** tool window:
-
- ![Debug the coroutine](coroutine-debug-2.png)
-
- Now the **Coroutines** tab shows the following:
- * The first coroutine has the **SUSPENDED** status – it is waiting for the values so it can multiply them.
- * The second coroutine is calculating the `a` value – it has the **RUNNING** status.
- * The third coroutine has the **CREATED** status and isn’t calculating the value of `b`.
-
-4. Resume the debugger session by clicking **Resume program** in the **Debug** tool window:
-
- ![Build a console application](coroutine-debug-3.png)
-
- Now the **Coroutines** tab shows the following:
- * The first coroutine has the **SUSPENDED** status – it is waiting for the values so it can multiply them.
- * The second coroutine has computed its value and disappeared.
- * The third coroutine is calculating the value of `b` – it has the **RUNNING** status.
-
-Using IntelliJ IDEA debugger, you can dig deeper into each coroutine to debug your code. \ No newline at end of file
diff --git a/docs/topics/debug-flow-with-idea.md b/docs/topics/debug-flow-with-idea.md
deleted file mode 100644
index 745dcb17..00000000
--- a/docs/topics/debug-flow-with-idea.md
+++ /dev/null
@@ -1,126 +0,0 @@
-[//]: # (title: Debug Kotlin Flow using IntelliJ IDEA – tutorial)
-
-This tutorial demonstrates how to create Kotlin Flow and debug it using IntelliJ IDEA.
-
-The tutorial assumes you have prior knowledge of the [coroutines](coroutines-guide.md) and [Kotlin Flow](flow.md#flows) concepts.
-
-> Debugging works for `kotlinx-coroutines-core` version 1.3.8 or later.
->
-{type="note"}
-
-## Create a Kotlin flow
-
-Create a Kotlin [flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow.html) with a slow emitter and a slow collector:
-
-1. Open a Kotlin project in IntelliJ IDEA. If you don't have a project, [create one](jvm-get-started.md#create-an-application).
-
-2. Open the `main.kt` file in `src/main/kotlin`.
-
- The `src` directory contains Kotlin source files and resources. The `main.kt` file contains sample code that will print `Hello World!`.
-
-2. Create the `simple()` function that returns a flow of three numbers:
-
- * Use the [`delay()`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html) function to imitate CPU-consuming blocking code. It suspends the coroutine for 100 ms without blocking the thread.
- * Produce the values in the `for` loop using the [`emit()`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow-collector/emit.html) function.
-
- ```kotlin
- import kotlinx.coroutines.*
- import kotlinx.coroutines.flow.*
- import kotlin.system.*
-
- fun simple(): Flow<Int> = flow {
- for (i in 1..3) {
- delay(100)
- emit(i)
- }
- }
- ```
-
-3. Change the code in the `main()` function:
-
- * Use the [`runBlocking()`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html) block to wrap a coroutine.
- * Collect the emitted values using the [`collect()`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/collect.html) function.
- * Use the [`delay()`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html) function to imitate CPU-consuming code. It suspends the coroutine for 300 ms without blocking the thread.
- * Print the collected value from the flow using the [`println()`](https://kotlinlang.org/api/latest/jvm/stdlib/stdlib/kotlin.io/println.html) function.
-
- ```kotlin
- fun main() = runBlocking {
- simple()
- .collect { value ->
- delay(300)
- println(value)
- }
- }
- ```
-
-4. Build the code by clicking **Build Project**.
-
- ![Build an application](flow-build-project.png)
-
-## Debug the coroutine
-
-1. Set a breakpoint at the at the line where the `emit()` function is called:
-
- ![Build a console application](flow-breakpoint.png)
-
-2. Run the code in debug mode by clicking **Debug** next to the run configuration at the top of the screen.
-
- ![Build a console application](flow-debug-project.png)
-
- The **Debug** tool window appears:
- * The **Frames** tab contains the call stack.
- * The **Variables** tab contains variables in the current context. It tells us that the flow is emitting the first value.
- * The **Coroutines** tab contains information on running or suspended coroutines.
-
- ![Debug the coroutine](flow-debug-1.png)
-
-3. Resume the debugger session by clicking **Resume program** in the **Debug** tool window. The program stops at the same breakpoint.
-
- ![Debug the coroutine](flow-resume-debug.png)
-
- Now the flow emits the second value.
-
- ![Debug the coroutine](flow-debug-2.png)
-
-## Add a concurrently running coroutine
-
-1. Open the `main.kt` file in `src/main/kotlin`.
-
-2. Enhance the code to run the emitter and collector concurrently:
-
- * Add a call to the [`buffer()`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/buffer.html) function to run the emitter and collector concurrently. `buffer()` stores emitted values and runs the flow collector in a separate coroutine.
-
- ```kotlin
- fun main() = runBlocking<Unit> {
- simple()
- .buffer()
- .collect { value ->
- delay(300)
- println(value)
- }
- }
- ```
-
-4. Build the code by clicking **Build Project**.
-
-## Debug a Kotlin flow with two coroutines
-
-1. Set a new breakpoint at `println(value)`.
-
-2. Run the code in debug mode by clicking **Debug** next to the run configuration at the top of the screen.
-
- ![Build a console application](flow-debug-3.png)
-
- The **Debug** tool window appears.
-
- In the **Coroutines** tab, you can see that there are two coroutines running concurrently. The flow collector and emitter run in separate coroutines because of the `buffer()` function.
- The `buffer()` function buffers emitted values from the flow.
- The emitter coroutine has the **RUNNING** status, and the collector coroutine has the **SUSPENDED** status.
-
-2. Resume the debugger session by clicking **Resume program** in the **Debug** tool window.
-
- ![Debugging coroutines](flow-debug-4.png)
-
- Now the collector coroutine has the **RUNNING** status, while the emitter coroutine has the **SUSPENDED** status.
-
- You can dig deeper into each coroutine to debug your code. \ No newline at end of file
diff --git a/docs/topics/debugging.md b/docs/topics/debugging.md
deleted file mode 100644
index d18df7f4..00000000
--- a/docs/topics/debugging.md
+++ /dev/null
@@ -1,112 +0,0 @@
-**Table of contents**
-
-<!--- TOC -->
-
-* [Debugging coroutines](#debugging-coroutines)
-* [Debug mode](#debug-mode)
-* [Stacktrace recovery](#stacktrace-recovery)
- * [Stacktrace recovery machinery](#stacktrace-recovery-machinery)
-* [Debug agent](#debug-agent)
- * [Debug agent and Android](#debug-agent-and-android)
-* [Android optimization](#android-optimization)
-
-<!--- END -->
-
-## Debugging coroutines
-
-Debugging asynchronous programs is challenging, because multiple concurrent coroutines are typically working at the same time.
-To help with that, `kotlinx.coroutines` comes with additional features for debugging: debug mode, stacktrace recovery
-and debug agent.
-
-## Debug mode
-
-The first debugging feature of `kotlinx.coroutines` is debug mode.
-It can be enabled either by setting system property [DEBUG_PROPERTY_NAME] or by running Java with enabled assertions (`-ea` flag).
-The latter is helpful to have debug mode enabled by default in unit tests.
-
-Debug mode attaches a unique [name][CoroutineName] to every launched coroutine.
-Coroutine name can be seen in a regular Java debugger,
-in a string representation of the coroutine or in the thread name executing named coroutine.
-Overhead of this feature is negligible and it can be safely turned on by default to simplify logging and diagnostic.
-
-## Stacktrace recovery
-
-Stacktrace recovery is another useful feature of debug mode. It is enabled by default in the debug mode,
-but can be separately disabled by setting `kotlinx.coroutines.stacktrace.recovery` system property to `false`.
-
-Stacktrace recovery tries to stitch asynchronous exception stacktrace with a stacktrace of the receiver by copying it, providing
-not only information where an exception was thrown, but also where it was asynchronously rethrown or caught.
-
-It is easy to demonstrate with actual stacktraces of the same program that awaits asynchronous operation in `main` function
-(runnable code is [here](../../kotlinx-coroutines-debug/test/RecoveryExample.kt)):
-
-| Without recovery | With recovery |
-| - | - |
-| ![before](../images/before.png "before") | ![after](../images/after.png "after") |
-
-The only downside of this approach is losing referential transparency of the exception.
-
-> Note that suppressed exceptions are not copied and are left intact in the cause
-> in order to prevent cycles in the exceptions chain, obscure`[CIRCULAR REFERENCE]` messages
-> and even [crashes](https://jira.qos.ch/browse/LOGBACK-1027) in some frameworks
-
-### Stacktrace recovery machinery
-
-This section explains the inner mechanism of stacktrace recovery and can be skipped.
-
-When an exception is rethrown between coroutines (e.g. through `withContext` or `Deferred.await` boundary), stacktrace recovery
-machinery tries to create a copy of the original exception (with the original exception as the cause), then rewrite stacktrace
-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-))
-and then throws the resulting exception instead of the original one.
-
-Exception copy logic is straightforward:
- 1) If the exception class implements [CopyableThrowable], [CopyableThrowable.createCopy] is used.
- `null` can be returned from `createCopy` to opt-out specific exception from being recovered.
- 2) If the exception class has class-specific fields not inherited from Throwable, the exception is not copied.
- 3) Otherwise, one of the public exception's constructor is invoked reflectively with an optional `initCause` call.
-
-## Debug agent
-
-[kotlinx-coroutines-debug](../../kotlinx-coroutines-debug) module provides one of the most powerful debug capabilities in `kotlinx.coroutines`.
-
-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,
-additionally enhancing stacktraces with information where coroutine was created.
-
-The full tutorial of how to use debug agent can be found in the corresponding [readme](../../kotlinx-coroutines-debug/README.md).
-
-### Debug agent and Android
-
-Unfortunately, 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;`.
-
-Nevertheless, 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
-
-<!---
-Make an exception googlable
-java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/ManagementFactory;
- at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent$ProcessProvider$ForCurrentVm$ForLegacyVm.resolve(ByteBuddyAgent.java:1055)
- at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent$ProcessProvider$ForCurrentVm.resolve(ByteBuddyAgent.java:1038)
- at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:374)
- at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:342)
- at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:328)
- at kotlinx.coroutines.debug.internal.DebugProbesImpl.install(DebugProbesImpl.kt:39)
- at kotlinx.coroutines.debug.DebugProbes.install(DebugProbes.kt:49)
--->
-
-## Android optimization
-
-In optimized (release) builds with R8 version 1.6.0 or later both
-[Debugging mode](../../docs/debugging.md#debug-mode) and
-[Stacktrace recovery](../../docs/debugging.md#stacktrace-recovery)
-are permanently turned off.
-For more details see ["Optimization" section for Android](../../ui/kotlinx-coroutines-android/README.md#optimization).
-
-<!--- MODULE kotlinx-coroutines-core -->
-<!--- INDEX kotlinx.coroutines -->
-
-[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
-[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-name/index.html
-[CopyableThrowable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/index.html
-[CopyableThrowable.createCopy]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/create-copy.html
-
-<!--- MODULE kotlinx-coroutines-debug -->
-<!--- END -->
diff --git a/docs/topics/exception-handling.md b/docs/topics/exception-handling.md
deleted file mode 100644
index fbd11313..00000000
--- a/docs/topics/exception-handling.md
+++ /dev/null
@@ -1,513 +0,0 @@
-<!--- TEST_NAME ExceptionsGuideTest -->
-
-[//]: # (title: Coroutine exceptions handling)
-
-This section covers exception handling and cancellation on exceptions.
-We already know that a cancelled coroutine throws [CancellationException] in suspension points and that it
-is ignored by the coroutines' machinery. Here we look at what happens if an exception is thrown during cancellation or multiple children of the same
-coroutine throw an exception.
-
-## Exception propagation
-
-Coroutine builders come in two flavors: propagating exceptions automatically ([launch] and [actor]) or
-exposing them to users ([async] and [produce]).
-When these builders are used to create a _root_ coroutine, that is not a _child_ of another coroutine,
-the former builders treat exceptions as **uncaught** exceptions, similar to Java's `Thread.uncaughtExceptionHandler`,
-while the latter are relying on the user to consume the final
-exception, for example via [await][Deferred.await] or [receive][ReceiveChannel.receive]
-([produce] and [receive][ReceiveChannel.receive] are covered later in [Channels](https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/channels.md) section).
-
-It can be demonstrated by a simple example that creates root coroutines using the [GlobalScope]:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
- val job = GlobalScope.launch { // root coroutine with launch
- println("Throwing exception from launch")
- throw IndexOutOfBoundsException() // Will be printed to the console by Thread.defaultUncaughtExceptionHandler
- }
- job.join()
- println("Joined failed job")
- val deferred = GlobalScope.async { // root coroutine with async
- println("Throwing exception from async")
- throw ArithmeticException() // Nothing is printed, relying on user to call await
- }
- try {
- deferred.await()
- println("Unreached")
- } catch (e: ArithmeticException) {
- println("Caught ArithmeticException")
- }
-}
-```
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-01.kt).
->
-{type="note"}
-
-The output of this code is (with [debug](https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/coroutine-context-and-dispatchers.md#debugging-coroutines-and-threads)):
-
-```text
-Throwing exception from launch
-Exception in thread "DefaultDispatcher-worker-2 @coroutine#2" java.lang.IndexOutOfBoundsException
-Joined failed job
-Throwing exception from async
-Caught ArithmeticException
-```
-
-<!--- TEST EXCEPTION-->
-
-## CoroutineExceptionHandler
-
-It is possible to customize the default behavior of printing **uncaught** exceptions to the console.
-[CoroutineExceptionHandler] context element on a _root_ coroutine can be used as generic `catch` block for
-this root coroutine and all its children where custom exception handling may take place.
-It is similar to [`Thread.uncaughtExceptionHandler`](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler)).
-You cannot recover from the exception in the `CoroutineExceptionHandler`. The coroutine had already completed
-with the corresponding exception when the handler is called. Normally, the handler is used to
-log the exception, show some kind of error message, terminate, and/or restart the application.
-
-On JVM it is possible to redefine global exception handler for all coroutines by registering [CoroutineExceptionHandler] via
-[`ServiceLoader`](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html).
-Global exception handler is similar to
-[`Thread.defaultUncaughtExceptionHandler`](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler))
-which is used when no more specific handlers are registered.
-On Android, `uncaughtExceptionPreHandler` is installed as a global coroutine exception handler.
-
-`CoroutineExceptionHandler` is invoked only on **uncaught** exceptions &mdash; exceptions that were not handled in any other way.
-In particular, all _children_ coroutines (coroutines created in the context of another [Job]) delegate handling of
-their exceptions to their parent coroutine, which also delegates to the parent, and so on until the root,
-so the `CoroutineExceptionHandler` installed in their context is never used.
-In addition to that, [async] builder always catches all exceptions and represents them in the resulting [Deferred] object,
-so its `CoroutineExceptionHandler` has no effect either.
-
-> Coroutines running in supervision scope do not propagate exceptions to their parent and are
-> excluded from this rule. A further [Supervision](#supervision) section of this document gives more details.
->
-{type="note"}
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
-//sampleStart
- val handler = CoroutineExceptionHandler { _, exception ->
- println("CoroutineExceptionHandler got $exception")
- }
- val job = GlobalScope.launch(handler) { // root coroutine, running in GlobalScope
- throw AssertionError()
- }
- val deferred = GlobalScope.async(handler) { // also root, but async instead of launch
- throw ArithmeticException() // Nothing will be printed, relying on user to call deferred.await()
- }
- joinAll(job, deferred)
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-02.kt).
->
-{type="note"}
-
-The output of this code is:
-
-```text
-CoroutineExceptionHandler got java.lang.AssertionError
-```
-
-<!--- TEST-->
-
-## Cancellation and exceptions
-
-Cancellation is closely related to exceptions. Coroutines internally use `CancellationException` for cancellation, these
-exceptions are ignored by all handlers, so they should be used only as the source of additional debug information, which can
-be obtained by `catch` block.
-When a coroutine is cancelled using [Job.cancel], it terminates, but it does not cancel its parent.
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
-//sampleStart
- val job = launch {
- val child = launch {
- try {
- delay(Long.MAX_VALUE)
- } finally {
- println("Child is cancelled")
- }
- }
- yield()
- println("Cancelling child")
- child.cancel()
- child.join()
- yield()
- println("Parent is not cancelled")
- }
- job.join()
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-03.kt).
->
-{type="note"}
-
-The output of this code is:
-
-```text
-Cancelling child
-Child is cancelled
-Parent is not cancelled
-```
-
-<!--- TEST-->
-
-If a coroutine encounters an exception other than `CancellationException`, it cancels its parent with that exception.
-This behaviour cannot be overridden and is used to provide stable coroutines hierarchies for
-[structured concurrency](https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/composing-suspending-functions.md#structured-concurrency-with-async).
-[CoroutineExceptionHandler] implementation is not used for child coroutines.
-
-> In these examples, [CoroutineExceptionHandler] is always installed to a coroutine
-> that is created in [GlobalScope]. It does not make sense to install an exception handler to a coroutine that
-> is launched in the scope of the main [runBlocking], since the main coroutine is going to be always cancelled
-> when its child completes with exception despite the installed handler.
->
-{type="note"}
-
-The original exception is handled by the parent only when all its children terminate,
-which is demonstrated by the following example.
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
-//sampleStart
- val handler = CoroutineExceptionHandler { _, exception ->
- println("CoroutineExceptionHandler got $exception")
- }
- val job = GlobalScope.launch(handler) {
- launch { // the first child
- try {
- delay(Long.MAX_VALUE)
- } finally {
- withContext(NonCancellable) {
- println("Children are cancelled, but exception is not handled until all children terminate")
- delay(100)
- println("The first child finished its non cancellable block")
- }
- }
- }
- launch { // the second child
- delay(10)
- println("Second child throws an exception")
- throw ArithmeticException()
- }
- }
- job.join()
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-04.kt).
->
-{type="note"}
-
-The output of this code is:
-
-```text
-Second child throws an exception
-Children are cancelled, but exception is not handled until all children terminate
-The first child finished its non cancellable block
-CoroutineExceptionHandler got java.lang.ArithmeticException
-```
-
-<!--- TEST-->
-
-## Exceptions aggregation
-
-When multiple children of a coroutine fail with an exception, the
-general rule is "the first exception wins", so the first exception gets handled.
-All additional exceptions that happen after the first one are attached to the first exception as suppressed ones.
-
-<!--- INCLUDE
-import kotlinx.coroutines.exceptions.*
--->
-
-```kotlin
-import kotlinx.coroutines.*
-import java.io.*
-
-fun main() = runBlocking {
- val handler = CoroutineExceptionHandler { _, exception ->
- println("CoroutineExceptionHandler got $exception with suppressed ${exception.suppressed.contentToString()}")
- }
- val job = GlobalScope.launch(handler) {
- launch {
- try {
- delay(Long.MAX_VALUE) // it gets cancelled when another sibling fails with IOException
- } finally {
- throw ArithmeticException() // the second exception
- }
- }
- launch {
- delay(100)
- throw IOException() // the first exception
- }
- delay(Long.MAX_VALUE)
- }
- job.join()
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-05.kt).
->
-{type="note"}
-
-> Note: This above code will work properly only on JDK7+ that supports `suppressed` exceptions
->
-{type="note"}
-
-The output of this code is:
-
-```text
-CoroutineExceptionHandler got java.io.IOException with suppressed [java.lang.ArithmeticException]
-```
-
-<!--- TEST-->
-
-> Note that this mechanism currently only works on Java version 1.7+.
-> The JS and Native restrictions are temporary and will be lifted in the future.
->
-{type="note"}
-
-Cancellation exceptions are transparent and are unwrapped by default:
-
-```kotlin
-import kotlinx.coroutines.*
-import java.io.*
-
-fun main() = runBlocking {
-//sampleStart
- val handler = CoroutineExceptionHandler { _, exception ->
- println("CoroutineExceptionHandler got $exception")
- }
- val job = GlobalScope.launch(handler) {
- val inner = launch { // all this stack of coroutines will get cancelled
- launch {
- launch {
- throw IOException() // the original exception
- }
- }
- }
- try {
- inner.join()
- } catch (e: CancellationException) {
- println("Rethrowing CancellationException with original cause")
- throw e // cancellation exception is rethrown, yet the original IOException gets to the handler
- }
- }
- job.join()
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-06.kt).
->
-{type="note"}
-
-The output of this code is:
-
-```text
-Rethrowing CancellationException with original cause
-CoroutineExceptionHandler got java.io.IOException
-```
-
-<!--- TEST-->
-
-## Supervision
-
-As we have studied before, cancellation is a bidirectional relationship propagating through the whole
-hierarchy of coroutines. Let us take a look at the case when unidirectional cancellation is required.
-
-A good example of such a requirement is a UI component with the job defined in its scope. If any of the UI's child tasks
-have failed, it is not always necessary to cancel (effectively kill) the whole UI component,
-but if UI component is destroyed (and its job is cancelled), then it is necessary to fail all child jobs as their results are no longer needed.
-
-Another example is a server process that spawns multiple child jobs and needs to _supervise_
-their execution, tracking their failures and only restarting the failed ones.
-
-### Supervision job
-
-The [SupervisorJob][SupervisorJob()] can be used for these purposes.
-It is similar to a regular [Job][Job()] with the only exception that cancellation is propagated
-only downwards. This can easily be demonstrated using the following example:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
- val supervisor = SupervisorJob()
- with(CoroutineScope(coroutineContext + supervisor)) {
- // launch the first child -- its exception is ignored for this example (don't do this in practice!)
- val firstChild = launch(CoroutineExceptionHandler { _, _ -> }) {
- println("The first child is failing")
- throw AssertionError("The first child is cancelled")
- }
- // launch the second child
- val secondChild = launch {
- firstChild.join()
- // Cancellation of the first child is not propagated to the second child
- println("The first child is cancelled: ${firstChild.isCancelled}, but the second one is still active")
- try {
- delay(Long.MAX_VALUE)
- } finally {
- // But cancellation of the supervisor is propagated
- println("The second child is cancelled because the supervisor was cancelled")
- }
- }
- // wait until the first child fails & completes
- firstChild.join()
- println("Cancelling the supervisor")
- supervisor.cancel()
- secondChild.join()
- }
-}
-```
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-supervision-01.kt).
->
-{type="note"}
-
-The output of this code is:
-
-```text
-The first child is failing
-The first child is cancelled: true, but the second one is still active
-Cancelling the supervisor
-The second child is cancelled because the supervisor was cancelled
-```
-
-<!--- TEST-->
-
-### Supervision scope
-
-Instead of [coroutineScope][_coroutineScope], we can use [supervisorScope][_supervisorScope] for _scoped_ concurrency. It propagates the cancellation
-in one direction only and cancels all its children only if it failed itself. It also waits for all children before completion
-just like [coroutineScope][_coroutineScope] does.
-
-```kotlin
-import kotlin.coroutines.*
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
- try {
- supervisorScope {
- val child = launch {
- try {
- println("The child is sleeping")
- delay(Long.MAX_VALUE)
- } finally {
- println("The child is cancelled")
- }
- }
- // Give our child a chance to execute and print using yield
- yield()
- println("Throwing an exception from the scope")
- throw AssertionError()
- }
- } catch(e: AssertionError) {
- println("Caught an assertion error")
- }
-}
-```
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-supervision-02.kt).
->
-{type="note"}
-
-The output of this code is:
-
-```text
-The child is sleeping
-Throwing an exception from the scope
-The child is cancelled
-Caught an assertion error
-```
-
-<!--- TEST-->
-
-#### Exceptions in supervised coroutines
-
-Another crucial difference between regular and supervisor jobs is exception handling.
-Every child should handle its exceptions by itself via the exception handling mechanism.
-This difference comes from the fact that child's failure does not propagate to the parent.
-It means that coroutines launched directly inside the [supervisorScope][_supervisorScope] _do_ use the [CoroutineExceptionHandler]
-that is installed in their scope in the same way as root coroutines do
-(see the [CoroutineExceptionHandler](#coroutineexceptionhandler) section for details).
-
-```kotlin
-import kotlin.coroutines.*
-import kotlinx.coroutines.*
-
-fun main() = runBlocking {
- val handler = CoroutineExceptionHandler { _, exception ->
- println("CoroutineExceptionHandler got $exception")
- }
- supervisorScope {
- val child = launch(handler) {
- println("The child throws an exception")
- throw AssertionError()
- }
- println("The scope is completing")
- }
- println("The scope is completed")
-}
-```
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-supervision-03.kt).
->
-{type="note"}
-
-The output of this code is:
-
-```text
-The scope is completing
-The child throws an exception
-CoroutineExceptionHandler got java.lang.AssertionError
-The scope is completed
-```
-
-<!--- TEST-->
-
-<!--- MODULE kotlinx-coroutines-core -->
-<!--- INDEX kotlinx.coroutines -->
-
-[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html
-[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
-[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
-[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/await.html
-[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
-[CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-exception-handler/index.html
-[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
-[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html
-[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html
-[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
-[SupervisorJob()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-supervisor-job.html
-[Job()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job.html
-[_coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
-[_supervisorScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/supervisor-scope.html
-
-<!--- INDEX kotlinx.coroutines.channels -->
-
-[actor]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/actor.html
-[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/produce.html
-[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive.html
-
-<!--- END --> \ No newline at end of file
diff --git a/docs/topics/flow.md b/docs/topics/flow.md
deleted file mode 100644
index 9dd84f3f..00000000
--- a/docs/topics/flow.md
+++ /dev/null
@@ -1,1896 +0,0 @@
-<!--- TEST_NAME FlowGuideTest -->
-
-[//]: # (title: Asynchronous Flow)
-
-A suspending function asynchronously returns a single value, but how can we return
-multiple asynchronously computed values? This is where Kotlin Flows come in.
-
-## Representing multiple values
-
-Multiple values can be represented in Kotlin using [collections].
-For example, we can have a `simple` function that returns a [List]
-of three numbers and then print them all using [forEach]:
-
-```kotlin
-fun simple(): List<Int> = listOf(1, 2, 3)
-
-fun main() {
- simple().forEach { value -> println(value) }
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-01.kt).
->
-{type="note"}
-
-This code outputs:
-
-```text
-1
-2
-3
-```
-
-<!--- TEST -->
-
-### Sequences
-
-If we are computing the numbers with some CPU-consuming blocking code
-(each computation taking 100ms), then we can represent the numbers using a [Sequence]:
-
-```kotlin
-fun simple(): Sequence<Int> = sequence { // sequence builder
- for (i in 1..3) {
- Thread.sleep(100) // pretend we are computing it
- yield(i) // yield next value
- }
-}
-
-fun main() {
- simple().forEach { value -> println(value) }
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-02.kt).
->
-{type="note"}
-
-This code outputs the same numbers, but it waits 100ms before printing each one.
-
-<!--- TEST
-1
-2
-3
--->
-
-### Suspending functions
-
-However, this computation blocks the main thread that is running the code.
-When these values are computed by asynchronous code we can mark the `simple` function with a `suspend` modifier,
-so that it can perform its work without blocking and return the result as a list:
-
-```kotlin
-import kotlinx.coroutines.*
-
-//sampleStart
-suspend fun simple(): List<Int> {
- delay(1000) // pretend we are doing something asynchronous here
- return listOf(1, 2, 3)
-}
-
-fun main() = runBlocking<Unit> {
- simple().forEach { value -> println(value) }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-03.kt).
->
-{type="note"}
-
-This code prints the numbers after waiting for a second.
-
-<!--- TEST
-1
-2
-3
--->
-
-### Flows
-
-Using the `List<Int>` result type, means we can only return all the values at once. To represent
-the stream of values that are being asynchronously computed, we can use a [`Flow<Int>`][Flow] type just like we would use the `Sequence<Int>` type for synchronously computed values:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun simple(): Flow<Int> = flow { // flow builder
- for (i in 1..3) {
- delay(100) // pretend we are doing something useful here
- emit(i) // emit next value
- }
-}
-
-fun main() = runBlocking<Unit> {
- // Launch a concurrent coroutine to check if the main thread is blocked
- launch {
- for (k in 1..3) {
- println("I'm not blocked $k")
- delay(100)
- }
- }
- // Collect the flow
- simple().collect { value -> println(value) }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-04.kt).
->
-{type="note"}
-
-This code waits 100ms before printing each number without blocking the main thread. This is verified
-by printing "I'm not blocked" every 100ms from a separate coroutine that is running in the main thread:
-
-```text
-I'm not blocked 1
-1
-I'm not blocked 2
-2
-I'm not blocked 3
-3
-```
-
-<!--- TEST -->
-
-Notice the following differences in the code with the [Flow] from the earlier examples:
-
-* A builder function for [Flow] type is called [flow][_flow].
-* Code inside the `flow { ... }` builder block can suspend.
-* The `simple` function is no longer marked with `suspend` modifier.
-* Values are _emitted_ from the flow using [emit][FlowCollector.emit] function.
-* Values are _collected_ from the flow using [collect][collect] function.
-
-> We can replace [delay] with `Thread.sleep` in the body of `foo`'s `flow { ... }` and see that the main
-> thread is blocked in this case.
->
-{type="note"}
-
-## Flows are cold
-
-Flows are _cold_ streams similar to sequences &mdash; the code inside a [flow][_flow] builder does not
-run until the flow is collected. This becomes clear in the following example:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun simple(): Flow<Int> = flow {
- println("Flow started")
- for (i in 1..3) {
- delay(100)
- emit(i)
- }
-}
-
-fun main() = runBlocking<Unit> {
- println("Calling simple function...")
- val flow = simple()
- println("Calling collect...")
- flow.collect { value -> println(value) }
- println("Calling collect again...")
- flow.collect { value -> println(value) }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-05.kt).
->
-{type="note"}
-
-Which prints:
-
-```text
-Calling simple function...
-Calling collect...
-Flow started
-1
-2
-3
-Calling collect again...
-Flow started
-1
-2
-3
-```
-
-<!--- TEST -->
-
-This is a key reason the `simple` function (which returns a flow) is not marked with `suspend` modifier.
-By itself, `simple()` call returns quickly and does not wait for anything. The flow starts every time it is collected,
-that is why we see "Flow started" when we call `collect` again.
-
-## Flow cancellation basics
-
-Flow adheres to the general cooperative cancellation of coroutines. As usual, flow collection can be
-cancelled when the flow is suspended in a cancellable suspending function (like [delay]).
-The following example shows how the flow gets cancelled on a timeout when running in a [withTimeoutOrNull] block
-and stops executing its code:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun simple(): Flow<Int> = flow {
- for (i in 1..3) {
- delay(100)
- println("Emitting $i")
- emit(i)
- }
-}
-
-fun main() = runBlocking<Unit> {
- withTimeoutOrNull(250) { // Timeout after 250ms
- simple().collect { value -> println(value) }
- }
- println("Done")
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-06.kt).
->
-{type="note"}
-
-Notice how only two numbers get emitted by the flow in the `simple` function, producing the following output:
-
-```text
-Emitting 1
-1
-Emitting 2
-2
-Done
-```
-
-<!--- TEST -->
-
-See [Flow cancellation checks](#flow-cancellation-checks) section for more details.
-
-## Flow builders
-
-The `flow { ... }` builder from the previous examples is the most basic one. There are other builders for
-easier declaration of flows:
-
-* [flowOf] builder that defines a flow emitting a fixed set of values.
-* Various collections and sequences can be converted to flows using `.asFlow()` extension functions.
-
-So, the example that prints the numbers from 1 to 3 from a flow can be written as:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- // Convert an integer range to a flow
- (1..3).asFlow().collect { value -> println(value) }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-07.kt).
->
-{type="note"}
-
-<!--- TEST
-1
-2
-3
--->
-
-## Intermediate flow operators
-
-Flows can be transformed with operators, just as you would with collections and sequences.
-Intermediate operators are applied to an upstream flow and return a downstream flow.
-These operators are cold, just like flows are. A call to such an operator is not
-a suspending function itself. It works quickly, returning the definition of a new transformed flow.
-
-The basic operators have familiar names like [map] and [filter].
-The important difference to sequences is that blocks of
-code inside these operators can call suspending functions.
-
-For example, a flow of incoming requests can be
-mapped to the results with the [map] operator, even when performing a request is a long-running
-operation that is implemented by a suspending function:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-suspend fun performRequest(request: Int): String {
- delay(1000) // imitate long-running asynchronous work
- return "response $request"
-}
-
-fun main() = runBlocking<Unit> {
- (1..3).asFlow() // a flow of requests
- .map { request -> performRequest(request) }
- .collect { response -> println(response) }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-08.kt).
->
-{type="note"}
-
-It produces the following three lines, each line appearing after each second:
-
-```text
-response 1
-response 2
-response 3
-```
-
-<!--- TEST -->
-
-### Transform operator
-
-Among the flow transformation operators, the most general one is called [transform]. It can be used to imitate
-simple transformations like [map] and [filter], as well as implement more complex transformations.
-Using the `transform` operator, we can [emit][FlowCollector.emit] arbitrary values an arbitrary number of times.
-
-For example, using `transform` we can emit a string before performing a long-running asynchronous request
-and follow it with a response:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-suspend fun performRequest(request: Int): String {
- delay(1000) // imitate long-running asynchronous work
- return "response $request"
-}
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- (1..3).asFlow() // a flow of requests
- .transform { request ->
- emit("Making request $request")
- emit(performRequest(request))
- }
- .collect { response -> println(response) }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-09.kt).
->
-{type="note"}
-
-The output of this code is:
-
-```text
-Making request 1
-response 1
-Making request 2
-response 2
-Making request 3
-response 3
-```
-
-<!--- TEST -->
-
-### Size-limiting operators
-
-Size-limiting intermediate operators like [take] cancel the execution of the flow when the corresponding limit
-is reached. Cancellation in coroutines is always performed by throwing an exception, so that all the resource-management
-functions (like `try { ... } finally { ... }` blocks) operate normally in case of cancellation:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun numbers(): Flow<Int> = flow {
- try {
- emit(1)
- emit(2)
- println("This line will not execute")
- emit(3)
- } finally {
- println("Finally in numbers")
- }
-}
-
-fun main() = runBlocking<Unit> {
- numbers()
- .take(2) // take only the first two
- .collect { value -> println(value) }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-10.kt).
->
-{type="note"}
-
-The output of this code clearly shows that the execution of the `flow { ... }` body in the `numbers()` function
-stopped after emitting the second number:
-
-```text
-1
-2
-Finally in numbers
-```
-
-<!--- TEST -->
-
-## Terminal flow operators
-
-Terminal operators on flows are _suspending functions_ that start a collection of the flow.
-The [collect] operator is the most basic one, but there are other terminal operators, which can make it easier:
-
-* Conversion to various collections like [toList] and [toSet].
-* Operators to get the [first] value and to ensure that a flow emits a [single] value.
-* Reducing a flow to a value with [reduce] and [fold].
-
-For example:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val sum = (1..5).asFlow()
- .map { it * it } // squares of numbers from 1 to 5
- .reduce { a, b -> a + b } // sum them (terminal operator)
- println(sum)
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-11.kt).
->
-{type="note"}
-
-Prints a single number:
-
-```text
-55
-```
-
-<!--- TEST -->
-
-## Flows are sequential
-
-Each individual collection of a flow is performed sequentially unless special operators that operate
-on multiple flows are used. The collection works directly in the coroutine that calls a terminal operator.
-No new coroutines are launched by default.
-Each emitted value is processed by all the intermediate operators from
-upstream to downstream and is then delivered to the terminal operator after.
-
-See the following example that filters the even integers and maps them to strings:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- (1..5).asFlow()
- .filter {
- println("Filter $it")
- it % 2 == 0
- }
- .map {
- println("Map $it")
- "string $it"
- }.collect {
- println("Collect $it")
- }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-12.kt).
->
-{type="note"}
-
-Producing:
-
-```text
-Filter 1
-Filter 2
-Map 2
-Collect string 2
-Filter 3
-Filter 4
-Map 4
-Collect string 4
-Filter 5
-```
-
-<!--- TEST -->
-
-## Flow context
-
-Collection of a flow always happens in the context of the calling coroutine. For example, if there is
-a `simple` flow, then the following code runs in the context specified
-by the author of this code, regardless of the implementation details of the `simple` flow:
-
-```kotlin
-withContext(context) {
- simple().collect { value ->
- println(value) // run in the specified context
- }
-}
-```
-
-<!--- CLEAR -->
-
-This property of a flow is called _context preservation_.
-
-So, by default, code in the `flow { ... }` builder runs in the context that is provided by a collector
-of the corresponding flow. For example, consider the implementation of a `simple` function that prints the thread
-it is called on and emits three numbers:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
-
-//sampleStart
-fun simple(): Flow<Int> = flow {
- log("Started simple flow")
- for (i in 1..3) {
- emit(i)
- }
-}
-
-fun main() = runBlocking<Unit> {
- simple().collect { value -> log("Collected $value") }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-13.kt).
->
-{type="note"}
-
-Running this code produces:
-
-```text
-[main @coroutine#1] Started simple flow
-[main @coroutine#1] Collected 1
-[main @coroutine#1] Collected 2
-[main @coroutine#1] Collected 3
-```
-
-<!--- TEST FLEXIBLE_THREAD -->
-
-Since `simple().collect` is called from the main thread, the body of `simple`'s flow is also called in the main thread.
-This is the perfect default for fast-running or asynchronous code that does not care about the execution context and
-does not block the caller.
-
-### Wrong emission withContext
-
-However, the long-running CPU-consuming code might need to be executed in the context of [Dispatchers.Default] and UI-updating
-code might need to be executed in the context of [Dispatchers.Main]. Usually, [withContext] is used
-to change the context in the code using Kotlin coroutines, but code in the `flow { ... }` builder has to honor the context
-preservation property and is not allowed to [emit][FlowCollector.emit] from a different context.
-
-Try running the following code:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun simple(): Flow<Int> = flow {
- // The WRONG way to change context for CPU-consuming code in flow builder
- kotlinx.coroutines.withContext(Dispatchers.Default) {
- for (i in 1..3) {
- Thread.sleep(100) // pretend we are computing it in CPU-consuming way
- emit(i) // emit next value
- }
- }
-}
-
-fun main() = runBlocking<Unit> {
- simple().collect { value -> println(value) }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-14.kt).
->
-{type="note"}
-
-This code produces the following exception:
-
-```text
-Exception in thread "main" java.lang.IllegalStateException: Flow invariant is violated:
- Flow was collected in [CoroutineId(1), "coroutine#1":BlockingCoroutine{Active}@5511c7f8, BlockingEventLoop@2eac3323],
- but emission happened in [CoroutineId(1), "coroutine#1":DispatchedCoroutine{Active}@2dae0000, Dispatchers.Default].
- Please refer to 'flow' documentation or use 'flowOn' instead
- at ...
-```
-
-<!--- TEST EXCEPTION -->
-
-### flowOn operator
-
-The exception refers to the [flowOn] function that shall be used to change the context of the flow emission.
-The correct way to change the context of a flow is shown in the example below, which also prints the
-names of the corresponding threads to show how it all works:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
-
-//sampleStart
-fun simple(): Flow<Int> = flow {
- for (i in 1..3) {
- Thread.sleep(100) // pretend we are computing it in CPU-consuming way
- log("Emitting $i")
- emit(i) // emit next value
- }
-}.flowOn(Dispatchers.Default) // RIGHT way to change context for CPU-consuming code in flow builder
-
-fun main() = runBlocking<Unit> {
- simple().collect { value ->
- log("Collected $value")
- }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-15.kt).
->
-{type="note"}
-
-Notice how `flow { ... }` works in the background thread, while collection happens in the main thread:
-
-<!--- TEST FLEXIBLE_THREAD
-[DefaultDispatcher-worker-1 @coroutine#2] Emitting 1
-[main @coroutine#1] Collected 1
-[DefaultDispatcher-worker-1 @coroutine#2] Emitting 2
-[main @coroutine#1] Collected 2
-[DefaultDispatcher-worker-1 @coroutine#2] Emitting 3
-[main @coroutine#1] Collected 3
--->
-
-Another thing to observe here is that the [flowOn] operator has changed the default sequential nature of the flow.
-Now collection happens in one coroutine ("coroutine#1") and emission happens in another coroutine
-("coroutine#2") that is running in another thread concurrently with the collecting coroutine. The [flowOn] operator
-creates another coroutine for an upstream flow when it has to change the [CoroutineDispatcher] in its context.
-
-## Buffering
-
-Running different parts of a flow in different coroutines can be helpful from the standpoint of the overall time it takes
-to collect the flow, especially when long-running asynchronous operations are involved. For example, consider a case when
-the emission by a `simple` flow is slow, taking 100 ms to produce an element; and collector is also slow,
-taking 300 ms to process an element. Let's see how long it takes to collect such a flow with three numbers:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-import kotlin.system.*
-
-//sampleStart
-fun simple(): Flow<Int> = flow {
- for (i in 1..3) {
- delay(100) // pretend we are asynchronously waiting 100 ms
- emit(i) // emit next value
- }
-}
-
-fun main() = runBlocking<Unit> {
- val time = measureTimeMillis {
- simple().collect { value ->
- delay(300) // pretend we are processing it for 300 ms
- println(value)
- }
- }
- println("Collected in $time ms")
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-16.kt).
->
-{type="note"}
-
-It produces something like this, with the whole collection taking around 1200 ms (three numbers, 400 ms for each):
-
-```text
-1
-2
-3
-Collected in 1220 ms
-```
-
-<!--- TEST ARBITRARY_TIME -->
-
-We can use a [buffer] operator on a flow to run emitting code of the `simple` flow concurrently with collecting code,
-as opposed to running them sequentially:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-import kotlin.system.*
-
-fun simple(): Flow<Int> = flow {
- for (i in 1..3) {
- delay(100) // pretend we are asynchronously waiting 100 ms
- emit(i) // emit next value
- }
-}
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val time = measureTimeMillis {
- simple()
- .buffer() // buffer emissions, don't wait
- .collect { value ->
- delay(300) // pretend we are processing it for 300 ms
- println(value)
- }
- }
- println("Collected in $time ms")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-17.kt).
->
-{type="note"}
-
-It produces the same numbers just faster, as we have effectively created a processing pipeline,
-having to only wait 100 ms for the first number and then spending only 300 ms to process
-each number. This way it takes around 1000 ms to run:
-
-```text
-1
-2
-3
-Collected in 1071 ms
-```
-
-<!--- TEST ARBITRARY_TIME -->
-
-> Note that the [flowOn] operator uses the same buffering mechanism when it has to change a [CoroutineDispatcher],
-> but here we explicitly request buffering without changing the execution context.
->
-{type="note"}
-
-### Conflation
-
-When a flow represents partial results of the operation or operation status updates, it may not be necessary
-to process each value, but instead, only most recent ones. In this case, the [conflate] operator can be used to skip
-intermediate values when a collector is too slow to process them. Building on the previous example:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-import kotlin.system.*
-
-fun simple(): Flow<Int> = flow {
- for (i in 1..3) {
- delay(100) // pretend we are asynchronously waiting 100 ms
- emit(i) // emit next value
- }
-}
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val time = measureTimeMillis {
- simple()
- .conflate() // conflate emissions, don't process each one
- .collect { value ->
- delay(300) // pretend we are processing it for 300 ms
- println(value)
- }
- }
- println("Collected in $time ms")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-18.kt).
->
-{type="note"}
-
-We see that while the first number was still being processed the second, and third were already produced, so
-the second one was _conflated_ and only the most recent (the third one) was delivered to the collector:
-
-```text
-1
-3
-Collected in 758 ms
-```
-
-<!--- TEST ARBITRARY_TIME -->
-
-### Processing the latest value
-
-Conflation is one way to speed up processing when both the emitter and collector are slow. It does it by dropping emitted values.
-The other way is to cancel a slow collector and restart it every time a new value is emitted. There is
-a family of `xxxLatest` operators that perform the same essential logic of a `xxx` operator, but cancel the
-code in their block on a new value. Let's try changing [conflate] to [collectLatest] in the previous example:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-import kotlin.system.*
-
-fun simple(): Flow<Int> = flow {
- for (i in 1..3) {
- delay(100) // pretend we are asynchronously waiting 100 ms
- emit(i) // emit next value
- }
-}
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val time = measureTimeMillis {
- simple()
- .collectLatest { value -> // cancel & restart on the latest value
- println("Collecting $value")
- delay(300) // pretend we are processing it for 300 ms
- println("Done $value")
- }
- }
- println("Collected in $time ms")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-19.kt).
->
-{type="note"}
-
-Since the body of [collectLatest] takes 300 ms, but new values are emitted every 100 ms, we see that the block
-is run on every value, but completes only for the last value:
-
-```text
-Collecting 1
-Collecting 2
-Collecting 3
-Done 3
-Collected in 741 ms
-```
-
-<!--- TEST ARBITRARY_TIME -->
-
-## Composing multiple flows
-
-There are lots of ways to compose multiple flows.
-
-### Zip
-
-Just like the [Sequence.zip] extension function in the Kotlin standard library,
-flows have a [zip] operator that combines the corresponding values of two flows:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val nums = (1..3).asFlow() // numbers 1..3
- val strs = flowOf("one", "two", "three") // strings
- nums.zip(strs) { a, b -> "$a -> $b" } // compose a single string
- .collect { println(it) } // collect and print
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-20.kt).
->
-{type="note"}
-
-This example prints:
-
-```text
-1 -> one
-2 -> two
-3 -> three
-```
-
-<!--- TEST -->
-
-### Combine
-
-When flow represents the most recent value of a variable or operation (see also the related
-section on [conflation](#conflation)), it might be needed to perform a computation that depends on
-the most recent values of the corresponding flows and to recompute it whenever any of the upstream
-flows emit a value. The corresponding family of operators is called [combine].
-
-For example, if the numbers in the previous example update every 300ms, but strings update every 400 ms,
-then zipping them using the [zip] operator will still produce the same result,
-albeit results that are printed every 400 ms:
-
-> We use a [onEach] intermediate operator in this example to delay each element and make the code
-> that emits sample flows more declarative and shorter.
->
-{type="note"}
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val nums = (1..3).asFlow().onEach { delay(300) } // numbers 1..3 every 300 ms
- val strs = flowOf("one", "two", "three").onEach { delay(400) } // strings every 400 ms
- val startTime = System.currentTimeMillis() // remember the start time
- nums.zip(strs) { a, b -> "$a -> $b" } // compose a single string with "zip"
- .collect { value -> // collect and print
- println("$value at ${System.currentTimeMillis() - startTime} ms from start")
- }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-21.kt).
->
-{type="note"}
-
-<!--- TEST ARBITRARY_TIME
-1 -> one at 437 ms from start
-2 -> two at 837 ms from start
-3 -> three at 1243 ms from start
--->
-
-However, when using a [combine] operator here instead of a [zip]:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val nums = (1..3).asFlow().onEach { delay(300) } // numbers 1..3 every 300 ms
- val strs = flowOf("one", "two", "three").onEach { delay(400) } // strings every 400 ms
- val startTime = System.currentTimeMillis() // remember the start time
- nums.combine(strs) { a, b -> "$a -> $b" } // compose a single string with "combine"
- .collect { value -> // collect and print
- println("$value at ${System.currentTimeMillis() - startTime} ms from start")
- }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-22.kt).
->
-{type="note"}
-
-We get quite a different output, where a line is printed at each emission from either `nums` or `strs` flows:
-
-```text
-1 -> one at 452 ms from start
-2 -> one at 651 ms from start
-2 -> two at 854 ms from start
-3 -> two at 952 ms from start
-3 -> three at 1256 ms from start
-```
-
-<!--- TEST ARBITRARY_TIME -->
-
-## Flattening flows
-
-Flows represent asynchronously received sequences of values, so it is quite easy to get in a situation where
-each value triggers a request for another sequence of values. For example, we can have the following
-function that returns a flow of two strings 500 ms apart:
-
-```kotlin
-fun requestFlow(i: Int): Flow<String> = flow {
- emit("$i: First")
- delay(500) // wait 500 ms
- emit("$i: Second")
-}
-```
-
-<!--- CLEAR -->
-
-Now if we have a flow of three integers and call `requestFlow` for each of them like this:
-
-```kotlin
-(1..3).asFlow().map { requestFlow(it) }
-```
-
-<!--- CLEAR -->
-
-Then we end up with a flow of flows (`Flow<Flow<String>>`) that needs to be _flattened_ into a single flow for
-further processing. Collections and sequences have [flatten][Sequence.flatten] and [flatMap][Sequence.flatMap]
-operators for this. However, due to the asynchronous nature of flows they call for different _modes_ of flattening,
-as such, there is a family of flattening operators on flows.
-
-### flatMapConcat
-
-Concatenating mode is implemented by [flatMapConcat] and [flattenConcat] operators. They are the most direct
-analogues of the corresponding sequence operators. They wait for the inner flow to complete before
-starting to collect the next one as the following example shows:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun requestFlow(i: Int): Flow<String> = flow {
- emit("$i: First")
- delay(500) // wait 500 ms
- emit("$i: Second")
-}
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val startTime = System.currentTimeMillis() // remember the start time
- (1..3).asFlow().onEach { delay(100) } // a number every 100 ms
- .flatMapConcat { requestFlow(it) }
- .collect { value -> // collect and print
- println("$value at ${System.currentTimeMillis() - startTime} ms from start")
- }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-23.kt).
->
-{type="note"}
-
-The sequential nature of [flatMapConcat] is clearly seen in the output:
-
-```text
-1: First at 121 ms from start
-1: Second at 622 ms from start
-2: First at 727 ms from start
-2: Second at 1227 ms from start
-3: First at 1328 ms from start
-3: Second at 1829 ms from start
-```
-
-<!--- TEST ARBITRARY_TIME -->
-
-### flatMapMerge
-
-Another flattening mode is to concurrently collect all the incoming flows and merge their values into
-a single flow so that values are emitted as soon as possible.
-It is implemented by [flatMapMerge] and [flattenMerge] operators. They both accept an optional
-`concurrency` parameter that limits the number of concurrent flows that are collected at the same time
-(it is equal to [DEFAULT_CONCURRENCY] by default).
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun requestFlow(i: Int): Flow<String> = flow {
- emit("$i: First")
- delay(500) // wait 500 ms
- emit("$i: Second")
-}
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val startTime = System.currentTimeMillis() // remember the start time
- (1..3).asFlow().onEach { delay(100) } // a number every 100 ms
- .flatMapMerge { requestFlow(it) }
- .collect { value -> // collect and print
- println("$value at ${System.currentTimeMillis() - startTime} ms from start")
- }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-24.kt).
->
-{type="note"}
-
-The concurrent nature of [flatMapMerge] is obvious:
-
-```text
-1: First at 136 ms from start
-2: First at 231 ms from start
-3: First at 333 ms from start
-1: Second at 639 ms from start
-2: Second at 732 ms from start
-3: Second at 833 ms from start
-```
-
-<!--- TEST ARBITRARY_TIME -->
-
-> Note that the [flatMapMerge] calls its block of code (`{ requestFlow(it) }` in this example) sequentially, but
-> collects the resulting flows concurrently, it is the equivalent of performing a sequential
-> `map { requestFlow(it) }` first and then calling [flattenMerge] on the result.
->
-{type="note"}
-
-### flatMapLatest
-
-In a similar way to the [collectLatest] operator, that was shown in
-["Processing the latest value"](#processing-the-latest-value) section, there is the corresponding "Latest"
-flattening mode where a collection of the previous flow is cancelled as soon as new flow is emitted.
-It is implemented by the [flatMapLatest] operator.
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun requestFlow(i: Int): Flow<String> = flow {
- emit("$i: First")
- delay(500) // wait 500 ms
- emit("$i: Second")
-}
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val startTime = System.currentTimeMillis() // remember the start time
- (1..3).asFlow().onEach { delay(100) } // a number every 100 ms
- .flatMapLatest { requestFlow(it) }
- .collect { value -> // collect and print
- println("$value at ${System.currentTimeMillis() - startTime} ms from start")
- }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-25.kt).
->
-{type="note"}
-
-The output here in this example is a good demonstration of how [flatMapLatest] works:
-
-```text
-1: First at 142 ms from start
-2: First at 322 ms from start
-3: First at 425 ms from start
-3: Second at 931 ms from start
-```
-
-<!--- TEST ARBITRARY_TIME -->
-
-> Note that [flatMapLatest] cancels all the code in its block (`{ requestFlow(it) }` in this example) on a new value.
-> It makes no difference in this particular example, because the call to `requestFlow` itself is fast, not-suspending,
-> and cannot be cancelled. However, it would show up if we were to use suspending functions like `delay` in there.
->
-{type="note"}
-
-## Flow exceptions
-
-Flow collection can complete with an exception when an emitter or code inside the operators throw an exception.
-There are several ways to handle these exceptions.
-
-### Collector try and catch
-
-A collector can use Kotlin's [`try/catch`][exceptions] block to handle exceptions:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun simple(): Flow<Int> = flow {
- for (i in 1..3) {
- println("Emitting $i")
- emit(i) // emit next value
- }
-}
-
-fun main() = runBlocking<Unit> {
- try {
- simple().collect { value ->
- println(value)
- check(value <= 1) { "Collected $value" }
- }
- } catch (e: Throwable) {
- println("Caught $e")
- }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-26.kt).
->
-{type="note"}
-
-This code successfully catches an exception in [collect] terminal operator and,
-as we see, no more values are emitted after that:
-
-```text
-Emitting 1
-1
-Emitting 2
-2
-Caught java.lang.IllegalStateException: Collected 2
-```
-
-<!--- TEST -->
-
-### Everything is caught
-
-The previous example actually catches any exception happening in the emitter or in any intermediate or terminal operators.
-For example, let's change the code so that emitted values are [mapped][map] to strings,
-but the corresponding code produces an exception:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun simple(): Flow<String> =
- flow {
- for (i in 1..3) {
- println("Emitting $i")
- emit(i) // emit next value
- }
- }
- .map { value ->
- check(value <= 1) { "Crashed on $value" }
- "string $value"
- }
-
-fun main() = runBlocking<Unit> {
- try {
- simple().collect { value -> println(value) }
- } catch (e: Throwable) {
- println("Caught $e")
- }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-27.kt).
->
-{type="note"}
-
-This exception is still caught and collection is stopped:
-
-```text
-Emitting 1
-string 1
-Emitting 2
-Caught java.lang.IllegalStateException: Crashed on 2
-```
-
-<!--- TEST -->
-
-## Exception transparency
-
-But how can code of the emitter encapsulate its exception handling behavior?
-
-Flows must be _transparent to exceptions_ and it is a violation of the exception transparency to [emit][FlowCollector.emit] values in the
-`flow { ... }` builder from inside of a `try/catch` block. This guarantees that a collector throwing an exception
-can always catch it using `try/catch` as in the previous example.
-
-The emitter can use a [catch] operator that preserves this exception transparency and allows encapsulation
-of its exception handling. The body of the `catch` operator can analyze an exception
-and react to it in different ways depending on which exception was caught:
-
-* Exceptions can be rethrown using `throw`.
-* Exceptions can be turned into emission of values using [emit][FlowCollector.emit] from the body of [catch].
-* Exceptions can be ignored, logged, or processed by some other code.
-
-For example, let us emit the text on catching an exception:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun simple(): Flow<String> =
- flow {
- for (i in 1..3) {
- println("Emitting $i")
- emit(i) // emit next value
- }
- }
- .map { value ->
- check(value <= 1) { "Crashed on $value" }
- "string $value"
- }
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- simple()
- .catch { e -> emit("Caught $e") } // emit on exception
- .collect { value -> println(value) }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-28.kt).
->
-{type="note"}
-
-The output of the example is the same, even though we do not have `try/catch` around the code anymore.
-
-<!--- TEST
-Emitting 1
-string 1
-Emitting 2
-Caught java.lang.IllegalStateException: Crashed on 2
--->
-
-### Transparent catch
-
-The [catch] intermediate operator, honoring exception transparency, catches only upstream exceptions
-(that is an exception from all the operators above `catch`, but not below it).
-If the block in `collect { ... }` (placed below `catch`) throws an exception then it escapes:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun simple(): Flow<Int> = flow {
- for (i in 1..3) {
- println("Emitting $i")
- emit(i)
- }
-}
-
-fun main() = runBlocking<Unit> {
- simple()
- .catch { e -> println("Caught $e") } // does not catch downstream exceptions
- .collect { value ->
- check(value <= 1) { "Collected $value" }
- println(value)
- }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-29.kt).
->
-{type="note"}
-
-A "Caught ..." message is not printed despite there being a `catch` operator:
-
-```text
-Emitting 1
-1
-Emitting 2
-Exception in thread "main" java.lang.IllegalStateException: Collected 2
- at ...
-```
-
-<!--- TEST EXCEPTION -->
-
-### Catching declaratively
-
-We can combine the declarative nature of the [catch] operator with a desire to handle all the exceptions, by moving the body
-of the [collect] operator into [onEach] and putting it before the `catch` operator. Collection of this flow must
-be triggered by a call to `collect()` without parameters:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun simple(): Flow<Int> = flow {
- for (i in 1..3) {
- println("Emitting $i")
- emit(i)
- }
-}
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- simple()
- .onEach { value ->
- check(value <= 1) { "Collected $value" }
- println(value)
- }
- .catch { e -> println("Caught $e") }
- .collect()
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-30.kt).
->
-{type="note"}
-
-Now we can see that a "Caught ..." message is printed and so we can catch all the exceptions without explicitly
-using a `try/catch` block:
-
-```text
-Emitting 1
-1
-Emitting 2
-Caught java.lang.IllegalStateException: Collected 2
-```
-
-<!--- TEST EXCEPTION -->
-
-## Flow completion
-
-When flow collection completes (normally or exceptionally) it may need to execute an action.
-As you may have already noticed, it can be done in two ways: imperative or declarative.
-
-### Imperative finally block
-
-In addition to `try`/`catch`, a collector can also use a `finally` block to execute an action
-upon `collect` completion.
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun simple(): Flow<Int> = (1..3).asFlow()
-
-fun main() = runBlocking<Unit> {
- try {
- simple().collect { value -> println(value) }
- } finally {
- println("Done")
- }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-31.kt).
->
-{type="note"}
-
-This code prints three numbers produced by the `simple` flow followed by a "Done" string:
-
-```text
-1
-2
-3
-Done
-```
-
-<!--- TEST -->
-
-### Declarative handling
-
-For the declarative approach, flow has [onCompletion] intermediate operator that is invoked
-when the flow has completely collected.
-
-The previous example can be rewritten using an [onCompletion] operator and produces the same output:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-fun simple(): Flow<Int> = (1..3).asFlow()
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- simple()
- .onCompletion { println("Done") }
- .collect { value -> println(value) }
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-32.kt).
->
-{type="note"}
-
-<!--- TEST
-1
-2
-3
-Done
--->
-
-The key advantage of [onCompletion] is a nullable `Throwable` parameter of the lambda that can be used
-to determine whether the flow collection was completed normally or exceptionally. In the following
-example the `simple` flow throws an exception after emitting the number 1:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun simple(): Flow<Int> = flow {
- emit(1)
- throw RuntimeException()
-}
-
-fun main() = runBlocking<Unit> {
- simple()
- .onCompletion { cause -> if (cause != null) println("Flow completed exceptionally") }
- .catch { cause -> println("Caught exception") }
- .collect { value -> println(value) }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-33.kt).
->
-{type="note"}
-
-As you may expect, it prints:
-
-```text
-1
-Flow completed exceptionally
-Caught exception
-```
-
-<!--- TEST -->
-
-The [onCompletion] operator, unlike [catch], does not handle the exception. As we can see from the above
-example code, the exception still flows downstream. It will be delivered to further `onCompletion` operators
-and can be handled with a `catch` operator.
-
-### Successful completion
-
-Another difference with [catch] operator is that [onCompletion] sees all exceptions and receives
-a `null` exception only on successful completion of the upstream flow (without cancellation or failure).
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun simple(): Flow<Int> = (1..3).asFlow()
-
-fun main() = runBlocking<Unit> {
- simple()
- .onCompletion { cause -> println("Flow completed with $cause") }
- .collect { value ->
- check(value <= 1) { "Collected $value" }
- println(value)
- }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-34.kt).
->
-{type="note"}
-
-We can see the completion cause is not null, because the flow was aborted due to downstream exception:
-
-```text
-1
-Flow completed with java.lang.IllegalStateException: Collected 2
-Exception in thread "main" java.lang.IllegalStateException: Collected 2
-```
-
-<!--- TEST EXCEPTION -->
-
-## Imperative versus declarative
-
-Now we know how to collect flow, and handle its completion and exceptions in both imperative and declarative ways.
-The natural question here is, which approach is preferred and why?
-As a library, we do not advocate for any particular approach and believe that both options
-are valid and should be selected according to your own preferences and code style.
-
-## Launching flow
-
-It is easy to use flows to represent asynchronous events that are coming from some source.
-In this case, we need an analogue of the `addEventListener` function that registers a piece of code with a reaction
-for incoming events and continues further work. The [onEach] operator can serve this role.
-However, `onEach` is an intermediate operator. We also need a terminal operator to collect the flow.
-Otherwise, just calling `onEach` has no effect.
-
-If we use the [collect] terminal operator after `onEach`, then the code after it will wait until the flow is collected:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-// Imitate a flow of events
-fun events(): Flow<Int> = (1..3).asFlow().onEach { delay(100) }
-
-fun main() = runBlocking<Unit> {
- events()
- .onEach { event -> println("Event: $event") }
- .collect() // <--- Collecting the flow waits
- println("Done")
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-35.kt).
->
-{type="note"}
-
-As you can see, it prints:
-
-```text
-Event: 1
-Event: 2
-Event: 3
-Done
-```
-
-<!--- TEST -->
-
-The [launchIn] terminal operator comes in handy here. By replacing `collect` with `launchIn` we can
-launch a collection of the flow in a separate coroutine, so that execution of further code
-immediately continues:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-// Imitate a flow of events
-fun events(): Flow<Int> = (1..3).asFlow().onEach { delay(100) }
-
-//sampleStart
-fun main() = runBlocking<Unit> {
- events()
- .onEach { event -> println("Event: $event") }
- .launchIn(this) // <--- Launching the flow in a separate coroutine
- println("Done")
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-36.kt).
->
-{type="note"}
-
-It prints:
-
-```text
-Done
-Event: 1
-Event: 2
-Event: 3
-```
-
-<!--- TEST -->
-
-The required parameter to `launchIn` must specify a [CoroutineScope] in which the coroutine to collect the flow is
-launched. In the above example this scope comes from the [runBlocking]
-coroutine builder, so while the flow is running, this [runBlocking] scope waits for completion of its child coroutine
-and keeps the main function from returning and terminating this example.
-
-In actual applications a scope will come from an entity with a limited
-lifetime. As soon as the lifetime of this entity is terminated the corresponding scope is cancelled, cancelling
-the collection of the corresponding flow. This way the pair of `onEach { ... }.launchIn(scope)` works
-like the `addEventListener`. However, there is no need for the corresponding `removeEventListener` function,
-as cancellation and structured concurrency serve this purpose.
-
-Note that [launchIn] also returns a [Job], which can be used to [cancel][Job.cancel] the corresponding flow collection
-coroutine only without cancelling the whole scope or to [join][Job.join] it.
-
-### Flow cancellation checks
-
-For convenience, the [flow][_flow] builder performs additional [ensureActive] checks for cancellation on each emitted value.
-It means that a busy loop emitting from a `flow { ... }` is cancellable:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun foo(): Flow<Int> = flow {
- for (i in 1..5) {
- println("Emitting $i")
- emit(i)
- }
-}
-
-fun main() = runBlocking<Unit> {
- foo().collect { value ->
- if (value == 3) cancel()
- println(value)
- }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-37.kt).
->
-{type="note"}
-
-We get only numbers up to 3 and a [CancellationException] after trying to emit number 4:
-
-```text
-Emitting 1
-1
-Emitting 2
-2
-Emitting 3
-3
-Emitting 4
-Exception in thread "main" kotlinx.coroutines.JobCancellationException: BlockingCoroutine was cancelled; job="coroutine#1":BlockingCoroutine{Cancelled}@6d7b4f4c
-```
-
-<!--- TEST EXCEPTION -->
-
-However, most other flow operators do not do additional cancellation checks on their own for performance reasons.
-For example, if you use [IntRange.asFlow] extension to write the same busy loop and don't suspend anywhere,
-then there are no checks for cancellation:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun main() = runBlocking<Unit> {
- (1..5).asFlow().collect { value ->
- if (value == 3) cancel()
- println(value)
- }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-38.kt).
->
-{type="note"}
-
-All numbers from 1 to 5 are collected and cancellation gets detected only before return from `runBlocking`:
-
-```text
-1
-2
-3
-4
-5
-Exception in thread "main" kotlinx.coroutines.JobCancellationException: BlockingCoroutine was cancelled; job="coroutine#1":BlockingCoroutine{Cancelled}@3327bd23
-```
-
-<!--- TEST EXCEPTION -->
-
-#### Making busy flow cancellable
-
-In the case where you have a busy loop with coroutines you must explicitly check for cancellation.
-You can add `.onEach { currentCoroutineContext().ensureActive() }`, but there is a ready-to-use
-[cancellable] operator provided to do that:
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.*
-
-//sampleStart
-fun main() = runBlocking<Unit> {
- (1..5).asFlow().cancellable().collect { value ->
- if (value == 3) cancel()
- println(value)
- }
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code from [here](../../kotlinx-coroutines-core/jvm/test/guide/example-flow-39.kt).
->
-{type="note"}
-
-With the `cancellable` operator only the numbers from 1 to 3 are collected:
-
-```text
-1
-2
-3
-Exception in thread "main" kotlinx.coroutines.JobCancellationException: BlockingCoroutine was cancelled; job="coroutine#1":BlockingCoroutine{Cancelled}@5ec0a365
-```
-
-<!--- TEST EXCEPTION -->
-
-## Flow and Reactive Streams
-
-For those who are familiar with [Reactive Streams](https://www.reactive-streams.org/) or reactive frameworks such as RxJava and project Reactor,
-design of the Flow may look very familiar.
-
-Indeed, its design was inspired by Reactive Streams and its various implementations. But Flow main goal is to have as simple design as possible,
-be Kotlin and suspension friendly and respect structured concurrency. Achieving this goal would be impossible without reactive pioneers and their tremendous work. You can read the complete story in [Reactive Streams and Kotlin Flows](https://medium.com/@elizarov/reactive-streams-and-kotlin-flows-bfd12772cda4) article.
-
-While being different, conceptually, Flow *is* a reactive stream and it is possible to convert it to the reactive (spec and TCK compliant) Publisher and vice versa.
-Such converters are provided by `kotlinx.coroutines` out-of-the-box and can be found in corresponding reactive modules (`kotlinx-coroutines-reactive` for Reactive Streams, `kotlinx-coroutines-reactor` for Project Reactor and `kotlinx-coroutines-rx2`/`kotlinx-coroutines-rx3` for RxJava2/RxJava3).
-Integration modules include conversions from and to `Flow`, integration with Reactor's `Context` and suspension-friendly ways to work with various reactive entities.
-
-<!-- stdlib references -->
-
-[collections]: https://kotlinlang.org/docs/reference/collections-overview.html
-[List]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html
-[forEach]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/for-each.html
-[Sequence]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/index.html
-[Sequence.zip]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/zip.html
-[Sequence.flatten]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/flatten.html
-[Sequence.flatMap]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/flat-map.html
-[exceptions]: https://kotlinlang.org/docs/reference/exceptions.html
-
-<!--- MODULE kotlinx-coroutines-core -->
-<!--- INDEX kotlinx.coroutines -->
-
-[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
-[withTimeoutOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout-or-null.html
-[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html
-[Dispatchers.Main]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html
-[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
-[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html
-[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
-[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
-[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
-[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html
-[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
-[ensureActive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-active.html
-[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html
-
-<!--- INDEX kotlinx.coroutines.flow -->
-
-[Flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html
-[_flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow.html
-[FlowCollector.emit]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow-collector/emit.html
-[collect]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/collect.html
-[flowOf]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow-of.html
-[map]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/map.html
-[filter]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/filter.html
-[transform]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/transform.html
-[take]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/take.html
-[toList]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/to-list.html
-[toSet]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/to-set.html
-[first]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/first.html
-[single]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/single.html
-[reduce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/reduce.html
-[fold]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/fold.html
-[flowOn]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow-on.html
-[buffer]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/buffer.html
-[conflate]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/conflate.html
-[collectLatest]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/collect-latest.html
-[zip]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/zip.html
-[combine]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/combine.html
-[onEach]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/on-each.html
-[flatMapConcat]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flat-map-concat.html
-[flattenConcat]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flatten-concat.html
-[flatMapMerge]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flat-map-merge.html
-[flattenMerge]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flatten-merge.html
-[DEFAULT_CONCURRENCY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-d-e-f-a-u-l-t_-c-o-n-c-u-r-r-e-n-c-y.html
-[flatMapLatest]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flat-map-latest.html
-[catch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/catch.html
-[onCompletion]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/on-completion.html
-[launchIn]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/launch-in.html
-[IntRange.asFlow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/kotlin.ranges.-int-range/as-flow.html
-[cancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/cancellable.html
-
-<!--- END -->
diff --git a/docs/topics/knit.properties b/docs/topics/knit.properties
deleted file mode 100644
index 562b4121..00000000
--- a/docs/topics/knit.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
-#
-
-knit.package=kotlinx.coroutines.guide
-knit.dir=../../kotlinx-coroutines-core/jvm/test/guide/
-
-test.package=kotlinx.coroutines.guide.test
-test.dir=../../kotlinx-coroutines-core/jvm/test/guide/test/
diff --git a/docs/topics/select-expression.md b/docs/topics/select-expression.md
deleted file mode 100644
index 082a50d6..00000000
--- a/docs/topics/select-expression.md
+++ /dev/null
@@ -1,502 +0,0 @@
-<!--- TEST_NAME SelectGuideTest -->
-
-[//]: # (title: Select expression \(experimental\))
-
-Select expression makes it possible to await multiple suspending functions simultaneously and _select_
-the first one that becomes available.
-
-> Select expressions are an experimental feature of `kotlinx.coroutines`. Their API is expected to
-> evolve in the upcoming updates of the `kotlinx.coroutines` library with potentially
-> breaking changes.
->
-{type="note"}
-
-## Selecting from channels
-
-Let us have two producers of strings: `fizz` and `buzz`. The `fizz` produces "Fizz" string every 300 ms:
-
-```kotlin
-fun CoroutineScope.fizz() = produce<String> {
- while (true) { // sends "Fizz" every 300 ms
- delay(300)
- send("Fizz")
- }
-}
-```
-
-And the `buzz` produces "Buzz!" string every 500 ms:
-
-```kotlin
-fun CoroutineScope.buzz() = produce<String> {
- while (true) { // sends "Buzz!" every 500 ms
- delay(500)
- send("Buzz!")
- }
-}
-```
-
-Using [receive][ReceiveChannel.receive] suspending function we can receive _either_ from one channel or the
-other. But [select] expression allows us to receive from _both_ simultaneously using its
-[onReceive][ReceiveChannel.onReceive] clauses:
-
-```kotlin
-suspend fun selectFizzBuzz(fizz: ReceiveChannel<String>, buzz: ReceiveChannel<String>) {
- select<Unit> { // <Unit> means that this select expression does not produce any result
- fizz.onReceive { value -> // this is the first select clause
- println("fizz -> '$value'")
- }
- buzz.onReceive { value -> // this is the second select clause
- println("buzz -> '$value'")
- }
- }
-}
-```
-
-Let us run it all seven times:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-import kotlinx.coroutines.selects.*
-
-fun CoroutineScope.fizz() = produce<String> {
- while (true) { // sends "Fizz" every 300 ms
- delay(300)
- send("Fizz")
- }
-}
-
-fun CoroutineScope.buzz() = produce<String> {
- while (true) { // sends "Buzz!" every 500 ms
- delay(500)
- send("Buzz!")
- }
-}
-
-suspend fun selectFizzBuzz(fizz: ReceiveChannel<String>, buzz: ReceiveChannel<String>) {
- select<Unit> { // <Unit> means that this select expression does not produce any result
- fizz.onReceive { value -> // this is the first select clause
- println("fizz -> '$value'")
- }
- buzz.onReceive { value -> // this is the second select clause
- println("buzz -> '$value'")
- }
- }
-}
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val fizz = fizz()
- val buzz = buzz()
- repeat(7) {
- selectFizzBuzz(fizz, buzz)
- }
- coroutineContext.cancelChildren() // cancel fizz & buzz coroutines
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-select-01.kt).
->
-{type="note"}
-
-The result of this code is:
-
-```text
-fizz -> 'Fizz'
-buzz -> 'Buzz!'
-fizz -> 'Fizz'
-fizz -> 'Fizz'
-buzz -> 'Buzz!'
-fizz -> 'Fizz'
-buzz -> 'Buzz!'
-```
-
-<!--- TEST -->
-
-## Selecting on close
-
-The [onReceive][ReceiveChannel.onReceive] clause in `select` fails when the channel is closed causing the corresponding
-`select` to throw an exception. We can use [onReceiveOrNull][onReceiveOrNull] clause to perform a
-specific action when the channel is closed. The following example also shows that `select` is an expression that returns
-the result of its selected clause:
-
-```kotlin
-suspend fun selectAorB(a: ReceiveChannel<String>, b: ReceiveChannel<String>): String =
- select<String> {
- a.onReceiveOrNull { value ->
- if (value == null)
- "Channel 'a' is closed"
- else
- "a -> '$value'"
- }
- b.onReceiveOrNull { value ->
- if (value == null)
- "Channel 'b' is closed"
- else
- "b -> '$value'"
- }
- }
-```
-
-Note that [onReceiveOrNull][onReceiveOrNull] is an extension function defined only
-for channels with non-nullable elements so that there is no accidental confusion between a closed channel
-and a null value.
-
-Let's use it with channel `a` that produces "Hello" string four times and
-channel `b` that produces "World" four times:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-import kotlinx.coroutines.selects.*
-
-suspend fun selectAorB(a: ReceiveChannel<String>, b: ReceiveChannel<String>): String =
- select<String> {
- a.onReceiveOrNull { value ->
- if (value == null)
- "Channel 'a' is closed"
- else
- "a -> '$value'"
- }
- b.onReceiveOrNull { value ->
- if (value == null)
- "Channel 'b' is closed"
- else
- "b -> '$value'"
- }
- }
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val a = produce<String> {
- repeat(4) { send("Hello $it") }
- }
- val b = produce<String> {
- repeat(4) { send("World $it") }
- }
- repeat(8) { // print first eight results
- println(selectAorB(a, b))
- }
- coroutineContext.cancelChildren()
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-select-02.kt).
->
-{type="note"}
-
-The result of this code is quite interesting, so we'll analyze it in more detail:
-
-```text
-a -> 'Hello 0'
-a -> 'Hello 1'
-b -> 'World 0'
-a -> 'Hello 2'
-a -> 'Hello 3'
-b -> 'World 1'
-Channel 'a' is closed
-Channel 'a' is closed
-```
-
-<!--- TEST -->
-
-There are couple of observations to make out of it.
-
-First of all, `select` is _biased_ to the first clause. When several clauses are selectable at the same time,
-the first one among them gets selected. Here, both channels are constantly producing strings, so `a` channel,
-being the first clause in select, wins. However, because we are using unbuffered channel, the `a` gets suspended from
-time to time on its [send][SendChannel.send] invocation and gives a chance for `b` to send, too.
-
-The second observation, is that [onReceiveOrNull][onReceiveOrNull] gets immediately selected when the
-channel is already closed.
-
-## Selecting to send
-
-Select expression has [onSend][SendChannel.onSend] clause that can be used for a great good in combination
-with a biased nature of selection.
-
-Let us write an example of producer of integers that sends its values to a `side` channel when
-the consumers on its primary channel cannot keep up with it:
-
-```kotlin
-fun CoroutineScope.produceNumbers(side: SendChannel<Int>) = produce<Int> {
- for (num in 1..10) { // produce 10 numbers from 1 to 10
- delay(100) // every 100 ms
- select<Unit> {
- onSend(num) {} // Send to the primary channel
- side.onSend(num) {} // or to the side channel
- }
- }
-}
-```
-
-Consumer is going to be quite slow, taking 250 ms to process each number:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-import kotlinx.coroutines.selects.*
-
-fun CoroutineScope.produceNumbers(side: SendChannel<Int>) = produce<Int> {
- for (num in 1..10) { // produce 10 numbers from 1 to 10
- delay(100) // every 100 ms
- select<Unit> {
- onSend(num) {} // Send to the primary channel
- side.onSend(num) {} // or to the side channel
- }
- }
-}
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val side = Channel<Int>() // allocate side channel
- launch { // this is a very fast consumer for the side channel
- side.consumeEach { println("Side channel has $it") }
- }
- produceNumbers(side).consumeEach {
- println("Consuming $it")
- delay(250) // let us digest the consumed number properly, do not hurry
- }
- println("Done consuming")
- coroutineContext.cancelChildren()
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-select-03.kt).
->
-{type="note"}
-
-So let us see what happens:
-
-```text
-Consuming 1
-Side channel has 2
-Side channel has 3
-Consuming 4
-Side channel has 5
-Side channel has 6
-Consuming 7
-Side channel has 8
-Side channel has 9
-Consuming 10
-Done consuming
-```
-
-<!--- TEST -->
-
-## Selecting deferred values
-
-Deferred values can be selected using [onAwait][Deferred.onAwait] clause.
-Let us start with an async function that returns a deferred string value after
-a random delay:
-
-```kotlin
-fun CoroutineScope.asyncString(time: Int) = async {
- delay(time.toLong())
- "Waited for $time ms"
-}
-```
-
-Let us start a dozen of them with a random delay.
-
-```kotlin
-fun CoroutineScope.asyncStringsList(): List<Deferred<String>> {
- val random = Random(3)
- return List(12) { asyncString(random.nextInt(1000)) }
-}
-```
-
-Now the main function awaits for the first of them to complete and counts the number of deferred values
-that are still active. Note that we've used here the fact that `select` expression is a Kotlin DSL,
-so we can provide clauses for it using an arbitrary code. In this case we iterate over a list
-of deferred values to provide `onAwait` clause for each deferred value.
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.selects.*
-import java.util.*
-
-fun CoroutineScope.asyncString(time: Int) = async {
- delay(time.toLong())
- "Waited for $time ms"
-}
-
-fun CoroutineScope.asyncStringsList(): List<Deferred<String>> {
- val random = Random(3)
- return List(12) { asyncString(random.nextInt(1000)) }
-}
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val list = asyncStringsList()
- val result = select<String> {
- list.withIndex().forEach { (index, deferred) ->
- deferred.onAwait { answer ->
- "Deferred $index produced answer '$answer'"
- }
- }
- }
- println(result)
- val countActive = list.count { it.isActive }
- println("$countActive coroutines are still active")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-select-04.kt).
->
-{type="note"}
-
-The output is:
-
-```text
-Deferred 4 produced answer 'Waited for 128 ms'
-11 coroutines are still active
-```
-
-<!--- TEST -->
-
-## Switch over a channel of deferred values
-
-Let us write a channel producer function that consumes a channel of deferred string values, waits for each received
-deferred value, but only until the next deferred value comes over or the channel is closed. This example puts together
-[onReceiveOrNull][onReceiveOrNull] and [onAwait][Deferred.onAwait] clauses in the same `select`:
-
-```kotlin
-fun CoroutineScope.switchMapDeferreds(input: ReceiveChannel<Deferred<String>>) = produce<String> {
- var current = input.receive() // start with first received deferred value
- while (isActive) { // loop while not cancelled/closed
- val next = select<Deferred<String>?> { // return next deferred value from this select or null
- input.onReceiveOrNull { update ->
- update // replaces next value to wait
- }
- current.onAwait { value ->
- send(value) // send value that current deferred has produced
- input.receiveOrNull() // and use the next deferred from the input channel
- }
- }
- if (next == null) {
- println("Channel was closed")
- break // out of loop
- } else {
- current = next
- }
- }
-}
-```
-
-To test it, we'll use a simple async function that resolves to a specified string after a specified time:
-
-```kotlin
-fun CoroutineScope.asyncString(str: String, time: Long) = async {
- delay(time)
- str
-}
-```
-
-The main function just launches a coroutine to print results of `switchMapDeferreds` and sends some test
-data to it:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-import kotlinx.coroutines.selects.*
-
-fun CoroutineScope.switchMapDeferreds(input: ReceiveChannel<Deferred<String>>) = produce<String> {
- var current = input.receive() // start with first received deferred value
- while (isActive) { // loop while not cancelled/closed
- val next = select<Deferred<String>?> { // return next deferred value from this select or null
- input.onReceiveOrNull { update ->
- update // replaces next value to wait
- }
- current.onAwait { value ->
- send(value) // send value that current deferred has produced
- input.receiveOrNull() // and use the next deferred from the input channel
- }
- }
- if (next == null) {
- println("Channel was closed")
- break // out of loop
- } else {
- current = next
- }
- }
-}
-
-fun CoroutineScope.asyncString(str: String, time: Long) = async {
- delay(time)
- str
-}
-
-fun main() = runBlocking<Unit> {
-//sampleStart
- val chan = Channel<Deferred<String>>() // the channel for test
- launch { // launch printing coroutine
- for (s in switchMapDeferreds(chan))
- println(s) // print each received string
- }
- chan.send(asyncString("BEGIN", 100))
- delay(200) // enough time for "BEGIN" to be produced
- chan.send(asyncString("Slow", 500))
- delay(100) // not enough time to produce slow
- chan.send(asyncString("Replace", 100))
- delay(500) // give it time before the last one
- chan.send(asyncString("END", 500))
- delay(1000) // give it time to process
- chan.close() // close the channel ...
- delay(500) // and wait some time to let it finish
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-select-05.kt).
->
-{type="note"}
-
-The result of this code:
-
-```text
-BEGIN
-Replace
-END
-Channel was closed
-```
-
-<!--- TEST -->
-
-<!--- MODULE kotlinx-coroutines-core -->
-<!--- INDEX kotlinx.coroutines -->
-
-[Deferred.onAwait]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/on-await.html
-
-<!--- INDEX kotlinx.coroutines.channels -->
-
-[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive.html
-[ReceiveChannel.onReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive.html
-[onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/on-receive-or-null.html
-[SendChannel.send]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/send.html
-[SendChannel.onSend]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/on-send.html
-
-<!--- INDEX kotlinx.coroutines.selects -->
-
-[select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html
-
-<!--- END --> \ No newline at end of file
diff --git a/docs/topics/shared-mutable-state-and-concurrency.md b/docs/topics/shared-mutable-state-and-concurrency.md
deleted file mode 100644
index b4b68b30..00000000
--- a/docs/topics/shared-mutable-state-and-concurrency.md
+++ /dev/null
@@ -1,513 +0,0 @@
-<!--- TEST_NAME SharedStateGuideTest -->
-
-[//]: # (title: Shared mutable state and concurrency)
-
-Coroutines can be executed concurrently using a multi-threaded dispatcher like the [Dispatchers.Default]. It presents
-all the usual concurrency problems. The main problem being synchronization of access to **shared mutable state**.
-Some solutions to this problem in the land of coroutines are similar to the solutions in the multi-threaded world,
-but others are unique.
-
-## The problem
-
-Let us launch a hundred coroutines all doing the same action thousand times.
-We'll also measure their completion time for further comparisons:
-
-```kotlin
-suspend fun massiveRun(action: suspend () -> Unit) {
- val n = 100 // number of coroutines to launch
- val k = 1000 // times an action is repeated by each coroutine
- val time = measureTimeMillis {
- coroutineScope { // scope for coroutines
- repeat(n) {
- launch {
- repeat(k) { action() }
- }
- }
- }
- }
- println("Completed ${n * k} actions in $time ms")
-}
-```
-
-We start with a very simple action that increments a shared mutable variable using
-multi-threaded [Dispatchers.Default].
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlin.system.*
-
-suspend fun massiveRun(action: suspend () -> Unit) {
- val n = 100 // number of coroutines to launch
- val k = 1000 // times an action is repeated by each coroutine
- val time = measureTimeMillis {
- coroutineScope { // scope for coroutines
- repeat(n) {
- launch {
- repeat(k) { action() }
- }
- }
- }
- }
- println("Completed ${n * k} actions in $time ms")
-}
-
-//sampleStart
-var counter = 0
-
-fun main() = runBlocking {
- withContext(Dispatchers.Default) {
- massiveRun {
- counter++
- }
- }
- println("Counter = $counter")
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-sync-01.kt).
->
-{type="note"}
-
-<!--- TEST LINES_START
-Completed 100000 actions in
-Counter =
--->
-
-What does it print at the end? It is highly unlikely to ever print "Counter = 100000", because a hundred coroutines
-increment the `counter` concurrently from multiple threads without any synchronization.
-
-## Volatiles are of no help
-
-There is a common misconception that making a variable `volatile` solves concurrency problem. Let us try it:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlin.system.*
-
-suspend fun massiveRun(action: suspend () -> Unit) {
- val n = 100 // number of coroutines to launch
- val k = 1000 // times an action is repeated by each coroutine
- val time = measureTimeMillis {
- coroutineScope { // scope for coroutines
- repeat(n) {
- launch {
- repeat(k) { action() }
- }
- }
- }
- }
- println("Completed ${n * k} actions in $time ms")
-}
-
-//sampleStart
-@Volatile // in Kotlin `volatile` is an annotation
-var counter = 0
-
-fun main() = runBlocking {
- withContext(Dispatchers.Default) {
- massiveRun {
- counter++
- }
- }
- println("Counter = $counter")
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-sync-02.kt).
->
-{type="note"}
-
-<!--- TEST LINES_START
-Completed 100000 actions in
-Counter =
--->
-
-This code works slower, but we still don't get "Counter = 100000" at the end, because volatile variables guarantee
-linearizable (this is a technical term for "atomic") reads and writes to the corresponding variable, but
-do not provide atomicity of larger actions (increment in our case).
-
-## Thread-safe data structures
-
-The general solution that works both for threads and for coroutines is to use a thread-safe (aka synchronized,
-linearizable, or atomic) data structure that provides all the necessary synchronization for the corresponding
-operations that needs to be performed on a shared state.
-In the case of a simple counter we can use `AtomicInteger` class which has atomic `incrementAndGet` operations:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import java.util.concurrent.atomic.*
-import kotlin.system.*
-
-suspend fun massiveRun(action: suspend () -> Unit) {
- val n = 100 // number of coroutines to launch
- val k = 1000 // times an action is repeated by each coroutine
- val time = measureTimeMillis {
- coroutineScope { // scope for coroutines
- repeat(n) {
- launch {
- repeat(k) { action() }
- }
- }
- }
- }
- println("Completed ${n * k} actions in $time ms")
-}
-
-//sampleStart
-val counter = AtomicInteger()
-
-fun main() = runBlocking {
- withContext(Dispatchers.Default) {
- massiveRun {
- counter.incrementAndGet()
- }
- }
- println("Counter = $counter")
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-sync-03.kt).
->
-{type="note"}
-
-<!--- TEST ARBITRARY_TIME
-Completed 100000 actions in xxx ms
-Counter = 100000
--->
-
-This is the fastest solution for this particular problem. It works for plain counters, collections, queues and other
-standard data structures and basic operations on them. However, it does not easily scale to complex
-state or to complex operations that do not have ready-to-use thread-safe implementations.
-
-## Thread confinement fine-grained
-
-_Thread confinement_ is an approach to the problem of shared mutable state where all access to the particular shared
-state is confined to a single thread. It is typically used in UI applications, where all UI state is confined to
-the single event-dispatch/application thread. It is easy to apply with coroutines by using a
-single-threaded context.
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlin.system.*
-
-suspend fun massiveRun(action: suspend () -> Unit) {
- val n = 100 // number of coroutines to launch
- val k = 1000 // times an action is repeated by each coroutine
- val time = measureTimeMillis {
- coroutineScope { // scope for coroutines
- repeat(n) {
- launch {
- repeat(k) { action() }
- }
- }
- }
- }
- println("Completed ${n * k} actions in $time ms")
-}
-
-//sampleStart
-val counterContext = newSingleThreadContext("CounterContext")
-var counter = 0
-
-fun main() = runBlocking {
- withContext(Dispatchers.Default) {
- massiveRun {
- // confine each increment to a single-threaded context
- withContext(counterContext) {
- counter++
- }
- }
- }
- println("Counter = $counter")
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-sync-04.kt).
->
-{type="note"}
-
-<!--- TEST ARBITRARY_TIME
-Completed 100000 actions in xxx ms
-Counter = 100000
--->
-
-This code works very slowly, because it does _fine-grained_ thread-confinement. Each individual increment switches
-from multi-threaded [Dispatchers.Default] context to the single-threaded context using
-[withContext(counterContext)][withContext] block.
-
-## Thread confinement coarse-grained
-
-In practice, thread confinement is performed in large chunks, e.g. big pieces of state-updating business logic
-are confined to the single thread. The following example does it like that, running each coroutine in
-the single-threaded context to start with.
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlin.system.*
-
-suspend fun massiveRun(action: suspend () -> Unit) {
- val n = 100 // number of coroutines to launch
- val k = 1000 // times an action is repeated by each coroutine
- val time = measureTimeMillis {
- coroutineScope { // scope for coroutines
- repeat(n) {
- launch {
- repeat(k) { action() }
- }
- }
- }
- }
- println("Completed ${n * k} actions in $time ms")
-}
-
-//sampleStart
-val counterContext = newSingleThreadContext("CounterContext")
-var counter = 0
-
-fun main() = runBlocking {
- // confine everything to a single-threaded context
- withContext(counterContext) {
- massiveRun {
- counter++
- }
- }
- println("Counter = $counter")
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-sync-05.kt).
->
-{type="note"}
-
-<!--- TEST ARBITRARY_TIME
-Completed 100000 actions in xxx ms
-Counter = 100000
--->
-
-This now works much faster and produces correct result.
-
-## Mutual exclusion
-
-Mutual exclusion solution to the problem is to protect all modifications of the shared state with a _critical section_
-that is never executed concurrently. In a blocking world you'd typically use `synchronized` or `ReentrantLock` for that.
-Coroutine's alternative is called [Mutex]. It has [lock][Mutex.lock] and [unlock][Mutex.unlock] functions to
-delimit a critical section. The key difference is that `Mutex.lock()` is a suspending function. It does not block a thread.
-
-There is also [withLock] extension function that conveniently represents
-`mutex.lock(); try { ... } finally { mutex.unlock() }` pattern:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.sync.*
-import kotlin.system.*
-
-suspend fun massiveRun(action: suspend () -> Unit) {
- val n = 100 // number of coroutines to launch
- val k = 1000 // times an action is repeated by each coroutine
- val time = measureTimeMillis {
- coroutineScope { // scope for coroutines
- repeat(n) {
- launch {
- repeat(k) { action() }
- }
- }
- }
- }
- println("Completed ${n * k} actions in $time ms")
-}
-
-//sampleStart
-val mutex = Mutex()
-var counter = 0
-
-fun main() = runBlocking {
- withContext(Dispatchers.Default) {
- massiveRun {
- // protect each increment with lock
- mutex.withLock {
- counter++
- }
- }
- }
- println("Counter = $counter")
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-sync-06.kt).
->
-{type="note"}
-
-<!--- TEST ARBITRARY_TIME
-Completed 100000 actions in xxx ms
-Counter = 100000
--->
-
-The locking in this example is fine-grained, so it pays the price. However, it is a good choice for some situations
-where you absolutely must modify some shared state periodically, but there is no natural thread that this state
-is confined to.
-
-## Actors
-
-An [actor](https://en.wikipedia.org/wiki/Actor_model) is an entity made up of a combination of a coroutine,
-the state that is confined and encapsulated into this coroutine,
-and a channel to communicate with other coroutines. A simple actor can be written as a function,
-but an actor with a complex state is better suited for a class.
-
-There is an [actor] coroutine builder that conveniently combines actor's mailbox channel into its
-scope to receive messages from and combines the send channel into the resulting job object, so that a
-single reference to the actor can be carried around as its handle.
-
-The first step of using an actor is to define a class of messages that an actor is going to process.
-Kotlin's [sealed classes](https://kotlinlang.org/docs/reference/sealed-classes.html) are well suited for that purpose.
-We define `CounterMsg` sealed class with `IncCounter` message to increment a counter and `GetCounter` message
-to get its value. The later needs to send a response. A [CompletableDeferred] communication
-primitive, that represents a single value that will be known (communicated) in the future,
-is used here for that purpose.
-
-```kotlin
-// Message types for counterActor
-sealed class CounterMsg
-object IncCounter : CounterMsg() // one-way message to increment counter
-class GetCounter(val response: CompletableDeferred<Int>) : CounterMsg() // a request with reply
-```
-
-Then we define a function that launches an actor using an [actor] coroutine builder:
-
-```kotlin
-// This function launches a new counter actor
-fun CoroutineScope.counterActor() = actor<CounterMsg> {
- var counter = 0 // actor state
- for (msg in channel) { // iterate over incoming messages
- when (msg) {
- is IncCounter -> counter++
- is GetCounter -> msg.response.complete(counter)
- }
- }
-}
-```
-
-The main code is straightforward:
-
-<!--- CLEAR -->
-
-```kotlin
-import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.*
-import kotlin.system.*
-
-suspend fun massiveRun(action: suspend () -> Unit) {
- val n = 100 // number of coroutines to launch
- val k = 1000 // times an action is repeated by each coroutine
- val time = measureTimeMillis {
- coroutineScope { // scope for coroutines
- repeat(n) {
- launch {
- repeat(k) { action() }
- }
- }
- }
- }
- println("Completed ${n * k} actions in $time ms")
-}
-
-// Message types for counterActor
-sealed class CounterMsg
-object IncCounter : CounterMsg() // one-way message to increment counter
-class GetCounter(val response: CompletableDeferred<Int>) : CounterMsg() // a request with reply
-
-// This function launches a new counter actor
-fun CoroutineScope.counterActor() = actor<CounterMsg> {
- var counter = 0 // actor state
- for (msg in channel) { // iterate over incoming messages
- when (msg) {
- is IncCounter -> counter++
- is GetCounter -> msg.response.complete(counter)
- }
- }
-}
-
-//sampleStart
-fun main() = runBlocking<Unit> {
- val counter = counterActor() // create the actor
- withContext(Dispatchers.Default) {
- massiveRun {
- counter.send(IncCounter)
- }
- }
- // send a message to get a counter value from an actor
- val response = CompletableDeferred<Int>()
- counter.send(GetCounter(response))
- println("Counter = ${response.await()}")
- counter.close() // shutdown the actor
-}
-//sampleEnd
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-sync-07.kt).
->
-{type="note"}
-
-<!--- TEST ARBITRARY_TIME
-Completed 100000 actions in xxx ms
-Counter = 100000
--->
-
-It does not matter (for correctness) what context the actor itself is executed in. An actor is
-a coroutine and a coroutine is executed sequentially, so confinement of the state to the specific coroutine
-works as a solution to the problem of shared mutable state. Indeed, actors may modify their own private state,
-but can only affect each other through messages (avoiding the need for any locks).
-
-Actor is more efficient than locking under load, because in this case it always has work to do and it does not
-have to switch to a different context at all.
-
-> Note that an [actor] coroutine builder is a dual of [produce] coroutine builder. An actor is associated
-> with the channel that it receives messages from, while a producer is associated with the channel that it
-> sends elements to.
->
-{type="note"}
-
-<!--- MODULE kotlinx-coroutines-core -->
-<!--- INDEX kotlinx.coroutines -->
-
-[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html
-[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
-[CompletableDeferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-completable-deferred/index.html
-
-<!--- INDEX kotlinx.coroutines.sync -->
-
-[Mutex]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/index.html
-[Mutex.lock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/lock.html
-[Mutex.unlock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/unlock.html
-[withLock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/with-lock.html
-
-<!--- INDEX kotlinx.coroutines.channels -->
-
-[actor]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/actor.html
-[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/produce.html
-
-<!--- END --> \ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 40b15961..1ffa02d1 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,27 +1,27 @@
#
-# Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+# Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
#
# Kotlin
-version=1.4.3-SNAPSHOT
+version=1.4.1-SNAPSHOT
group=org.jetbrains.kotlinx
-kotlin_version=1.4.30
+kotlin_version=1.4.0
# Dependencies
junit_version=4.12
-atomicfu_version=0.15.1
-knit_version=0.2.3
+atomicfu_version=0.14.4
+knit_version=0.2.2
html_version=0.6.8
-lincheck_version=2.10
+lincheck_version=2.7.1
dokka_version=0.9.16-rdev-2-mpp-hacks
byte_buddy_version=1.10.9
-reactor_version=3.4.1
+reactor_version=3.2.5.RELEASE
reactive_streams_version=1.0.2
rxjava2_version=2.2.8
rxjava3_version=3.0.2
javafx_version=11.0.2
javafx_plugin_version=0.0.8
-binary_compatibility_validator_version=0.4.0
+binary_compatibility_validator_version=0.2.2
blockhound_version=1.0.2.RELEASE
jna_version=5.5.0
@@ -55,7 +55,7 @@ jekyll_version=4.0
org.gradle.jvmargs=-Xmx2g
# Workaround for Bintray treating .sha512 files as artifacts
-# https://github.com/gradle/gradle/issues/1.4.3
+# https://github.com/gradle/gradle/issues/11412
systemProp.org.gradle.internal.publish.checksums.insecure=true
# todo:KLUDGE: This is commented out, and the property is set conditionally in build.gradle, because IDEA doesn't work with it.
diff --git a/gradle/compile-common.gradle b/gradle/compile-common.gradle
index 6c3777b1..0dc1b5c0 100644
--- a/gradle/compile-common.gradle
+++ b/gradle/compile-common.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
kotlin.sourceSets {
diff --git a/gradle/compile-js-multiplatform.gradle b/gradle/compile-js-multiplatform.gradle
index 1e885db0..b52cfc52 100644
--- a/gradle/compile-js-multiplatform.gradle
+++ b/gradle/compile-js-multiplatform.gradle
@@ -1,18 +1,23 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
apply from: rootProject.file('gradle/node-js.gradle')
kotlin {
js {
- moduleName = project.name
+ // In 1.3.7x js() has not member `moduleName`
+ // In 1.4.x it has and allow to safety set compiler output file name and does not break test integration
+ if (it.hasProperty("moduleName")) {
+ moduleName = project.name
+ }
+ // In 1.3.7x js() has not member `irTarget`
// In 1.4.x it has in `both` and `legacy` mode and js() is of type `KotlinJsTarget`
// `irTarget` is non-null in `both` mode
// and contains appropriate `irTarget` with type `KotlinJsIrTarget`
// `irTarget` is null in `legacy` mode
- if (it.irTarget != null) {
+ if (it.hasProperty("irTarget") && it.irTarget != null) {
irTarget.nodejs()
irTarget.compilations['main']?.dependencies {
api "org.jetbrains.kotlinx:atomicfu-js:$atomicfu_version"
diff --git a/gradle/compile-js.gradle b/gradle/compile-js.gradle
new file mode 100644
index 00000000..55c81fe5
--- /dev/null
+++ b/gradle/compile-js.gradle
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+// Platform-specific configuration to compile JS modules
+
+apply plugin: 'org.jetbrains.kotlin.js'
+
+dependencies {
+ testImplementation "org.jetbrains.kotlin:kotlin-test-js:$kotlin_version"
+}
+
+kotlin {
+ js(LEGACY) {
+ moduleName = project.name - "-js"
+ }
+
+ sourceSets {
+ main.kotlin.srcDirs = ['src']
+ test.kotlin.srcDirs = ['test']
+ main.resources.srcDirs = ['resources']
+ test.resources.srcDirs = ['test-resources']
+ }
+}
+
+tasks.withType(compileKotlinJs.getClass()) {
+ kotlinOptions {
+ moduleKind = "umd"
+ sourceMap = true
+ metaInfo = true
+ }
+}
diff --git a/gradle/compile-jvm-multiplatform.gradle b/gradle/compile-jvm-multiplatform.gradle
index 1f861f80..e72d3051 100644
--- a/gradle/compile-jvm-multiplatform.gradle
+++ b/gradle/compile-jvm-multiplatform.gradle
@@ -1,17 +1,13 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
sourceCompatibility = 1.6
targetCompatibility = 1.6
kotlin {
- jvm {
- if (rootProject.ext.jvm_ir_enabled) {
- compilations.all {
- kotlinOptions.useIR = true
- }
- }
+ targets {
+ fromPreset(presets.jvm, 'jvm')
}
sourceSets {
jvmTest.dependencies {
diff --git a/gradle/compile-jvm.gradle b/gradle/compile-jvm.gradle
new file mode 100644
index 00000000..caa5c45f
--- /dev/null
+++ b/gradle/compile-jvm.gradle
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+// Platform-specific configuration to compile JVM modules
+
+apply plugin: 'org.jetbrains.kotlin.jvm'
+
+sourceCompatibility = 1.6
+targetCompatibility = 1.6
+
+dependencies {
+ testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
+ // Workaround to make addSuppressed work in tests
+ testCompile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
+ testCompile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
+ testCompile "junit:junit:$junit_version"
+}
+
+compileKotlin {
+ kotlinOptions {
+ freeCompilerArgs += ['-Xexplicit-api=strict']
+ }
+}
+
+tasks.withType(Test) {
+ testLogging {
+ showStandardStreams = true
+ events "passed", "failed"
+ }
+ def stressTest = project.properties['stressTest']
+ if (stressTest != null) systemProperties['stressTest'] = stressTest
+}
diff --git a/gradle/compile-native-multiplatform.gradle b/gradle/compile-native-multiplatform.gradle
index 50ddf975..44874467 100644
--- a/gradle/compile-native-multiplatform.gradle
+++ b/gradle/compile-native-multiplatform.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
project.ext.nativeMainSets = []
diff --git a/gradle/dokka.gradle b/gradle/dokka.gradle
index f0cad154..559ec8b6 100644
--- a/gradle/dokka.gradle
+++ b/gradle/dokka.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// Configures generation of JavaDoc & Dokka artifacts
diff --git a/gradle/experimental.gradle b/gradle/experimental.gradle
index 11aeb6d8..b045a1f6 100644
--- a/gradle/experimental.gradle
+++ b/gradle/experimental.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// For new mpp
diff --git a/gradle/node-js.gradle b/gradle/node-js.gradle
index 42f101c5..d4bd86ca 100644
--- a/gradle/node-js.gradle
+++ b/gradle/node-js.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
apply plugin: 'com.moowork.node'
diff --git a/gradle/publish-bintray.gradle b/gradle/publish-bintray.gradle
index e6f04234..b36c7976 100644
--- a/gradle/publish-bintray.gradle
+++ b/gradle/publish-bintray.gradle
@@ -1,19 +1,19 @@
+import org.gradle.util.VersionNumber
+
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-import org.gradle.util.VersionNumber
-
// Configures publishing of Maven artifacts to Bintray
apply plugin: 'maven'
apply plugin: 'maven-publish'
-apply plugin: 'signing'
// ------------- tasks
def isMultiplatform = project.name == "kotlinx-coroutines-core"
def isBom = project.name == "kotlinx-coroutines-bom"
+def isKotlin137x = VersionNumber.parse(kotlin_version) <= VersionNumber.parse("1.3.79")
if (!isBom) {
apply plugin: "com.github.johnrengelman.shadow"
@@ -37,11 +37,16 @@ if (!isMultiplatform && !isBom) {
publishing {
repositories {
- def bintrayUpload = System.getenv("libs.bintray.upload") != null
- if (bintrayUpload) {
- PublishingKt.configureBintrayPublication(delegate, project)
- } else {
- PublishingKt.configureMavenPublication(delegate, project)
+ maven {
+ def user = 'kotlin'
+ def repo = 'kotlinx'
+ def name = 'kotlinx.coroutines'
+ url = "https://api.bintray.com/maven/$user/$repo/$name/;publish=0"
+
+ credentials {
+ username = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER')
+ password = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY')
+ }
}
}
@@ -60,32 +65,46 @@ publishing {
}
publications.all {
- PublishingKt.configureMavenCentralMetadata(pom, project)
- def bintrayUpload = System.getenv("libs.bintray.upload") != null
- if (!bintrayUpload) {
- PublishingKt.signPublicationIfKeyPresent(project, it)
- }
+ MavenCentralKt.configureMavenCentralMetadata(pom, project)
+
// add empty javadocs
if (!isBom && it.name != "kotlinMultiplatform") {
it.artifact(javadocJar)
}
+ // Rename MPP artifacts for backward compatibility
def type = it.name
switch (type) {
case 'kotlinMultiplatform':
// With Kotlin 1.4 & HMPP, the root module should have no suffix in the ID, but for compatibility with
// the consumers who can't read Gradle module metadata, we publish the JVM artifacts in it, too
- it.artifactId = project.name
- apply from: "$rootDir/gradle/publish-mpp-root-module-in-platform.gradle"
- publishPlatformArtifactsInRootModule(publications["jvm"])
+ it.artifactId = isKotlin137x ? "$project.name-native" : project.name
+ if (!isKotlin137x) {
+ apply from: "$rootDir/gradle/publish-mpp-root-module-in-platform.gradle"
+ publishPlatformArtifactsInRootModule(publications["jvm"])
+ }
break
case 'metadata':
+ // As the old -common dependencies will fail to resolve with Gradle module metadata, rename the module
+ // to '*-metadata' so that the resolution failure are more clear
+ it.artifactId = isKotlin137x ? "$project.name-common" : "$project.name-metadata"
+ break
case 'jvm':
+ it.artifactId = isKotlin137x ? project.name : "$project.name-jvm"
+ break
case 'js':
case 'native':
it.artifactId = "$project.name-$type"
break
}
+ // Hierarchical project structures are not fully supported in 1.3.7x MPP
+ if (isKotlin137x) {
+ // disable metadata everywhere, but in native and js modules
+ if (type == 'maven' || type == 'metadata' || type == 'jvm') {
+ moduleDescriptorGenerator = null
+ }
+ }
+
}
}
@@ -93,5 +112,12 @@ tasks.matching { it.name == "generatePomFileForKotlinMultiplatformPublication"}.
dependsOn(tasks["generatePomFileForJvmPublication"])
}
+task publishDevelopSnapshot() {
+ def branch = System.getenv('currentBranch')
+ if (branch == "develop") {
+ dependsOn(":publish")
+ }
+}
+
// Compatibility with old TeamCity configurations that perform :kotlinx-coroutines-core:bintrayUpload
task bintrayUpload(dependsOn: publish)
diff --git a/gradle/publish-mpp-root-module-in-platform.gradle b/gradle/publish-mpp-root-module-in-platform.gradle
index 8036bea0..8bc0b502 100644
--- a/gradle/publish-mpp-root-module-in-platform.gradle
+++ b/gradle/publish-mpp-root-module-in-platform.gradle
@@ -1,42 +1,39 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2014-2020 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
-/** Publish the platform JAR and POM so that consumers who depend on this module and can't read Gradle module
- metadata can still get the platform artifact and transitive dependencies from the POM: */
-project.ext.publishPlatformArtifactsInRootModule = { MavenPublication platformPublication ->
+/*
+ * Publish the platform JAR and POM so that consumers who depend on this module and can't read Gradle module metadata
+ * can still get the platform artifact and transitive dependencies from the POM.
+ *
+ * See the full rationale here https://youtrack.jetbrains.com/issue/KMM-237#focus=streamItem-27-4115233.0-0
+ */
+project.ext.publishPlatformArtifactsInRootModule = { platformPublication ->
+ def platformPomBuilder = null
- XmlProvider platformXml = null
+ platformPublication.pom.withXml { platformPomBuilder = asString() }
- platformPublication.pom.withXml { platformXml = it }
+ publishing.publications.kotlinMultiplatform {
+ platformPublication.artifacts.forEach {
+ artifact(it)
+ }
- publishing.publications.kotlinMultiplatform {
pom.withXml {
- Node root = asNode()
- // Remove the original content and add the content from the platform POM:
- root.children().toList().each { root.remove(it as Node) }
- platformXml.asNode().children().each { root.append(it as Node) }
-
- // Adjust the self artifact ID, as it should match the root module's coordinates:
- ((root.get("artifactId") as NodeList).get(0) as Node).setValue(artifactId)
-
- // Set packaging to POM to indicate that there's no artifact:
- root.appendNode("packaging", "pom")
-
- // Remove the original platform dependencies and add a single dependency on the platform module:
- Node dependencies = (root.get("dependencies") as NodeList).get(0) as Node
- dependencies.children().toList().each { dependencies.remove(it as Node) }
- Node singleDependency = dependencies.appendNode("dependency")
- singleDependency.appendNode("groupId", platformPublication.groupId)
- singleDependency.appendNode("artifactId", platformPublication.artifactId)
- singleDependency.appendNode("version", platformPublication.version)
- singleDependency.appendNode("scope", "compile")
+ def pomStringBuilder = asString()
+ pomStringBuilder.setLength(0)
+ // The platform POM needs its artifact ID replaced with the artifact ID of the root module:
+ def platformPomString = platformPomBuilder.toString()
+ platformPomString.eachLine { line ->
+ if (!line.contains("<!--")) { // Remove the Gradle module metadata marker as it will be added anew
+ pomStringBuilder.append(line.replace(platformPublication.artifactId, artifactId))
+ pomStringBuilder.append("\n")
+ }
+ }
}
}
- tasks.matching { it.name == "generatePomFileForKotlinMultiplatformPublication" }.configureEach {
+ tasks.matching { it.name == "generatePomFileForKotlinMultiplatformPublication"}.configureEach {
dependsOn(tasks["generatePomFileFor${platformPublication.name.capitalize()}Publication"])
}
-
-}
+} \ No newline at end of file
diff --git a/gradle/publish-npm-js.gradle b/gradle/publish-npm-js.gradle
index 382c6749..8e1a7bb5 100644
--- a/gradle/publish-npm-js.gradle
+++ b/gradle/publish-npm-js.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
def prop(name, defVal) {
diff --git a/gradle/test-mocha-js.gradle b/gradle/test-mocha-js.gradle
index d011eeaa..7de79b99 100644
--- a/gradle/test-mocha-js.gradle
+++ b/gradle/test-mocha-js.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// -- Testing with Mocha under Node
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index e708b1c0..28861d27 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 3a9638d5..23082f9a 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,9 +1,9 @@
#
-# Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+# Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
#
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
diff --git a/gradlew b/gradlew
index ea79e0af..cccdd3d5 100755
--- a/gradlew
+++ b/gradlew
@@ -1,9 +1,5 @@
#!/usr/bin/env sh
-#
-# Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
-#
-
##############################################################################
##
## Gradle start up script for UN*X
@@ -32,7 +28,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@@ -70,7 +66,6 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -114,11 +109,10 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@@ -144,19 +138,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
else
eval `echo args$i`="\"$arg\""
fi
- i=`expr $i + 1`
+ i=$((i+1))
done
case $i in
- 0) set -- ;;
- 1) set -- "$args0" ;;
- 2) set -- "$args0" "$args1" ;;
- 3) set -- "$args0" "$args1" "$args2" ;;
- 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -165,9 +159,14 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
-APP_ARGS=`save "$@"`
+APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 107acd32..f9553162 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,19 +1,3 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -29,18 +13,15 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +35,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto execute
+if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,14 +45,28 @@ echo location of your Java installation.
goto fail
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
diff --git a/integration-testing/build.gradle b/integration-testing/build.gradle
index c5a551a0..b1cbc08f 100644
--- a/integration-testing/build.gradle
+++ b/integration-testing/build.gradle
@@ -1,12 +1,10 @@
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
+
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
-
-plugins {
- id("kotlin-jvm-conventions")
-}
+apply from: rootProject.file("gradle/compile-jvm.gradle")
repositories {
mavenLocal()
diff --git a/integration-testing/src/coreAgentTest/kotlin/CoreAgentTest.kt b/integration-testing/src/coreAgentTest/kotlin/CoreAgentTest.kt
index 359338b8..6d473233 100644
--- a/integration-testing/src/coreAgentTest/kotlin/CoreAgentTest.kt
+++ b/integration-testing/src/coreAgentTest/kotlin/CoreAgentTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import org.junit.*
import kotlinx.coroutines.*
diff --git a/integration-testing/src/debugAgentTest/kotlin/DebugAgentTest.kt b/integration-testing/src/debugAgentTest/kotlin/DebugAgentTest.kt
index 779cd5b7..d6c4aa2f 100644
--- a/integration-testing/src/debugAgentTest/kotlin/DebugAgentTest.kt
+++ b/integration-testing/src/debugAgentTest/kotlin/DebugAgentTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import org.junit.*
import kotlinx.coroutines.*
diff --git a/integration-testing/src/debugAgentTest/kotlin/DebugProbes.kt b/integration-testing/src/debugAgentTest/kotlin/DebugProbes.kt
index 81741569..46a7634a 100644
--- a/integration-testing/src/debugAgentTest/kotlin/DebugProbes.kt
+++ b/integration-testing/src/debugAgentTest/kotlin/DebugProbes.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package kotlin.coroutines.jvm.internal
@@ -11,4 +11,4 @@ internal fun <T> probeCoroutineCreated(completion: Continuation<T>): Continuatio
internal fun probeCoroutineResumed(frame: Continuation<*>) = DebugProbesImpl.probeCoroutineResumed(frame)
-internal fun probeCoroutineSuspended(frame: Continuation<*>) = DebugProbesImpl.probeCoroutineSuspended(frame)
+internal fun probeCoroutineSuspended(frame: Continuation<*>) = DebugProbesImpl.probeCoroutineSuspended(frame) \ No newline at end of file
diff --git a/integration-testing/src/debugAgentTest/kotlin/PrecompiledDebugProbesTest.kt b/integration-testing/src/debugAgentTest/kotlin/PrecompiledDebugProbesTest.kt
index ce82e577..5d799ee0 100644
--- a/integration-testing/src/debugAgentTest/kotlin/PrecompiledDebugProbesTest.kt
+++ b/integration-testing/src/debugAgentTest/kotlin/PrecompiledDebugProbesTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import org.junit.Test
import java.io.*
@@ -36,4 +36,4 @@ class PrecompiledDebugProbesTest {
"ensure that classfile has major version equal to 50 (Java 6 compliance)")
}
}
-}
+} \ No newline at end of file
diff --git a/integration-testing/src/mavenTest/kotlin/MavenPublicationValidator.kt b/integration-testing/src/mavenTest/kotlin/MavenPublicationValidator.kt
index 39d6598b..5089c535 100644
--- a/integration-testing/src/mavenTest/kotlin/MavenPublicationValidator.kt
+++ b/integration-testing/src/mavenTest/kotlin/MavenPublicationValidator.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.validator
diff --git a/integration-testing/src/npmTest/kotlin/NpmPublicationValidator.kt b/integration-testing/src/npmTest/kotlin/NpmPublicationValidator.kt
index 8e1b9f99..52479d56 100644
--- a/integration-testing/src/npmTest/kotlin/NpmPublicationValidator.kt
+++ b/integration-testing/src/npmTest/kotlin/NpmPublicationValidator.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.validator
diff --git a/integration/kotlinx-coroutines-guava/README.md b/integration/kotlinx-coroutines-guava/README.md
index 130cf0a0..4c43317a 100644
--- a/integration/kotlinx-coroutines-guava/README.md
+++ b/integration/kotlinx-coroutines-guava/README.md
@@ -50,15 +50,11 @@ Integration with Guava [ListenableFuture](https://github.com/google/guava/wiki/L
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
-
[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
-
<!--- MODULE kotlinx-coroutines-guava -->
<!--- INDEX kotlinx.coroutines.guava -->
-
[future]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/kotlinx.coroutines.-coroutine-scope/future.html
[com.google.common.util.concurrent.ListenableFuture]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/com.google.common.util.concurrent.-listenable-future/index.html
[com.google.common.util.concurrent.ListenableFuture.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/com.google.common.util.concurrent.-listenable-future/await.html
[kotlinx.coroutines.Deferred.asListenableFuture]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/kotlinx.coroutines.-deferred/as-listenable-future.html
-
<!--- END -->
diff --git a/integration/kotlinx-coroutines-guava/build.gradle.kts b/integration/kotlinx-coroutines-guava/build.gradle.kts
index 12a6ca70..53e91add 100644
--- a/integration/kotlinx-coroutines-guava/build.gradle.kts
+++ b/integration/kotlinx-coroutines-guava/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
val guavaVersion = "28.0-jre"
diff --git a/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt b/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt
index 53019c4b..974e2462 100644
--- a/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt
+++ b/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.guava
@@ -17,11 +17,8 @@ import kotlin.coroutines.*
* The coroutine is immediately started. Passing [CoroutineStart.LAZY] to [start] throws
* [IllegalArgumentException], because Futures don't have a way to start lazily.
*
- * When the created coroutine [isCompleted][Job.isCompleted], it will try to
- * *synchronously* complete the returned Future with the same outcome. This will
- * succeed, barring a race with external cancellation of returned [ListenableFuture].
- *
- * Cancellation is propagated bidirectionally.
+ * The created coroutine is cancelled when the resulting future completes successfully, fails, or
+ * is cancelled.
*
* `CoroutineContext` is inherited from this [CoroutineScope]. Additional context elements can be
* added/overlaid by passing [context].
@@ -35,10 +32,8 @@ import kotlin.coroutines.*
* See [newCoroutineContext][CoroutineScope.newCoroutineContext] for a description of debugging
* facilities.
*
- * Note that the error and cancellation semantics of [future] are _subtly different_ than [asListenableFuture]'s.
- * In particular, any exception that happens in the coroutine after returned future is
- * successfully cancelled will be passed to the [CoroutineExceptionHandler] from the [context].
- * See [ListenableFutureCoroutine] for details.
+ * Note that the error and cancellation semantics of [future] are _subtly different_ than
+ * [asListenableFuture]'s. See [ListenableFutureCoroutine] for details.
*
* @param context added overlaying [CoroutineScope.coroutineContext] to form the new context.
* @param start coroutine start option. The default value is [CoroutineStart.DEFAULT].
@@ -51,9 +46,14 @@ public fun <T> CoroutineScope.future(
): ListenableFuture<T> {
require(!start.isLazy) { "$start start is not supported" }
val newContext = newCoroutineContext(context)
- val coroutine = ListenableFutureCoroutine<T>(newContext)
+ val future = SettableFuture.create<T>()
+ val coroutine = ListenableFutureCoroutine(newContext, future)
+ future.addListener(
+ coroutine,
+ MoreExecutors.directExecutor())
coroutine.start(start, coroutine, block)
- return coroutine.future
+ // Return hides the SettableFuture. This should prevent casting.
+ return object: ListenableFuture<T> by future {}
}
/**
@@ -70,7 +70,7 @@ public fun <T> CoroutineScope.future(
* When `this` `ListenableFuture` is [successfully cancelled][java.util.concurrent.Future.cancel],
* it will cancel the returned `Deferred`.
*
- * When the returned `Deferred` is [cancelled][Deferred.cancel], it will try to propagate the
+ * When the returned `Deferred` is [cancelled][Deferred.cancel()], it will try to propagate the
* cancellation to `this` `ListenableFuture`. Propagation will succeed, barring a race with the
* `ListenableFuture` completing normally. This is the only case in which the returned `Deferred`
* will complete with a different outcome than `this` `ListenableFuture`.
@@ -152,8 +152,7 @@ public fun <T> ListenableFuture<T>.asDeferred(): Deferred<T> {
deferred.invokeOnCompletion {
cancel(false)
}
- // Return hides the CompletableDeferred. This should prevent casting.
- return object : Deferred<T> by deferred {}
+ return deferred
}
/**
@@ -167,7 +166,7 @@ public fun <T> ListenableFuture<T>.asDeferred(): Deferred<T> {
* state - a serious fundamental bug.
*/
private fun ExecutionException.nonNullCause(): Throwable {
- return this.cause!!
+ return this.cause!!
}
/**
@@ -196,21 +195,13 @@ private fun ExecutionException.nonNullCause(): Throwable {
*
* This is inherently a race. See [Future.cancel] for a description of `Future` cancellation
* semantics. See [Job] for a description of coroutine cancellation semantics. See
- * [JobListenableFuture.cancel] for greater detail on the overlapped cancellation semantics and
+ * [DeferredListenableFuture.cancel] for greater detail on the overlapped cancellation semantics and
* corner cases of this method.
*/
public fun <T> Deferred<T>.asListenableFuture(): ListenableFuture<T> {
- val listenableFuture = JobListenableFuture<T>(this)
- // This invokeOnCompletion completes the JobListenableFuture with the same result as `this` Deferred.
- // The JobListenableFuture may have completed earlier if it got cancelled! See JobListenableFuture.cancel().
- invokeOnCompletion { throwable ->
- if (throwable == null) {
- listenableFuture.complete(getCompleted())
- } else {
- listenableFuture.completeExceptionallyOrCancel(throwable)
- }
- }
- return listenableFuture
+ val outerFuture = OuterFuture<T>(this)
+ outerFuture.afterInit()
+ return outerFuture
}
/**
@@ -224,6 +215,7 @@ public fun <T> Deferred<T>.asListenableFuture(): ListenableFuture<T> {
* This method is intended to be used with one-shot Futures, so on coroutine cancellation, the Future is cancelled as well.
* If cancelling the given future is undesired, use [Futures.nonCancellationPropagating] or
* [kotlinx.coroutines.NonCancellable].
+ *
*/
public suspend fun <T> ListenableFuture<T>.await(): T {
try {
@@ -263,7 +255,8 @@ private class ToContinuation<T>(
continuation.cancel()
} else {
try {
- continuation.resume(Uninterruptibles.getUninterruptibly(futureToObserve))
+ continuation.resumeWith(
+ Result.success(Uninterruptibles.getUninterruptibly(futureToObserve)))
} catch (e: ExecutionException) {
// ExecutionException is the only kind of exception that can be thrown from a gotten
// Future. Anything else showing up here indicates a very fundamental bug in a
@@ -278,47 +271,57 @@ private class ToContinuation<T>(
* An [AbstractCoroutine] intended for use directly creating a [ListenableFuture] handle to
* completion.
*
- * If [future] is successfully cancelled, cancellation is propagated to `this` `Coroutine`.
- * By documented contract, a [Future] has been cancelled if
- * and only if its `isCancelled()` method returns true.
- *
- * Any error that occurs after successfully cancelling a [ListenableFuture] will be passed
- * to the [CoroutineExceptionHandler] from the context. The contract of [Future] does not permit
- * it to return an error after it is successfully cancelled.
- *
- * By calling [asListenableFuture] on a [Deferred], any error that occurs after successfully
- * cancelling the [ListenableFuture] representation of the [Deferred] will _not_ be passed to
- * the [CoroutineExceptionHandler]. Cancelling a [Deferred] places that [Deferred] in the
- * cancelling/cancelled states defined by [Job], which _can_ show the error. It's assumed that
- * the [Deferred] pointing to the task will be used to observe any error outcome occurring after
- * cancellation.
- *
- * This may be counterintuitive, but it maintains the error and cancellation contracts of both
- * the [Deferred] and [ListenableFuture] types, while permitting both kinds of promise to point
- * to the same running task.
+ * The code in the [Runnable] portion of the class is registered as a [ListenableFuture] callback.
+ * See [run] for details. Both types are implemented by this object to save an allocation.
*/
private class ListenableFutureCoroutine<T>(
- context: CoroutineContext
-) : AbstractCoroutine<T>(context) {
+ context: CoroutineContext,
+ private val future: SettableFuture<T>
+) : AbstractCoroutine<T>(context), Runnable {
- // JobListenableFuture propagates external cancellation to `this` coroutine. See JobListenableFuture.
- @JvmField
- val future = JobListenableFuture<T>(this)
+ /**
+ * When registered as a [ListenableFuture] listener, cancels the returned [Coroutine] if
+ * [future] is successfully cancelled. By documented contract, a [Future] has been cancelled if
+ * and only if its `isCancelled()` method returns true.
+ *
+ * Any error that occurs after successfully cancelling a [ListenableFuture]
+ * created by submitting the returned object as a [Runnable] to an `Executor` will be passed
+ * to the [CoroutineExceptionHandler] from the context. The contract of [Future] does not permit
+ * it to return an error after it is successfully cancelled.
+ *
+ * By calling [asListenableFuture] on a [Deferred], any error that occurs after successfully
+ * cancelling the [ListenableFuture] representation of the [Deferred] will _not_ be passed to
+ * the [CoroutineExceptionHandler]. Cancelling a [Deferred] places that [Deferred] in the
+ * cancelling/cancelled states defined by [Job], which _can_ show the error. It's assumed that
+ * the [Deferred] pointing to the task will be used to observe any error outcome occurring after
+ * cancellation.
+ *
+ * This may be counterintuitive, but it maintains the error and cancellation contracts of both
+ * the [Deferred] and [ListenableFuture] types, while permitting both kinds of promise to point
+ * to the same running task.
+ */
+ override fun run() {
+ if (future.isCancelled) {
+ cancel()
+ }
+ }
override fun onCompleted(value: T) {
- future.complete(value)
+ future.set(value)
}
+ // TODO: This doesn't actually cancel the Future. There doesn't seem to be bidi cancellation?
override fun onCancelled(cause: Throwable, handled: Boolean) {
- if (!future.completeExceptionallyOrCancel(cause) && !handled) {
- // prevents loss of exception that was not handled by parent & could not be set to JobListenableFuture
+ if (!future.setException(cause) && !handled) {
+ // prevents loss of exception that was not handled by parent & could not be set to SettableFuture
handleCoroutineException(context, cause)
}
}
}
/**
- * A [ListenableFuture] that delegates to an internal [SettableFuture], collaborating with it.
+ * A [ListenableFuture] that delegates to an internal [DeferredListenableFuture], collaborating with
+ * it.
*
* This setup allows the returned [ListenableFuture] to maintain the following properties:
*
@@ -330,176 +333,130 @@ private class ListenableFutureCoroutine<T>(
* - Fully correct cancellation and listener happens-after obeying [Future] and
* [ListenableFuture]'s documented and implicit contracts is surprisingly difficult to achieve.
* The best way to be correct, especially given the fun corner cases from
- * [AbstractFuture.setFuture], is to just use an [AbstractFuture].
- * - To maintain sanity, this class implements [ListenableFuture] and uses an auxiliary [SettableFuture]
- * around coroutine's result as a state engine to establish happens-after-completion. This
- * could probably be compressed into one subclass of [AbstractFuture] to save an allocation, at the
+ * [AsyncFuture.setAsync], is to just use an [AsyncFuture].
+ * - To maintain sanity, this class implements [ListenableFuture] and uses an inner [AsyncFuture]
+ * around its input [deferred] as a state engine to establish happens-after-completion. This
+ * could probably be compressed into one subclass of [AsyncFuture] to save an allocation, at the
* cost of the implementation's readability.
*/
-private class JobListenableFuture<T>(private val jobToCancel: Job): ListenableFuture<T> {
- /**
- * Serves as a state machine for [Future] cancellation.
- *
- * [AbstractFuture] has a highly-correct atomic implementation of `Future`'s completion and
- * cancellation semantics. By using that type, the [JobListenableFuture] can delegate its semantics to
- * `auxFuture.get()` the result in such a way that the `Deferred` is always complete when returned.
- *
- * To preserve Coroutine's [CancellationException], this future points to either `T` or [Cancelled].
- */
- private val auxFuture = SettableFuture.create<Any>()
-
- /**
- * `true` if [auxFuture.get][ListenableFuture.get] throws [ExecutionException].
- *
- * Note: this is eventually consistent with the state of [auxFuture].
- *
- * Unfortunately, there's no API to figure out if [ListenableFuture] throws [ExecutionException]
- * apart from calling [ListenableFuture.get] on it. To avoid unnecessary [ExecutionException] allocation
- * we use this field as an optimization.
- */
- private var auxFutureIsFailed: Boolean = false
+private class OuterFuture<T>(private val deferred: Deferred<T>): ListenableFuture<T> {
+ val innerFuture = DeferredListenableFuture(deferred)
- /**
- * When the attached coroutine [isCompleted][Job.isCompleted] successfully
- * its outcome should be passed to this method.
- *
- * This should succeed barring a race with external cancellation.
- */
- fun complete(result: T): Boolean = auxFuture.set(result)
-
- /**
- * When the attached coroutine [isCompleted][Job.isCompleted] [exceptionally][Job.isCancelled]
- * its outcome should be passed to this method.
- *
- * This method will map coroutine's exception into corresponding Future's exception.
- *
- * This should succeed barring a race with external cancellation.
- */
- // CancellationException is wrapped into `Cancelled` to preserve original cause and message.
- // All the other exceptions are delegated to SettableFuture.setException.
- fun completeExceptionallyOrCancel(t: Throwable): Boolean =
- if (t is CancellationException) auxFuture.set(Cancelled(t))
- else auxFuture.setException(t).also { if (it) auxFutureIsFailed = true }
+ // Adding the listener after initialization resolves partial construction hairpin problem.
+ //
+ // This invokeOnCompletion completes the innerFuture as `deferred` does. The innerFuture may
+ // have completed earlier if it got cancelled! See DeferredListenableFuture.
+ fun afterInit() {
+ deferred.invokeOnCompletion {
+ innerFuture.complete()
+ }
+ }
/**
* Returns cancellation _in the sense of [Future]_. This is _not_ equivalent to
* [Job.isCancelled].
*
- * When done, this Future is cancelled if its [auxFuture] is cancelled, or if [auxFuture]
- * contains [CancellationException].
+ * When done, this Future is cancelled if its innerFuture is cancelled, or if its delegate
+ * [deferred] is cancelled. Cancellation of [innerFuture] collaborates with this class.
*
- * See [cancel].
+ * See [DeferredListenableFuture.cancel].
*/
override fun isCancelled(): Boolean {
// This expression ensures that isCancelled() will *never* return true when isDone() returns false.
// In the case that the deferred has completed with cancellation, completing `this`, its
// reaching the "cancelled" state with a cause of CancellationException is treated as the
- // same thing as auxFuture getting cancelled. If the Job is in the "cancelling" state and
+ // same thing as innerFuture getting cancelled. If the Job is in the "cancelling" state and
// this Future hasn't itself been successfully cancelled, the Future will return
// isCancelled() == false. This is the only discovered way to reconcile the two different
// cancellation contracts.
- return auxFuture.isCancelled || isDone && !auxFutureIsFailed && try {
- Uninterruptibles.getUninterruptibly(auxFuture) is Cancelled
- } catch (e: CancellationException) {
- // `auxFuture` got cancelled right after `auxFuture.isCancelled` returned false.
- true
- } catch (e: ExecutionException) {
- // `auxFutureIsFailed` hasn't been updated yet.
- auxFutureIsFailed = true
- false
- }
+ return isDone
+ && (innerFuture.isCancelled
+ || deferred.getCompletionExceptionOrNull() is kotlinx.coroutines.CancellationException)
}
/**
- * Waits for [auxFuture] to complete by blocking, then uses its `result`
- * to get the `T` value `this` [ListenableFuture] is pointing to or throw a [CancellationException].
- * This establishes happens-after ordering for completion of the entangled coroutine.
+ * Waits for [innerFuture] to complete by blocking, then uses the [deferred] returned by that
+ * Future to get the `T` value `this` [ListenableFuture] is pointing to. This establishes
+ * happens-after ordering for completion of the [Deferred] input to [OuterFuture].
*
- * [SettableFuture.get] can only throw [CancellationException] if it was cancelled externally.
- * Otherwise it returns [Cancelled] that encapsulates outcome of the entangled coroutine.
- *
- * [auxFuture] _must be complete_ in order for the [isDone] and [isCancelled] happens-after
- * contract of [Future] to be correctly followed.
+ * `innerFuture` _must be complete_ in order for the [isDone] and [isCancelled] happens-after
+ * contract of [Future] to be correctly followed. If this method were to directly use
+ * _`this.deferred`_ instead of blocking on its `innerFuture`, the [Deferred] that this
+ * [ListenableFuture] is created from might be in an incomplete state when used by `get()`.
*/
override fun get(): T {
- return getInternal(auxFuture.get())
+ return getInternal(innerFuture.get())
}
/** See [get()]. */
override fun get(timeout: Long, unit: TimeUnit): T {
- return getInternal(auxFuture.get(timeout, unit))
+ return getInternal(innerFuture.get(timeout, unit))
}
/** See [get()]. */
- private fun getInternal(result: Any): T = if (result is Cancelled) {
- throw CancellationException().initCause(result.exception)
- } else {
- // We know that `auxFuture` can contain either `T` or `Cancelled`.
- @Suppress("UNCHECKED_CAST")
- result as T
+ private fun getInternal(deferred: Deferred<T>): T {
+ if (deferred.isCancelled) {
+ val exception = deferred.getCompletionExceptionOrNull()
+ if (exception is kotlinx.coroutines.CancellationException) {
+ throw exception
+ } else {
+ throw ExecutionException(exception)
+ }
+ } else {
+ return deferred.getCompleted()
+ }
}
override fun addListener(listener: Runnable, executor: Executor) {
- auxFuture.addListener(listener, executor)
+ innerFuture.addListener(listener, executor)
}
override fun isDone(): Boolean {
- return auxFuture.isDone
+ return innerFuture.isDone
+ }
+
+ override fun cancel(mayInterruptIfRunning: Boolean): Boolean {
+ return innerFuture.cancel(mayInterruptIfRunning)
+ }
+}
+
+/**
+ * Holds a delegate deferred, and serves as a state machine for [Future] cancellation.
+ *
+ * [AbstractFuture] has a highly-correct atomic implementation of `Future`'s completion and
+ * cancellation semantics. By using that type, the [OuterFuture] can delegate its semantics to
+ * _this_ `Future` `get()` the result in such a way that the `Deferred` is always complete when
+ * returned.
+ */
+private class DeferredListenableFuture<T>(
+ private val deferred: Deferred<T>
+) : AbstractFuture<Deferred<T>>() {
+
+ fun complete() {
+ set(deferred)
}
/**
- * Tries to cancel [jobToCancel] if `this` future was cancelled. This is fundamentally racy.
+ * Tries to cancel the task. This is fundamentally racy.
*
- * The call to `cancel()` will try to cancel [auxFuture]: if and only if cancellation of [auxFuture]
- * succeeds, [jobToCancel] will have its [Job.cancel] called.
+ * For any given call to `cancel()`, if [deferred] is already completed, the call will complete
+ * this Future with it, and fail to cancel. Otherwise, the
+ * call to `cancel()` will try to cancel this Future: if and only if cancellation of this
+ * succeeds, [deferred] will have its [Deferred.cancel] called.
*
- * This arrangement means that [jobToCancel] _might not successfully cancel_, if the race resolves
- * in a particular way. [jobToCancel] may also be in its "cancelling" state while this
+ * This arrangement means that [deferred] _might not successfully cancel_, if the race resolves
+ * in a particular way. [deferred] may also be in its "cancelling" state while this
* ListenableFuture is complete and cancelled.
+ *
+ * [OuterFuture] collaborates with this class to present a more cohesive picture and ensure
+ * that certain combinations of cancelled/cancelling states can't be observed.
*/
override fun cancel(mayInterruptIfRunning: Boolean): Boolean {
- // TODO: call jobToCancel.cancel() _before_ running the listeners.
- // `auxFuture.cancel()` will execute auxFuture's listeners. This delays cancellation of
- // `jobToCancel` until after auxFuture's listeners have already run.
- // Consider moving `jobToCancel.cancel()` into [AbstractFuture.afterDone] when the API is finalized.
- return if (auxFuture.cancel(mayInterruptIfRunning)) {
- jobToCancel.cancel()
+ return if (super.cancel(mayInterruptIfRunning)) {
+ deferred.cancel()
true
} else {
false
}
}
-
- override fun toString(): String = buildString {
- append(super.toString())
- append("[status=")
- if (isDone) {
- try {
- when (val result = Uninterruptibles.getUninterruptibly(auxFuture)) {
- is Cancelled -> append("CANCELLED, cause=[${result.exception}]")
- else -> append("SUCCESS, result=[$result]")
- }
- } catch (e: CancellationException) {
- // `this` future was cancelled by `Future.cancel`. In this case there's no cause or message.
- append("CANCELLED")
- } catch (e: ExecutionException) {
- append("FAILURE, cause=[${e.cause}]")
- } catch (t: Throwable) {
- // Violation of Future's contract, should never happen.
- append("UNKNOWN, cause=[${t.javaClass} thrown from get()]")
- }
- } else {
- append("PENDING, delegate=[$auxFuture]")
- }
- append(']')
- }
}
-
-/**
- * A wrapper for `Coroutine`'s [CancellationException].
- *
- * If the coroutine is _cancelled normally_, we want to show the reason of cancellation to the user. Unfortunately,
- * [SettableFuture] can't store the reason of cancellation. To mitigate this, we wrap cancellation exception into this
- * class and pass it into [SettableFuture.complete]. See implementation of [JobListenableFuture].
- */
-private class Cancelled(@JvmField val exception: CancellationException)
diff --git a/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt b/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt
index 9dca9e9b..a9a7f7ba 100644
--- a/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt
+++ b/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt
@@ -7,7 +7,6 @@ package kotlinx.coroutines.guava
import com.google.common.util.concurrent.*
import kotlinx.coroutines.*
import org.junit.*
-import org.junit.Ignore
import org.junit.Test
import java.util.concurrent.*
import java.util.concurrent.CancellationException
@@ -317,28 +316,6 @@ class ListenableFutureTest : TestBase() {
}
@Test
- @Ignore // TODO: propagate cancellation before running listeners.
- fun testAsListenableFuturePropagatesCancellationBeforeRunningListeners() = runTest {
- expect(1)
- val deferred = async(context = Dispatchers.Unconfined) {
- try {
- delay(Long.MAX_VALUE)
- } finally {
- expect(3) // Cancelled.
- }
- }
- val asFuture = deferred.asListenableFuture()
- asFuture.addListener(Runnable { expect(4) }, MoreExecutors.directExecutor())
- assertFalse(asFuture.isDone)
- expect(2)
- asFuture.cancel(false)
- assertTrue(asFuture.isDone)
- assertTrue(asFuture.isCancelled)
- assertFailsWith<CancellationException> { deferred.await() }
- finish(5)
- }
-
- @Test
fun testFutureCancellation() = runTest {
val future = awaitFutureWithCancel(true)
assertTrue(future.isCancelled)
@@ -356,18 +333,15 @@ class ListenableFutureTest : TestBase() {
val outputCancellationException =
assertFailsWith<CancellationException> { asFuture.get() }
- val cause = outputCancellationException.cause
- assertNotNull(cause)
- assertEquals(cause.message, "Foobar")
- assertTrue(cause.cause is OutOfMemoryError)
- assertEquals(cause.cause?.message, "Foobaz")
+ assertEquals(outputCancellationException.message, "Foobar")
+ assertTrue(outputCancellationException.cause is OutOfMemoryError)
+ assertEquals(outputCancellationException.cause?.message, "Foobaz")
}
@Test
fun testNoFutureCancellation() = runTest {
val future = awaitFutureWithCancel(false)
assertFalse(future.isCancelled)
- @Suppress("BlockingMethodInNonBlockingContext")
assertEquals(42, future.get())
finish(4)
}
@@ -380,7 +354,7 @@ class ListenableFutureTest : TestBase() {
assertTrue(asDeferredAsFuture.isCancelled)
assertFailsWith<CancellationException> {
- asDeferredAsFuture.await()
+ val value: Int = asDeferredAsFuture.await()
}
}
@@ -405,7 +379,7 @@ class ListenableFutureTest : TestBase() {
assertTrue(asDeferred.isCancelled)
assertFailsWith<CancellationException> {
- asDeferred.await()
+ val value: Int = asDeferred.await()
}
}
@@ -459,10 +433,7 @@ class ListenableFutureTest : TestBase() {
@Test
fun testFutureCompletedWithNullFastPathAsDeferred() = runTest {
val executor = MoreExecutors.listeningDecorator(ForkJoinPool.commonPool())
- val future = executor.submit(Callable<Int> { null }).also {
- @Suppress("BlockingMethodInNonBlockingContext")
- it.get()
- }
+ val future = executor.submit(Callable<Int> { null }).also { it.get() }
assertNull(future.asDeferred().await())
}
@@ -523,10 +494,8 @@ class ListenableFutureTest : TestBase() {
val future = future(Dispatchers.Unconfined) {
try {
delay(Long.MAX_VALUE)
- expectUnreached()
- } catch (e: CancellationException) {
+ } finally {
expect(2)
- throw e
}
}
@@ -538,19 +507,17 @@ class ListenableFutureTest : TestBase() {
@Test
fun testExceptionOnExternalCancellation() = runTest(expected = {it is TestException}) {
+ expect(1)
val result = future(Dispatchers.Unconfined) {
try {
- expect(1)
delay(Long.MAX_VALUE)
- expectUnreached()
- } catch (e: CancellationException) {
- expect(3)
+ } finally {
+ expect(2)
throw TestException()
}
}
- expect(2)
result.cancel(true)
- finish(4)
+ finish(3)
}
@Test
@@ -573,164 +540,12 @@ class ListenableFutureTest : TestBase() {
finish(3)
}
- /** This test ensures that we never pass [CancellationException] to [CoroutineExceptionHandler]. */
- @Test
- fun testCancellationExceptionOnExternalCancellation() = runTest {
- expect(1)
- // No parent here (NonCancellable), so nowhere to propagate exception
- val result = future(NonCancellable + Dispatchers.Unconfined) {
- try {
- delay(Long.MAX_VALUE)
- } finally {
- expect(2)
- throw TestCancellationException() // this exception cannot be handled
- }
- }
- assertTrue(result.cancel(true))
- finish(3)
- }
-
- @Test
- fun testCancellingFutureContextJobCancelsFuture() = runTest {
- expect(1)
- val supervisorJob = SupervisorJob()
- val future = future(context = supervisorJob) {
- expect(2)
- try {
- delay(Long.MAX_VALUE)
- expectUnreached()
- } catch (e: CancellationException) {
- expect(4)
- throw e
- }
- }
- yield()
- expect(3)
- supervisorJob.cancel(CancellationException("Parent cancelled", TestException()))
- supervisorJob.join()
- assertTrue(future.isDone)
- assertTrue(future.isCancelled)
- val thrown = assertFailsWith<CancellationException> { future.get() }
- val cause = thrown.cause
- assertNotNull(cause)
- assertTrue(cause is CancellationException)
- assertEquals("Parent cancelled", cause.message)
- assertTrue(cause.cause is TestException)
- finish(5)
- }
-
- @Test
- fun testFutureChildException() = runTest {
- val future = future(context = NonCancellable + Dispatchers.Unconfined) {
- val foo = async { delay(Long.MAX_VALUE); 42 }
- val bar = async<Int> { throw TestException() }
- foo.await() + bar.await()
- }
- future.checkFutureException<TestException>()
- }
-
- @Test
- fun testFutureIsDoneAfterChildrenCompleted() = runTest {
- expect(1)
- val testException = TestException()
- // Don't propagate exception to the test and use different dispatchers as we are going to block test thread.
- val future = future(context = NonCancellable + Dispatchers.Default) {
- val foo = async {
- try {
- delay(Long.MAX_VALUE)
- 42
- } finally {
- withContext(NonCancellable) {
- delay(200)
- }
- }
- }
- foo.invokeOnCompletion {
- expect(3)
- }
- val bar = async<Int> { throw testException }
- foo.await() + bar.await()
- }
- yield()
- expect(2)
- // Blocking get should succeed after internal coroutine completes.
- val thrown = assertFailsWith<ExecutionException> { future.get() }
- expect(4)
- assertEquals(testException, thrown.cause)
- finish(5)
- }
-
- @Test
- @Ignore // TODO: propagate cancellation before running listeners.
- fun testFuturePropagatesCancellationBeforeRunningListeners() = runTest {
- expect(1)
- val future = future(context = Dispatchers.Unconfined) {
- try {
- delay(Long.MAX_VALUE)
- } finally {
- expect(3) // Cancelled.
- }
- }
- future.addListener(Runnable { expect(4) }, MoreExecutors.directExecutor())
- assertFalse(future.isDone)
- expect(2)
- future.cancel(false)
- assertTrue(future.isDone)
- assertTrue(future.isCancelled)
- finish(5)
- }
-
- @Test
- fun testFutureCompletedExceptionally() = runTest {
- val testException = TestException()
- // NonCancellable to not propagate error to this scope.
- val future = future(context = NonCancellable) {
- throw testException
- }
- yield()
- assertTrue(future.isDone)
- assertFalse(future.isCancelled)
- val thrown = assertFailsWith<ExecutionException> { future.get() }
- assertEquals(testException, thrown.cause)
- }
-
- @Test
- fun testAsListenableFutureCompletedExceptionally() = runTest {
- val testException = TestException()
- val deferred = CompletableDeferred<String>().apply {
- completeExceptionally(testException)
- }
- val asListenableFuture = deferred.asListenableFuture()
- assertTrue(asListenableFuture.isDone)
- assertFalse(asListenableFuture.isCancelled)
- val thrown = assertFailsWith<ExecutionException> { asListenableFuture.get() }
- assertEquals(testException, thrown.cause)
- }
-
- @Test
- fun stressTestJobListenableFutureIsCancelledDoesNotThrow() = runTest {
- repeat(1000) {
- val deferred = CompletableDeferred<String>()
- val asListenableFuture = deferred.asListenableFuture()
- // We heed two threads to test a race condition.
- withContext(Dispatchers.Default) {
- val cancellationJob = launch {
- asListenableFuture.cancel(false)
- }
- while (!cancellationJob.isCompleted) {
- asListenableFuture.isCancelled // Shouldn't throw.
- }
- }
- }
- }
-
private inline fun <reified T: Throwable> ListenableFuture<*>.checkFutureException() {
val e = assertFailsWith<ExecutionException> { get() }
val cause = e.cause!!
assertTrue(cause is T)
}
- @Suppress("SuspendFunctionOnCoroutineScope")
private suspend fun CoroutineScope.awaitFutureWithCancel(cancellable: Boolean): ListenableFuture<Int> {
val latch = CountDownLatch(1)
val executor = MoreExecutors.listeningDecorator(ForkJoinPool.commonPool())
diff --git a/integration/kotlinx-coroutines-guava/test/ListenableFutureToStringTest.kt b/integration/kotlinx-coroutines-guava/test/ListenableFutureToStringTest.kt
deleted file mode 100644
index 13ac2990..00000000
--- a/integration/kotlinx-coroutines-guava/test/ListenableFutureToStringTest.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines.guava
-
-import kotlinx.coroutines.*
-import org.junit.Test
-import kotlin.test.*
-
-class ListenableFutureToStringTest : TestBase() {
- @Test
- fun testSuccessfulFuture() = runTest {
- val deferred = CompletableDeferred("OK")
- val succeededFuture = deferred.asListenableFuture()
- val toString = succeededFuture.toString()
- assertTrue(message = "Unexpected format: $toString") {
- toString.matches(Regex("""kotlinx\.coroutines\.guava\.JobListenableFuture@[^\[]*\[status=SUCCESS, result=\[OK]]"""))
- }
- }
-
- @Test
- fun testFailedFuture() = runTest {
- val exception = TestRuntimeException("test")
- val deferred = CompletableDeferred<String>().apply {
- completeExceptionally(exception)
- }
- val failedFuture = deferred.asListenableFuture()
- val toString = failedFuture.toString()
- assertTrue(message = "Unexpected format: $toString") {
- toString.matches(Regex("""kotlinx\.coroutines\.guava\.JobListenableFuture@[^\[]*\[status=FAILURE, cause=\[$exception]]"""))
- }
- }
-
- @Test
- fun testPendingFuture() = runTest {
- val deferred = CompletableDeferred<String>()
- val pendingFuture = deferred.asListenableFuture()
- val toString = pendingFuture.toString()
- assertTrue(message = "Unexpected format: $toString") {
- toString.matches(Regex("""kotlinx\.coroutines\.guava\.JobListenableFuture@[^\[]*\[status=PENDING, delegate=\[.*]]"""))
- }
- }
-
- @Test
- fun testCancelledCoroutineAsListenableFuture() = runTest {
- val exception = CancellationException("test")
- val deferred = CompletableDeferred<String>().apply {
- cancel(exception)
- }
- val cancelledFuture = deferred.asListenableFuture()
- val toString = cancelledFuture.toString()
- assertTrue(message = "Unexpected format: $toString") {
- toString.matches(Regex("""kotlinx\.coroutines\.guava\.JobListenableFuture@[^\[]*\[status=CANCELLED, cause=\[$exception]]"""))
- }
- }
-
- @Test
- fun testCancelledFuture() = runTest {
- val deferred = CompletableDeferred<String>()
- val cancelledFuture = deferred.asListenableFuture().apply {
- cancel(false)
- }
- val toString = cancelledFuture.toString()
- assertTrue(message = "Unexpected format: $toString") {
- toString.matches(Regex("""kotlinx\.coroutines\.guava\.JobListenableFuture@[^\[]*\[status=CANCELLED]"""))
- }
- }
-}
diff --git a/integration/kotlinx-coroutines-jdk8/README.md b/integration/kotlinx-coroutines-jdk8/README.md
index aebd90f0..3a204416 100644
--- a/integration/kotlinx-coroutines-jdk8/README.md
+++ b/integration/kotlinx-coroutines-jdk8/README.md
@@ -53,16 +53,12 @@ Integration with JDK8 [CompletableFuture] (Android API level 24).
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
-
[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html
-
<!--- MODULE kotlinx-coroutines-jdk8 -->
<!--- INDEX kotlinx.coroutines.future -->
-
[future]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/kotlinx.coroutines.-coroutine-scope/future.html
[java.util.concurrent.CompletionStage.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/java.util.concurrent.-completion-stage/await.html
[java.util.concurrent.CompletionStage.asDeferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/java.util.concurrent.-completion-stage/as-deferred.html
[kotlinx.coroutines.Deferred.asCompletableFuture]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.future/kotlinx.coroutines.-deferred/as-completable-future.html
-
<!--- END -->
diff --git a/integration/kotlinx-coroutines-jdk8/build.gradle.kts b/integration/kotlinx-coroutines-jdk8/build.gradle.kts
index 791bd950..09915929 100644
--- a/integration/kotlinx-coroutines-jdk8/build.gradle.kts
+++ b/integration/kotlinx-coroutines-jdk8/build.gradle.kts
@@ -1,4 +1,4 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
diff --git a/integration/kotlinx-coroutines-jdk8/src/future/Future.kt b/integration/kotlinx-coroutines-jdk8/src/future/Future.kt
index b3b45e9d..f7fdba5f 100644
--- a/integration/kotlinx-coroutines-jdk8/src/future/Future.kt
+++ b/integration/kotlinx-coroutines-jdk8/src/future/Future.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.future
@@ -105,19 +105,16 @@ private fun Job.setupCancellation(future: CompletableFuture<*>) {
}
/**
- * Converts this [CompletionStage] to an instance of [Deferred].
- *
- * The [CompletableFuture] that corresponds to this [CompletionStage] (see [CompletionStage.toCompletableFuture])
- * is cancelled when the resulting deferred is cancelled.
+ * Converts this completion stage to an instance of [Deferred].
+ * When this completion stage is an instance of [Future], then it is cancelled when
+ * the resulting deferred is cancelled.
*/
-@Suppress("DeferredIsResult")
public fun <T> CompletionStage<T>.asDeferred(): Deferred<T> {
- val future = toCompletableFuture() // retrieve the future
// Fast path if already completed
- if (future.isDone) {
+ if (this is Future<*> && isDone()){
return try {
@Suppress("UNCHECKED_CAST")
- CompletableDeferred(future.get() as T)
+ CompletableDeferred(get() as T)
} catch (e: Throwable) {
// unwrap original cause from ExecutionException
val original = (e as? ExecutionException)?.cause ?: e
@@ -135,28 +132,25 @@ public fun <T> CompletionStage<T>.asDeferred(): Deferred<T> {
result.completeExceptionally((exception as? CompletionException)?.cause ?: exception)
}
}
- result.cancelFutureOnCompletion(future)
+ if (this is Future<*>) result.cancelFutureOnCompletion(this)
return result
}
/**
- * Awaits for completion of [CompletionStage] without blocking a thread.
+ * Awaits for completion of the completion stage without blocking a thread.
*
* This suspending function is cancellable.
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
* stops waiting for the completion stage and immediately resumes with [CancellationException][kotlinx.coroutines.CancellationException].
- *
- * This method is intended to be used with one-shot futures, so on coroutine cancellation the [CompletableFuture] that
- * corresponds to this [CompletionStage] (see [CompletionStage.toCompletableFuture])
- * is cancelled. If cancelling the given stage is undesired, `stage.asDeferred().await()` should be used instead.
+ * This method is intended to be used with one-shot futures, so on coroutine cancellation completion stage is cancelled as well if it is instance of [CompletableFuture].
+ * If cancelling given stage is undesired, `stage.asDeferred().await()` should be used instead.
*/
public suspend fun <T> CompletionStage<T>.await(): T {
- val future = toCompletableFuture() // retrieve the future
// fast path when CompletableFuture is already done (does not suspend)
- if (future.isDone) {
+ if (this is Future<*> && isDone()) {
try {
- @Suppress("UNCHECKED_CAST", "BlockingMethodInNonBlockingContext")
- return future.get() as T
+ @Suppress("UNCHECKED_CAST")
+ return get() as T
} catch (e: ExecutionException) {
throw e.cause ?: e // unwrap original cause from ExecutionException
}
@@ -166,7 +160,8 @@ public suspend fun <T> CompletionStage<T>.await(): T {
val consumer = ContinuationConsumer(cont)
whenComplete(consumer)
cont.invokeOnCancellation {
- future.cancel(false)
+ // mayInterruptIfRunning is not used
+ (this as? CompletableFuture<T>)?.cancel(false)
consumer.cont = null // shall clear reference to continuation to aid GC
}
}
diff --git a/integration/kotlinx-coroutines-jdk8/src/stream/Stream.kt b/integration/kotlinx-coroutines-jdk8/src/stream/Stream.kt
index 1d804e59..641a83a6 100644
--- a/integration/kotlinx-coroutines-jdk8/src/stream/Stream.kt
+++ b/integration/kotlinx-coroutines-jdk8/src/stream/Stream.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.stream
diff --git a/integration/kotlinx-coroutines-jdk8/src/time/Time.kt b/integration/kotlinx-coroutines-jdk8/src/time/Time.kt
index 78cf6e53..acff1d21 100644
--- a/integration/kotlinx-coroutines-jdk8/src/time/Time.kt
+++ b/integration/kotlinx-coroutines-jdk8/src/time/Time.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:OptIn(ExperimentalContracts::class)
diff --git a/integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt b/integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt
index 998aaa08..f75c9674 100644
--- a/integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt
+++ b/integration/kotlinx-coroutines-jdk8/test/future/FutureTest.kt
@@ -490,81 +490,4 @@ class FutureTest : TestBase() {
}
}
}
-
- /**
- * https://github.com/Kotlin/kotlinx.coroutines/issues/2456
- */
- @Test
- fun testCompletedStageAwait() = runTest {
- val stage = CompletableFuture.completedStage("OK")
- assertEquals("OK", stage.await())
- }
-
- /**
- * https://github.com/Kotlin/kotlinx.coroutines/issues/2456
- */
- @Test
- fun testCompletedStageAsDeferredAwait() = runTest {
- val stage = CompletableFuture.completedStage("OK")
- val deferred = stage.asDeferred()
- assertEquals("OK", deferred.await())
- }
-
- @Test
- fun testCompletedStateThenApplyAwait() = runTest {
- expect(1)
- val cf = CompletableFuture<String>()
- launch {
- expect(3)
- cf.complete("O")
- }
- expect(2)
- val stage = cf.thenApply { it + "K" }
- assertEquals("OK", stage.await())
- finish(4)
- }
-
- @Test
- fun testCompletedStateThenApplyAwaitCancel() = runTest {
- expect(1)
- val cf = CompletableFuture<String>()
- launch {
- expect(3)
- cf.cancel(false)
- }
- expect(2)
- val stage = cf.thenApply { it + "K" }
- assertFailsWith<CancellationException> { stage.await() }
- finish(4)
- }
-
- @Test
- fun testCompletedStateThenApplyAsDeferredAwait() = runTest {
- expect(1)
- val cf = CompletableFuture<String>()
- launch {
- expect(3)
- cf.complete("O")
- }
- expect(2)
- val stage = cf.thenApply { it + "K" }
- val deferred = stage.asDeferred()
- assertEquals("OK", deferred.await())
- finish(4)
- }
-
- @Test
- fun testCompletedStateThenApplyAsDeferredAwaitCancel() = runTest {
- expect(1)
- val cf = CompletableFuture<String>()
- expect(2)
- val stage = cf.thenApply { it + "K" }
- val deferred = stage.asDeferred()
- launch {
- expect(3)
- deferred.cancel() // cancel the deferred!
- }
- assertFailsWith<CancellationException> { stage.await() }
- finish(4)
- }
}
diff --git a/integration/kotlinx-coroutines-play-services/build.gradle b/integration/kotlinx-coroutines-play-services/build.gradle
new file mode 100644
index 00000000..29ce3d60
--- /dev/null
+++ b/integration/kotlinx-coroutines-play-services/build.gradle
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+ext.tasks_version = '16.0.1'
+
+def artifactType = Attribute.of("artifactType", String)
+def unpackedAar = Attribute.of("unpackedAar", Boolean)
+
+configurations.all {
+ afterEvaluate {
+ if (canBeResolved) {
+ attributes.attribute(unpackedAar, true) // request all AARs to be unpacked
+ }
+ }
+}
+
+dependencies {
+ attributesSchema {
+ attribute(unpackedAar)
+ }
+
+ artifactTypes {
+ aar {
+ attributes.attribute(unpackedAar, false)
+ }
+ }
+
+ registerTransform(UnpackAar) {
+ from.attribute(unpackedAar, false).attribute(artifactType, "aar")
+ to.attribute(unpackedAar, true).attribute(artifactType, "jar")
+ }
+
+ api("com.google.android.gms:play-services-tasks:$tasks_version") {
+ exclude group: 'com.android.support'
+ }
+}
+
+tasks.withType(dokka.getClass()) {
+ externalDocumentationLink {
+ url = new URL("https://developers.google.com/android/reference/")
+ // This is workaround for missing package list in Google API
+ packageListUrl = projectDir.toPath().resolve("package.list").toUri().toURL()
+ }
+}
diff --git a/integration/kotlinx-coroutines-play-services/build.gradle.kts b/integration/kotlinx-coroutines-play-services/build.gradle.kts
deleted file mode 100644
index 59f3b0bd..00000000
--- a/integration/kotlinx-coroutines-play-services/build.gradle.kts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-val tasksVersion = "16.0.1"
-
-val artifactType = Attribute.of("artifactType", String::class.java)
-val unpackedAar = Attribute.of("unpackedAar", Boolean::class.javaObjectType)
-
-configurations.configureEach {
- afterEvaluate {
- if (isCanBeResolved) {
- attributes.attribute(unpackedAar, true) // request all AARs to be unpacked
- }
- }
-}
-
-dependencies {
- attributesSchema {
- attribute(unpackedAar)
- }
-
- artifactTypes {
- create("aar") {
- attributes.attribute(unpackedAar, false)
- }
- }
-
- registerTransform(UnpackAar::class.java) {
- from.attribute(unpackedAar, false).attribute(artifactType, "aar")
- to.attribute(unpackedAar, true).attribute(artifactType, "jar")
- }
-
- api("com.google.android.gms:play-services-tasks:$tasksVersion") {
- exclude(group="com.android.support")
- }
-}
-
-externalDocumentationLink(
- url = "https://developers.google.com/android/reference/"
-)
diff --git a/integration/kotlinx-coroutines-play-services/src/Tasks.kt b/integration/kotlinx-coroutines-play-services/src/Tasks.kt
index d89d1aec..f9b9a604 100644
--- a/integration/kotlinx-coroutines-play-services/src/Tasks.kt
+++ b/integration/kotlinx-coroutines-play-services/src/Tasks.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("RedundantVisibilityModifier")
diff --git a/integration/kotlinx-coroutines-slf4j/README.md b/integration/kotlinx-coroutines-slf4j/README.md
index e23d3907..ee5fb320 100644
--- a/integration/kotlinx-coroutines-slf4j/README.md
+++ b/integration/kotlinx-coroutines-slf4j/README.md
@@ -20,7 +20,5 @@ Integration with SLF4J [MDC](https://logback.qos.ch/manual/mdc.html).
<!--- MODULE kotlinx-coroutines-slf4j -->
<!--- INDEX kotlinx.coroutines.slf4j -->
-
[MDCContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-slf4j/kotlinx.coroutines.slf4j/-m-d-c-context/index.html
-
<!--- END -->
diff --git a/integration/kotlinx-coroutines-slf4j/build.gradle.kts b/integration/kotlinx-coroutines-slf4j/build.gradle.kts
index a341eefe..c7d0d82d 100644
--- a/integration/kotlinx-coroutines-slf4j/build.gradle.kts
+++ b/integration/kotlinx-coroutines-slf4j/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
dependencies {
diff --git a/integration/kotlinx-coroutines-slf4j/src/MDCContext.kt b/integration/kotlinx-coroutines-slf4j/src/MDCContext.kt
index 9528f2b2..078800d0 100644
--- a/integration/kotlinx-coroutines-slf4j/src/MDCContext.kt
+++ b/integration/kotlinx-coroutines-slf4j/src/MDCContext.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.slf4j
diff --git a/js/example-frontend-js/build.gradle b/js/example-frontend-js/build.gradle
new file mode 100644
index 00000000..7abde639
--- /dev/null
+++ b/js/example-frontend-js/build.gradle
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+project.kotlin {
+ js(LEGACY) {
+ binaries.executable()
+ browser {
+ distribution {
+ directory = new File(directory.parentFile, "dist")
+ }
+ webpackTask {
+ cssSupport.enabled = true
+ }
+ runTask {
+ cssSupport.enabled = true
+ }
+ testTask {
+ useKarma {
+ useChromeHeadless()
+ webpackConfig.cssSupport.enabled = true
+ }
+ }
+ }
+ }
+
+ sourceSets {
+ main.dependencies {
+ implementation "org.jetbrains.kotlinx:kotlinx-html-js:$html_version"
+ implementation(npm("html-webpack-plugin", "3.2.0"))
+ }
+ }
+}
diff --git a/js/example-frontend-js/build.gradle.kts b/js/example-frontend-js/build.gradle.kts
deleted file mode 100644
index 5b18966f..00000000
--- a/js/example-frontend-js/build.gradle.kts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-kotlin {
- js(LEGACY) {
- binaries.executable()
- browser {
- distribution {
- directory = directory.parentFile.resolve("dist")
- }
- commonWebpackConfig {
- cssSupport.enabled = true
- }
- testTask {
- useKarma {
- useChromeHeadless()
- }
- }
- }
- }
-}
-
-dependencies {
- implementation("org.jetbrains.kotlinx:kotlinx-html-js:${version("html")}")
- implementation(devNpm("html-webpack-plugin", "3.2.0"))
-}
diff --git a/js/example-frontend-js/src/ExampleMain.kt b/js/example-frontend-js/src/ExampleMain.kt
index d4e530b0..da6e4196 100644
--- a/js/example-frontend-js/src/ExampleMain.kt
+++ b/js/example-frontend-js/src/ExampleMain.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import kotlinx.coroutines.*
diff --git a/js/example-frontend-js/src/main/web/style.css b/js/example-frontend-js/src/main/web/style.css
index e2e777a5..31d0ebc0 100644
--- a/js/example-frontend-js/src/main/web/style.css
+++ b/js/example-frontend-js/src/main/web/style.css
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
#scene {
diff --git a/js/js-stub/build.gradle.kts b/js/js-stub/build.gradle.kts
index 201ac43c..6b9d6555 100644
--- a/js/js-stub/build.gradle.kts
+++ b/js/js-stub/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
diff --git a/js/js-stub/src/Performance.kt b/js/js-stub/src/Performance.kt
index eefb1d74..0b85c93d 100644
--- a/js/js-stub/src/Performance.kt
+++ b/js/js-stub/src/Performance.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package org.w3c.performance
diff --git a/js/js-stub/src/Promise.kt b/js/js-stub/src/Promise.kt
index 243d0c9e..7413a872 100644
--- a/js/js-stub/src/Promise.kt
+++ b/js/js-stub/src/Promise.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlin.js
diff --git a/js/js-stub/src/Window.kt b/js/js-stub/src/Window.kt
index 8b2bb800..f54ed0d7 100644
--- a/js/js-stub/src/Window.kt
+++ b/js/js-stub/src/Window.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package org.w3c.dom
diff --git a/knit.properties b/knit.properties
index 45b2216d..bc177ce4 100644
--- a/knit.properties
+++ b/knit.properties
@@ -1,5 +1,5 @@
#
-# Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+# Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
#
knit.include=docs/knit.code.include
@@ -13,4 +13,4 @@ test.mode.FLEXIBLE_TIME=verifyLinesFlexibleTime
test.mode.FLEXIBLE_THREAD=verifyLinesFlexibleThread
test.mode.LINES_START_UNORDERED=verifyLinesStartUnordered
test.mode.LINES_START=verifyLinesStart
-test.mode.EXCEPTION=verifyExceptions
+test.mode.EXCEPTION=verifyExceptions \ No newline at end of file
diff --git a/kotlinx-coroutines-bom/build.gradle b/kotlinx-coroutines-bom/build.gradle
index ef87f3f7..e39c9229 100644
--- a/kotlinx-coroutines-bom/build.gradle
+++ b/kotlinx-coroutines-bom/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
plugins {
id 'java-platform'
diff --git a/kotlinx-coroutines-core/README.md b/kotlinx-coroutines-core/README.md
index bc558762..5fe32981 100644
--- a/kotlinx-coroutines-core/README.md
+++ b/kotlinx-coroutines-core/README.md
@@ -90,7 +90,6 @@ Obsolete and deprecated module to test coroutines. Replaced with `kotlinx-corout
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
-
[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
@@ -115,16 +114,12 @@ Obsolete and deprecated module to test coroutines. Replaced with `kotlinx-corout
[Job.isCompleted]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/is-completed.html
[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/await.html
[Deferred.onAwait]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/on-await.html
-
<!--- INDEX kotlinx.coroutines.sync -->
-
[kotlinx.coroutines.sync.Mutex]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/index.html
[kotlinx.coroutines.sync.Mutex.lock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/lock.html
[kotlinx.coroutines.sync.Mutex.onLock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/on-lock.html
[kotlinx.coroutines.sync.Mutex.tryLock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/try-lock.html
-
<!--- INDEX kotlinx.coroutines.channels -->
-
[kotlinx.coroutines.channels.produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/produce.html
[kotlinx.coroutines.channels.ReceiveChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/index.html
[kotlinx.coroutines.channels.ProducerScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-producer-scope/index.html
@@ -138,11 +133,8 @@ Obsolete and deprecated module to test coroutines. Replaced with `kotlinx-corout
[kotlinx.coroutines.channels.ReceiveChannel.poll]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/poll.html
[kotlinx.coroutines.channels.receiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/receive-or-null.html
[kotlinx.coroutines.channels.onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/on-receive-or-null.html
-
<!--- INDEX kotlinx.coroutines.selects -->
-
[kotlinx.coroutines.selects.select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html
[kotlinx.coroutines.selects.SelectBuilder.onTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/-select-builder/on-timeout.html
-
<!--- INDEX kotlinx.coroutines.test -->
<!--- END -->
diff --git a/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api b/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api
index 1d16d310..b86076fc 100644
--- a/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api
+++ b/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api
@@ -270,7 +270,7 @@ public final class kotlinx/coroutines/Delay$DefaultImpls {
public final class kotlinx/coroutines/DelayKt {
public static final fun awaitCancellation (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun delay (JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
- public static final fun delay-VtjQ1oo (DLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+ public static final fun delay-p9JZ4hM (DLkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
public final class kotlinx/coroutines/Dispatchers {
@@ -535,9 +535,9 @@ public final class kotlinx/coroutines/TimeoutCancellationException : java/util/c
public final class kotlinx/coroutines/TimeoutKt {
public static final fun withTimeout (JLkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
- public static final fun withTimeout-KLykuaI (DLkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+ public static final fun withTimeout-lwyi7ZQ (DLkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun withTimeoutOrNull (JLkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
- public static final fun withTimeoutOrNull-KLykuaI (DLkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+ public static final fun withTimeoutOrNull-lwyi7ZQ (DLkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
public final class kotlinx/coroutines/YieldKt {
@@ -796,7 +796,7 @@ public abstract interface class kotlinx/coroutines/channels/ReceiveChannel {
public abstract fun iterator ()Lkotlinx/coroutines/channels/ChannelIterator;
public abstract fun poll ()Ljava/lang/Object;
public abstract fun receive (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
- public abstract fun receiveOrClosed-WVj179g (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+ public abstract fun receiveOrClosed-ZYPwvRU (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun receiveOrNull (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
@@ -861,6 +861,10 @@ public final class kotlinx/coroutines/debug/internal/DebugCoroutineInfo {
public final fun lastObservedStackTrace ()Ljava/util/List;
}
+public synthetic class kotlinx/coroutines/debug/internal/DebugProbesImplSequenceNumberRefVolatile {
+ public fun <init> (J)V
+}
+
public final class kotlinx/coroutines/debug/internal/DebuggerInfo : java/io/Serializable {
public fun <init> (Lkotlinx/coroutines/debug/internal/DebugCoroutineInfoImpl;Lkotlin/coroutines/CoroutineContext;)V
public final fun getCoroutineId ()Ljava/lang/Long;
@@ -939,7 +943,7 @@ public final class kotlinx/coroutines/flow/FlowKt {
public static final fun count (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun debounce (Lkotlinx/coroutines/flow/Flow;J)Lkotlinx/coroutines/flow/Flow;
public static final fun debounce (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
- public static final fun debounce-HG0u8IE (Lkotlinx/coroutines/flow/Flow;D)Lkotlinx/coroutines/flow/Flow;
+ public static final fun debounce-8GFy2Ro (Lkotlinx/coroutines/flow/Flow;D)Lkotlinx/coroutines/flow/Flow;
public static final fun debounceDuration (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
public static final fun delayEach (Lkotlinx/coroutines/flow/Flow;J)Lkotlinx/coroutines/flow/Flow;
public static final fun delayFlow (Lkotlinx/coroutines/flow/Flow;J)Lkotlinx/coroutines/flow/Flow;
@@ -1015,7 +1019,7 @@ public final class kotlinx/coroutines/flow/FlowKt {
public static final fun retryWhen (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function4;)Lkotlinx/coroutines/flow/Flow;
public static final fun runningReduce (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
public static final fun sample (Lkotlinx/coroutines/flow/Flow;J)Lkotlinx/coroutines/flow/Flow;
- public static final fun sample-HG0u8IE (Lkotlinx/coroutines/flow/Flow;D)Lkotlinx/coroutines/flow/Flow;
+ public static final fun sample-8GFy2Ro (Lkotlinx/coroutines/flow/Flow;D)Lkotlinx/coroutines/flow/Flow;
public static final fun scan (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
public static final fun scanFold (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
public static final fun scanReduce (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
@@ -1060,7 +1064,6 @@ public final class kotlinx/coroutines/flow/LintKt {
}
public abstract interface class kotlinx/coroutines/flow/MutableSharedFlow : kotlinx/coroutines/flow/FlowCollector, kotlinx/coroutines/flow/SharedFlow {
- public abstract fun emit (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun getSubscriptionCount ()Lkotlinx/coroutines/flow/StateFlow;
public abstract fun resetReplayCache ()V
public abstract fun tryEmit (Ljava/lang/Object;)Z
@@ -1102,8 +1105,8 @@ public final class kotlinx/coroutines/flow/SharingStarted$Companion {
}
public final class kotlinx/coroutines/flow/SharingStartedKt {
- public static final fun WhileSubscribed-5qebJ5I (Lkotlinx/coroutines/flow/SharingStarted$Companion;DD)Lkotlinx/coroutines/flow/SharingStarted;
- public static synthetic fun WhileSubscribed-5qebJ5I$default (Lkotlinx/coroutines/flow/SharingStarted$Companion;DDILjava/lang/Object;)Lkotlinx/coroutines/flow/SharingStarted;
+ public static final fun WhileSubscribed-9tZugJw (Lkotlinx/coroutines/flow/SharingStarted$Companion;DD)Lkotlinx/coroutines/flow/SharingStarted;
+ public static synthetic fun WhileSubscribed-9tZugJw$default (Lkotlinx/coroutines/flow/SharingStarted$Companion;DDILjava/lang/Object;)Lkotlinx/coroutines/flow/SharingStarted;
}
public abstract interface class kotlinx/coroutines/flow/StateFlow : kotlinx/coroutines/flow/SharedFlow {
@@ -1234,7 +1237,7 @@ public abstract interface class kotlinx/coroutines/selects/SelectInstance {
}
public final class kotlinx/coroutines/selects/SelectKt {
- public static final fun onTimeout-8Mi8wO0 (Lkotlinx/coroutines/selects/SelectBuilder;DLkotlin/jvm/functions/Function1;)V
+ public static final fun onTimeout-0lHKgQg (Lkotlinx/coroutines/selects/SelectBuilder;DLkotlin/jvm/functions/Function1;)V
public static final fun select (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
diff --git a/kotlinx-coroutines-core/build.gradle b/kotlinx-coroutines-core/build.gradle
index c2a57f9d..f98f6a52 100644
--- a/kotlinx-coroutines-core/build.gradle
+++ b/kotlinx-coroutines-core/build.gradle
@@ -1,16 +1,12 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
apply plugin: 'org.jetbrains.kotlin.multiplatform'
apply from: rootProject.file("gradle/compile-jvm-multiplatform.gradle")
apply from: rootProject.file("gradle/compile-common.gradle")
-
-if (rootProject.ext.native_targets_enabled) {
- apply from: rootProject.file("gradle/compile-native-multiplatform.gradle")
-}
-
apply from: rootProject.file("gradle/compile-js-multiplatform.gradle")
+apply from: rootProject.file("gradle/compile-native-multiplatform.gradle")
apply from: rootProject.file('gradle/publish-npm-js.gradle')
/* ==========================================================================
@@ -56,11 +52,8 @@ static boolean isNativeDarwin(String name) { return ["ios", "macos", "tvos", "wa
static boolean isNativeOther(String name) { return ["linux", "mingw"].any { name.startsWith(it) } }
defineSourceSet("concurrent", ["common"]) { it in ["jvm", "native"] }
-
-if (rootProject.ext.native_targets_enabled) {
- defineSourceSet("nativeDarwin", ["native"]) { isNativeDarwin(it) }
- defineSourceSet("nativeOther", ["native"]) { isNativeOther(it) }
-}
+defineSourceSet("nativeDarwin", ["native"]) { isNativeDarwin(it) }
+defineSourceSet("nativeOther", ["native"]) { isNativeOther(it) }
/* ========================================================================== */
@@ -136,7 +129,7 @@ def configureNativeSourceSetPreset(name, preset) {
}
// :KLUDGE: Idea.active: Configure platform libraries for native source sets when working in IDEA
-if (Idea.active && rootProject.ext.native_targets_enabled) {
+if (Idea.active) {
def manager = project.ext.hostManager
def linuxPreset = kotlin.presets.linuxX64
def macosPreset = kotlin.presets.macosX64
@@ -184,28 +177,12 @@ jvmTest {
minHeapSize = '1g'
maxHeapSize = '1g'
enableAssertions = true
- if (!Idea.active) {
- // We should not set this security manager when `jvmTest`
- // is invoked by IntelliJ IDEA since we need to pass
- // system properties for Lincheck and stress tests.
- // TODO Remove once IDEA is smart enough to select between `jvmTest`/`jvmStressTest`/`jvmLincheckTest` #KTIJ-599
- systemProperty 'java.security.manager', 'kotlinx.coroutines.TestSecurityManager'
- }
+ systemProperty 'java.security.manager', 'kotlinx.coroutines.TestSecurityManager'
// 'stress' is required to be able to run all subpackage tests like ":jvmTests --tests "*channels*" -Pstress=true"
if (!Idea.active && rootProject.properties['stress'] == null) {
- exclude '**/*LincheckTest.*'
exclude '**/*StressTest.*'
}
- if (Idea.active) {
- // Configure the IDEA runner for Lincheck
- configureJvmForLincheck(jvmTest)
- }
- // TODO: JVM IR generates different stacktrace so temporary disable stacktrace tests
- if (rootProject.ext.jvm_ir_enabled) {
- filter {
- excludeTestsMatching('kotlinx.coroutines.exceptions.StackTraceRecovery*')
- }
- }
+ systemProperty 'kotlinx.coroutines.scheduler.keep.alive.sec', '100000' // any unpark problem hangs test
}
jvmJar {
@@ -228,41 +205,23 @@ task jvmStressTest(type: Test, dependsOn: compileTestKotlinJvm) {
systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '10'
}
-task jvmLincheckTest(type: Test, dependsOn: compileTestKotlinJvm) {
- classpath = files { jvmTest.classpath }
- testClassesDirs = files { jvmTest.testClassesDirs }
- include '**/*LincheckTest.*'
- enableAssertions = true
- testLogging.showStandardStreams = true
- configureJvmForLincheck(jvmLincheckTest)
-}
-
-static void configureJvmForLincheck(task) {
- task.minHeapSize = '1g'
- task.maxHeapSize = '6g' // we may need more space for building an interleaving tree in the model checking mode
- task.jvmArgs = ['--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED', // required for transformation
- '--add-exports', 'java.base/jdk.internal.util=ALL-UNNAMED'] // in the model checking mode
- task.systemProperty 'kotlinx.coroutines.semaphore.segmentSize', '2'
- task.systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '1' // better for the model checking mode
-}
-
task jdk16Test(type: Test, dependsOn: [compileTestKotlinJvm, checkJdk16]) {
classpath = files { jvmTest.classpath }
testClassesDirs = files { jvmTest.testClassesDirs }
executable = "$System.env.JDK_16/bin/java"
exclude '**/*LFStressTest.*' // lock-freedom tests use LockFreedomTestEnvironment which needs JDK8
- exclude '**/*LincheckTest.*' // Lincheck tests use LinChecker which needs JDK8
+ exclude '**/*LCStressTest.*' // lin-check tests use LinChecker which needs JDK8
exclude '**/exceptions/**' // exceptions tests check suppressed exception which needs JDK8
exclude '**/ExceptionsGuideTest.*'
exclude '**/RunInterruptibleStressTest.*' // fails on JDK 1.6 due to JDK bug
}
-// Run jdk16Test test only during nightly stress test
+// Run these tests only during nightly stress test
jdk16Test.onlyIf { project.properties['stressTest'] != null }
-// Always check additional test sets
-task moreTest(dependsOn: [jvmStressTest, jvmLincheckTest, jdk16Test])
-check.dependsOn moreTest
+// Always run those tests
+task moreTest(dependsOn: [jvmStressTest, jdk16Test])
+build.dependsOn moreTest
task testsJar(type: Jar, dependsOn: jvmTestClasses) {
classifier = 'tests'
diff --git a/kotlinx-coroutines-core/common/README.md b/kotlinx-coroutines-core/common/README.md
index 6712648a..e59392ee 100644
--- a/kotlinx-coroutines-core/common/README.md
+++ b/kotlinx-coroutines-core/common/README.md
@@ -97,7 +97,6 @@ Low-level primitives for finer-grained control of coroutines.
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
-
[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
@@ -126,16 +125,12 @@ Low-level primitives for finer-grained control of coroutines.
[Deferred.onAwait]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/on-await.html
[newCoroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/new-coroutine-context.html
[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
-
<!--- INDEX kotlinx.coroutines.sync -->
-
[kotlinx.coroutines.sync.Mutex]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/index.html
[kotlinx.coroutines.sync.Mutex.lock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/lock.html
[kotlinx.coroutines.sync.Mutex.onLock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/on-lock.html
[kotlinx.coroutines.sync.Mutex.tryLock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/try-lock.html
-
<!--- INDEX kotlinx.coroutines.channels -->
-
[kotlinx.coroutines.channels.produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/produce.html
[kotlinx.coroutines.channels.ReceiveChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/index.html
[kotlinx.coroutines.channels.ProducerScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-producer-scope/index.html
@@ -151,14 +146,9 @@ Low-level primitives for finer-grained control of coroutines.
[kotlinx.coroutines.channels.ReceiveChannel.poll]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/poll.html
[kotlinx.coroutines.channels.receiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/receive-or-null.html
[kotlinx.coroutines.channels.onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/on-receive-or-null.html
-
<!--- INDEX kotlinx.coroutines.selects -->
-
[kotlinx.coroutines.selects.select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html
[kotlinx.coroutines.selects.SelectBuilder.onTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/-select-builder/on-timeout.html
-
<!--- INDEX kotlinx.coroutines.test -->
-
[kotlinx.coroutines.test.TestCoroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.test/-test-coroutine-context/index.html
-
<!--- END -->
diff --git a/kotlinx-coroutines-core/common/src/AbstractCoroutine.kt b/kotlinx-coroutines-core/common/src/AbstractCoroutine.kt
index af392b63..742c9670 100644
--- a/kotlinx-coroutines-core/common/src/AbstractCoroutine.kt
+++ b/kotlinx-coroutines-core/common/src/AbstractCoroutine.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION_ERROR")
diff --git a/kotlinx-coroutines-core/common/src/Annotations.kt b/kotlinx-coroutines-core/common/src/Annotations.kt
index 70adad9b..5475c6b1 100644
--- a/kotlinx-coroutines-core/common/src/Annotations.kt
+++ b/kotlinx-coroutines-core/common/src/Annotations.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Await.kt b/kotlinx-coroutines-core/common/src/Await.kt
index e06ed330..71893490 100644
--- a/kotlinx-coroutines-core/common/src/Await.kt
+++ b/kotlinx-coroutines-core/common/src/Await.kt
@@ -1,10 +1,11 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
import kotlinx.atomicfu.*
+import kotlinx.coroutines.channels.*
import kotlin.coroutines.*
/**
@@ -74,7 +75,7 @@ private class AwaitAll<T>(private val deferreds: Array<out Deferred<T>>) {
val nodes = Array(deferreds.size) { i ->
val deferred = deferreds[i]
deferred.start() // To properly await lazily started deferreds
- AwaitAllNode(cont).apply {
+ AwaitAllNode(cont, deferred).apply {
handle = deferred.invokeOnCompletion(asHandler)
}
}
@@ -100,7 +101,7 @@ private class AwaitAll<T>(private val deferreds: Array<out Deferred<T>>) {
override fun toString(): String = "DisposeHandlersOnCancel[$nodes]"
}
- private inner class AwaitAllNode(private val continuation: CancellableContinuation<List<T>>) : JobNode() {
+ private inner class AwaitAllNode(private val continuation: CancellableContinuation<List<T>>, job: Job) : JobNode<Job>(job) {
lateinit var handle: DisposableHandle
private val _disposer = atomic<DisposeHandlersOnCancel?>(null)
diff --git a/kotlinx-coroutines-core/common/src/Builders.common.kt b/kotlinx-coroutines-core/common/src/Builders.common.kt
index 93b3ee48..b7deaccb 100644
--- a/kotlinx-coroutines-core/common/src/Builders.common.kt
+++ b/kotlinx-coroutines-core/common/src/Builders.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@@ -133,10 +133,6 @@ private class LazyDeferredCoroutine<T>(
* which means that if the original [coroutineContext], in which `withContext` was invoked,
* is cancelled by the time its dispatcher starts to execute the code,
* it discards the result of `withContext` and throws [CancellationException].
- *
- * The cancellation behaviour described above is enabled if and only if the dispatcher is being changed.
- * For example, when using `withContext(NonCancellable) { ... }` there is no change in dispatcher and
- * this call will not be cancelled neither on entry to the block inside `withContext` nor on exit from it.
*/
public suspend fun <T> withContext(
context: CoroutineContext,
@@ -207,17 +203,25 @@ private class LazyStandaloneCoroutine(
}
// Used by withContext when context changes, but dispatcher stays the same
-internal expect class UndispatchedCoroutine<in T>(
+private class UndispatchedCoroutine<in T>(
context: CoroutineContext,
uCont: Continuation<T>
-) : ScopeCoroutine<T>
+) : ScopeCoroutine<T>(context, uCont) {
+ override fun afterResume(state: Any?) {
+ // resume undispatched -- update context by stay on the same dispatcher
+ val result = recoverResult(state, uCont)
+ withCoroutineContext(uCont.context, null) {
+ uCont.resumeWith(result)
+ }
+ }
+}
private const val UNDECIDED = 0
private const val SUSPENDED = 1
private const val RESUMED = 2
// Used by withContext when context dispatcher changes
-internal class DispatchedCoroutine<in T>(
+private class DispatchedCoroutine<in T>(
context: CoroutineContext,
uCont: Continuation<T>
) : ScopeCoroutine<T>(context, uCont) {
diff --git a/kotlinx-coroutines-core/common/src/CancellableContinuation.kt b/kotlinx-coroutines-core/common/src/CancellableContinuation.kt
index 8f589912..7d9315af 100644
--- a/kotlinx-coroutines-core/common/src/CancellableContinuation.kt
+++ b/kotlinx-coroutines-core/common/src/CancellableContinuation.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt b/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt
index 1a8f3566..cdb1b788 100644
--- a/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt
+++ b/kotlinx-coroutines-core/common/src/CancellableContinuationImpl.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -85,13 +85,6 @@ internal open class CancellableContinuationImpl<in T>(
public override val isCancelled: Boolean get() = state is CancelledContinuation
- // We cannot invoke `state.toString()` since it may cause a circular dependency
- private val stateDebugRepresentation get() = when(state) {
- is NotCompleted -> "Active"
- is CancelledContinuation -> "Cancelled"
- else -> "Completed"
- }
-
public override fun initCancellability() {
setupCancellation()
}
@@ -129,7 +122,7 @@ internal open class CancellableContinuationImpl<in T>(
val parent = delegate.context[Job] ?: return // fast path 3 -- don't do anything without parent
val handle = parent.invokeOnCompletion(
onCancelling = true,
- handler = ChildContinuation(this).asHandler
+ handler = ChildContinuation(parent, this).asHandler
)
parentHandle = handle
// now check our state _after_ registering (could have completed while we were registering)
@@ -510,7 +503,7 @@ internal open class CancellableContinuationImpl<in T>(
// For nicer debugging
public override fun toString(): String =
- "${nameString()}(${delegate.toDebugString()}){$stateDebugRepresentation}@$hexAddress"
+ "${nameString()}(${delegate.toDebugString()}){$state}@$hexAddress"
protected open fun nameString(): String =
"CancellableContinuation"
diff --git a/kotlinx-coroutines-core/common/src/CompletableDeferred.kt b/kotlinx-coroutines-core/common/src/CompletableDeferred.kt
index c8073796..2f008472 100644
--- a/kotlinx-coroutines-core/common/src/CompletableDeferred.kt
+++ b/kotlinx-coroutines-core/common/src/CompletableDeferred.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION_ERROR")
diff --git a/kotlinx-coroutines-core/common/src/CompletableJob.kt b/kotlinx-coroutines-core/common/src/CompletableJob.kt
index f986d787..74a92e36 100644
--- a/kotlinx-coroutines-core/common/src/CompletableJob.kt
+++ b/kotlinx-coroutines-core/common/src/CompletableJob.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CompletionHandler.common.kt b/kotlinx-coroutines-core/common/src/CompletionHandler.common.kt
index e712ff1f..bf690008 100644
--- a/kotlinx-coroutines-core/common/src/CompletionHandler.common.kt
+++ b/kotlinx-coroutines-core/common/src/CompletionHandler.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CompletionState.kt b/kotlinx-coroutines-core/common/src/CompletionState.kt
index b9042874..f09aa3cc 100644
--- a/kotlinx-coroutines-core/common/src/CompletionState.kt
+++ b/kotlinx-coroutines-core/common/src/CompletionState.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CoroutineContext.common.kt b/kotlinx-coroutines-core/common/src/CoroutineContext.common.kt
index 68b4b1a3..51374603 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineContext.common.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineContext.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -19,6 +19,5 @@ internal expect val DefaultDelay: Delay
// countOrElement -- pre-cached value for ThreadContext.kt
internal expect inline fun <T> withCoroutineContext(context: CoroutineContext, countOrElement: Any?, block: () -> T): T
-internal expect inline fun <T> withContinuationContext(continuation: Continuation<*>, countOrElement: Any?, block: () -> T): T
internal expect fun Continuation<*>.toDebugString(): String
internal expect val CoroutineContext.coroutineName: String?
diff --git a/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt b/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt
index b2b88798..ab1e814b 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CoroutineExceptionHandler.kt b/kotlinx-coroutines-core/common/src/CoroutineExceptionHandler.kt
index 49923a92..b49a6faa 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineExceptionHandler.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineExceptionHandler.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CoroutineName.kt b/kotlinx-coroutines-core/common/src/CoroutineName.kt
index dc3f1c0c..7f09a589 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineName.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineName.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/CoroutineScope.kt b/kotlinx-coroutines-core/common/src/CoroutineScope.kt
index e7c243a4..0dde6c93 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineScope.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineScope.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:OptIn(ExperimentalContracts::class)
diff --git a/kotlinx-coroutines-core/common/src/CoroutineStart.kt b/kotlinx-coroutines-core/common/src/CoroutineStart.kt
index 6059829c..d5791c79 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineStart.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineStart.kt
@@ -1,6 +1,7 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
+@file:Suppress("NO_EXPLICIT_VISIBILITY_IN_API_MODE")
package kotlinx.coroutines
import kotlinx.coroutines.CoroutineStart.*
@@ -58,8 +59,8 @@ public enum class CoroutineStart {
ATOMIC,
/**
- * Immediately executes the coroutine until its first suspension point _in the current thread_ similarly to
- * the coroutine being started using [Dispatchers.Unconfined]. However, when the coroutine is resumed from suspension
+ * Immediately executes the coroutine until its first suspension point _in the current thread_ as if the
+ * coroutine was started using [Dispatchers.Unconfined]. However, when the coroutine is resumed from suspension
* it is dispatched according to the [CoroutineDispatcher] in its context.
*
* This is similar to [ATOMIC] in the sense that coroutine starts executing even if it was already cancelled,
@@ -68,11 +69,9 @@ public enum class CoroutineStart {
* Cancellability of coroutine at suspension points depends on the particular implementation details of
* suspending functions as in [DEFAULT].
*
- * ### Unconfined event loop
- *
- * Unlike [Dispatchers.Unconfined] and [MainCoroutineDispatcher.immediate], nested undispatched coroutines do not form
- * an event loop that otherwise prevents potential stack overflow in case of unlimited nesting.
+ * **Note: This is an experimental api.** Execution semantics of coroutines may change in the future when this mode is used.
*/
+ @ExperimentalCoroutinesApi // Since 1.0.0, no ETA on stability
UNDISPATCHED;
/**
diff --git a/kotlinx-coroutines-core/common/src/Debug.common.kt b/kotlinx-coroutines-core/common/src/Debug.common.kt
index 1381ecd8..949b05c6 100644
--- a/kotlinx-coroutines-core/common/src/Debug.common.kt
+++ b/kotlinx-coroutines-core/common/src/Debug.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -35,7 +35,6 @@ public interface CopyableThrowable<T> where T : Throwable, T : CopyableThrowable
* For better debuggability, it is recommended to use original exception as [cause][Throwable.cause] of the resulting one.
* Stacktrace of copied exception will be overwritten by stacktrace recovery machinery by [Throwable.setStackTrace] call.
* An exception can opt-out of copying by returning `null` from this function.
- * Suppressed exceptions of the original exception should not be copied in order to avoid circular exceptions.
*/
public fun createCopy(): T?
}
diff --git a/kotlinx-coroutines-core/common/src/Deferred.kt b/kotlinx-coroutines-core/common/src/Deferred.kt
index 595700e2..ff996756 100644
--- a/kotlinx-coroutines-core/common/src/Deferred.kt
+++ b/kotlinx-coroutines-core/common/src/Deferred.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Delay.kt b/kotlinx-coroutines-core/common/src/Delay.kt
index 53dadf97..aae623d5 100644
--- a/kotlinx-coroutines-core/common/src/Delay.kt
+++ b/kotlinx-coroutines-core/common/src/Delay.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Dispatchers.common.kt b/kotlinx-coroutines-core/common/src/Dispatchers.common.kt
index 8681b182..dba57abc 100644
--- a/kotlinx-coroutines-core/common/src/Dispatchers.common.kt
+++ b/kotlinx-coroutines-core/common/src/Dispatchers.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/EventLoop.common.kt b/kotlinx-coroutines-core/common/src/EventLoop.common.kt
index e6a57c92..69ea9fe3 100644
--- a/kotlinx-coroutines-core/common/src/EventLoop.common.kt
+++ b/kotlinx-coroutines-core/common/src/EventLoop.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Exceptions.common.kt b/kotlinx-coroutines-core/common/src/Exceptions.common.kt
index 6d5442df..64f8911e 100644
--- a/kotlinx-coroutines-core/common/src/Exceptions.common.kt
+++ b/kotlinx-coroutines-core/common/src/Exceptions.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Job.kt b/kotlinx-coroutines-core/common/src/Job.kt
index 31e2ef22..2e05635a 100644
--- a/kotlinx-coroutines-core/common/src/Job.kt
+++ b/kotlinx-coroutines-core/common/src/Job.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@@ -490,7 +490,7 @@ public interface ChildHandle : DisposableHandle {
* ```
*/
internal fun Job.disposeOnCompletion(handle: DisposableHandle): DisposableHandle =
- invokeOnCompletion(handler = DisposeOnCompletion(handle).asHandler)
+ invokeOnCompletion(handler = DisposeOnCompletion(this, handle).asHandler)
/**
* Cancels the job and suspends the invoking coroutine until the cancelled job is complete.
diff --git a/kotlinx-coroutines-core/common/src/JobSupport.kt b/kotlinx-coroutines-core/common/src/JobSupport.kt
index 5b516ae2..020d00a3 100644
--- a/kotlinx-coroutines-core/common/src/JobSupport.kt
+++ b/kotlinx-coroutines-core/common/src/JobSupport.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION_ERROR")
@@ -287,7 +287,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
// fast-path method to finalize normally completed coroutines without children
// returns true if complete, and afterCompletion(update) shall be called
private fun tryFinalizeSimpleState(state: Incomplete, update: Any?): Boolean {
- assert { state is Empty || state is JobNode } // only simple state without lists where children can concurrently add
+ assert { state is Empty || state is JobNode<*> } // only simple state without lists where children can concurrently add
assert { update !is CompletedExceptionally } // only for normal completion
if (!_state.compareAndSet(state, update.boxIncomplete())) return false
onCancelling(null) // simple state is not a failure
@@ -313,7 +313,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
* 2) Invoke completion handlers: .join(), callbacks etc.
* It's important to invoke them only AFTER exception handling and everything else, see #208
*/
- if (state is JobNode) { // SINGLE/SINGLE+ state -- one completion handler (common case)
+ if (state is JobNode<*>) { // SINGLE/SINGLE+ state -- one completion handler (common case)
try {
state.invoke(cause)
} catch (ex: Throwable) {
@@ -327,7 +327,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
private fun notifyCancelling(list: NodeList, cause: Throwable) {
// first cancel our own children
onCancelling(cause)
- notifyHandlers<JobCancellingNode>(list, cause)
+ notifyHandlers<JobCancellingNode<*>>(list, cause)
// then cancel parent
cancelParent(cause) // tentative cancellation -- does not matter if there is no parent
}
@@ -359,9 +359,9 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
}
private fun NodeList.notifyCompletion(cause: Throwable?) =
- notifyHandlers<JobNode>(this, cause)
+ notifyHandlers<JobNode<*>>(this, cause)
- private inline fun <reified T: JobNode> notifyHandlers(list: NodeList, cause: Throwable?) {
+ private inline fun <reified T: JobNode<*>> notifyHandlers(list: NodeList, cause: Throwable?) {
var exception: Throwable? = null
list.forEach<T> { node ->
try {
@@ -453,14 +453,13 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
invokeImmediately: Boolean,
handler: CompletionHandler
): DisposableHandle {
- // Create node upfront -- for common cases it just initializes JobNode.job field,
- // for user-defined handlers it allocates a JobNode object that we might not need, but this is Ok.
- val node: JobNode = makeNode(handler, onCancelling)
+ var nodeCache: JobNode<*>? = null
loopOnState { state ->
when (state) {
is Empty -> { // EMPTY_X state -- no completion handlers
if (state.isActive) {
// try move to SINGLE state
+ val node = nodeCache ?: makeNode(handler, onCancelling).also { nodeCache = it }
if (_state.compareAndSet(state, node)) return node
} else
promoteEmptyToNodeList(state) // that way we can add listener for non-active coroutine
@@ -468,7 +467,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
is Incomplete -> {
val list = state.list
if (list == null) { // SINGLE/SINGLE+
- promoteSingleToNodeList(state as JobNode)
+ promoteSingleToNodeList(state as JobNode<*>)
} else {
var rootCause: Throwable? = null
var handle: DisposableHandle = NonDisposableHandle
@@ -480,6 +479,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
// or we are adding a child to a coroutine that is not completing yet
if (rootCause == null || handler.isHandlerOf<ChildHandleNode>() && !state.isCompleting) {
// Note: add node the list while holding lock on state (make sure it cannot change)
+ val node = nodeCache ?: makeNode(handler, onCancelling).also { nodeCache = it }
if (!addLastAtomic(state, list, node)) return@loopOnState // retry
// just return node if we don't have to invoke handler (not cancelling yet)
if (rootCause == null) return node
@@ -493,6 +493,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
if (invokeImmediately) handler.invokeIt(rootCause)
return handle
} else {
+ val node = nodeCache ?: makeNode(handler, onCancelling).also { nodeCache = it }
if (addLastAtomic(state, list, node)) return node
}
}
@@ -507,20 +508,16 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
}
}
- private fun makeNode(handler: CompletionHandler, onCancelling: Boolean): JobNode {
- val node = if (onCancelling) {
- (handler as? JobCancellingNode)
- ?: InvokeOnCancelling(handler)
- } else {
- (handler as? JobNode)
- ?.also { assert { it !is JobCancellingNode } }
- ?: InvokeOnCompletion(handler)
- }
- node.job = this
- return node
+ private fun makeNode(handler: CompletionHandler, onCancelling: Boolean): JobNode<*> {
+ return if (onCancelling)
+ (handler as? JobCancellingNode<*>)?.also { assert { it.job === this } }
+ ?: InvokeOnCancelling(this, handler)
+ else
+ (handler as? JobNode<*>)?.also { assert { it.job === this && it !is JobCancellingNode } }
+ ?: InvokeOnCompletion(this, handler)
}
- private fun addLastAtomic(expect: Any, list: NodeList, node: JobNode) =
+ private fun addLastAtomic(expect: Any, list: NodeList, node: JobNode<*>) =
list.addLastIf(node) { this.state === expect }
private fun promoteEmptyToNodeList(state: Empty) {
@@ -530,7 +527,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
_state.compareAndSet(state, update)
}
- private fun promoteSingleToNodeList(state: JobNode) {
+ private fun promoteSingleToNodeList(state: JobNode<*>) {
// try to promote it to list (SINGLE+ state)
state.addOneIfEmpty(NodeList())
// it must be in SINGLE+ state or state has changed (node could have need removed from state)
@@ -556,7 +553,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
private suspend fun joinSuspend() = suspendCancellableCoroutine<Unit> { cont ->
// We have to invoke join() handler only on cancellation, on completion we will be resumed regularly without handlers
- cont.disposeOnCancellation(invokeOnCompletion(handler = ResumeOnCompletion(cont).asHandler))
+ cont.disposeOnCancellation(invokeOnCompletion(handler = ResumeOnCompletion(this, cont).asHandler))
}
public final override val onJoin: SelectClause0
@@ -576,7 +573,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
}
if (startInternal(state) == 0) {
// slow-path -- register waiter for completion
- select.disposeOnSelect(invokeOnCompletion(handler = SelectJoinOnCompletion(select, block).asHandler))
+ select.disposeOnSelect(invokeOnCompletion(handler = SelectJoinOnCompletion(this, select, block).asHandler))
return
}
}
@@ -585,11 +582,11 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
/**
* @suppress **This is unstable API and it is subject to change.**
*/
- internal fun removeNode(node: JobNode) {
+ internal fun removeNode(node: JobNode<*>) {
// remove logic depends on the state of the job
loopOnState { state ->
when (state) {
- is JobNode -> { // SINGE/SINGLE+ state -- one completion handler
+ is JobNode<*> -> { // SINGE/SINGLE+ state -- one completion handler
if (state !== node) return // a different job node --> we were already removed
// try remove and revert back to empty state
if (_state.compareAndSet(state, EMPTY_ACTIVE)) return
@@ -773,7 +770,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
private fun getOrPromoteCancellingList(state: Incomplete): NodeList? = state.list ?:
when (state) {
is Empty -> NodeList() // we can allocate new empty list that'll get integrated into Cancelling state
- is JobNode -> {
+ is JobNode<*> -> {
// SINGLE/SINGLE+ must be promoted to NodeList first, because otherwise we cannot
// correctly capture a reference to it
promoteSingleToNodeList(state)
@@ -852,7 +849,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
* Otherwise, there can be a race between (completed state -> handled exception and newly attached child/join)
* which may miss unhandled exception.
*/
- if ((state is Empty || state is JobNode) && state !is ChildHandleNode && proposedUpdate !is CompletedExceptionally) {
+ if ((state is Empty || state is JobNode<*>) && state !is ChildHandleNode && proposedUpdate !is CompletedExceptionally) {
if (tryFinalizeSimpleState(state, proposedUpdate)) {
// Completed successfully on fast path -- return updated state
return proposedUpdate
@@ -967,7 +964,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
* If child is attached when the job is already being cancelled, such child will receive immediate notification on
* cancellation, but parent *will* wait for that child before completion and will handle its exception.
*/
- return invokeOnCompletion(onCancelling = true, handler = ChildHandleNode(child).asHandler) as ChildHandle
+ return invokeOnCompletion(onCancelling = true, handler = ChildHandleNode(this, child).asHandler) as ChildHandle
}
/**
@@ -1150,10 +1147,12 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
private val state: Finishing,
private val child: ChildHandleNode,
private val proposedUpdate: Any?
- ) : JobNode() {
+ ) : JobNode<Job>(child.childJob) {
override fun invoke(cause: Throwable?) {
parent.continueCompleting(state, child, proposedUpdate)
}
+ override fun toString(): String =
+ "ChildCompletion[$child, $proposedUpdate]"
}
private class AwaitContinuation<T>(
@@ -1228,7 +1227,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
* thrown and not a JobCancellationException.
*/
val cont = AwaitContinuation(uCont.intercepted(), this)
- cont.disposeOnCancellation(invokeOnCompletion(ResumeAwaitOnCompletion(cont).asHandler))
+ cont.disposeOnCancellation(invokeOnCompletion(ResumeAwaitOnCompletion(this, cont).asHandler))
cont.getResult()
}
@@ -1255,7 +1254,7 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
}
if (startInternal(state) == 0) {
// slow-path -- register waiter for completion
- select.disposeOnSelect(invokeOnCompletion(handler = SelectAwaitOnCompletion(select, block).asHandler))
+ select.disposeOnSelect(invokeOnCompletion(handler = SelectAwaitOnCompletion(this, select, block).asHandler))
return
}
}
@@ -1345,15 +1344,12 @@ internal interface Incomplete {
val list: NodeList? // is null only for Empty and JobNode incomplete state objects
}
-internal abstract class JobNode : CompletionHandlerBase(), DisposableHandle, Incomplete {
- /**
- * Initialized by [JobSupport.makeNode].
- */
- lateinit var job: JobSupport
+internal abstract class JobNode<out J : Job>(
+ @JvmField val job: J
+) : CompletionHandlerBase(), DisposableHandle, Incomplete {
override val isActive: Boolean get() = true
override val list: NodeList? get() = null
- override fun dispose() = job.removeNode(this)
- override fun toString() = "$classSimpleName@$hexAddress[job@${job.hexAddress}]"
+ override fun dispose() = (job as JobSupport).removeNode(this)
}
internal class NodeList : LockFreeLinkedListHead(), Incomplete {
@@ -1365,7 +1361,7 @@ internal class NodeList : LockFreeLinkedListHead(), Incomplete {
append(state)
append("}[")
var first = true
- this@NodeList.forEach<JobNode> { node ->
+ this@NodeList.forEach<JobNode<*>> { node ->
if (first) first = false else append(", ")
append(node)
}
@@ -1384,20 +1380,25 @@ internal class InactiveNodeList(
}
private class InvokeOnCompletion(
+ job: Job,
private val handler: CompletionHandler
-) : JobNode() {
+) : JobNode<Job>(job) {
override fun invoke(cause: Throwable?) = handler.invoke(cause)
+ override fun toString() = "InvokeOnCompletion[$classSimpleName@$hexAddress]"
}
private class ResumeOnCompletion(
+ job: Job,
private val continuation: Continuation<Unit>
-) : JobNode() {
+) : JobNode<Job>(job) {
override fun invoke(cause: Throwable?) = continuation.resume(Unit)
+ override fun toString() = "ResumeOnCompletion[$continuation]"
}
private class ResumeAwaitOnCompletion<T>(
+ job: JobSupport,
private val continuation: CancellableContinuationImpl<T>
-) : JobNode() {
+) : JobNode<JobSupport>(job) {
override fun invoke(cause: Throwable?) {
val state = job.state
assert { state !is Incomplete }
@@ -1410,32 +1411,39 @@ private class ResumeAwaitOnCompletion<T>(
continuation.resume(state.unboxState() as T)
}
}
+ override fun toString() = "ResumeAwaitOnCompletion[$continuation]"
}
internal class DisposeOnCompletion(
+ job: Job,
private val handle: DisposableHandle
-) : JobNode() {
+) : JobNode<Job>(job) {
override fun invoke(cause: Throwable?) = handle.dispose()
+ override fun toString(): String = "DisposeOnCompletion[$handle]"
}
private class SelectJoinOnCompletion<R>(
+ job: JobSupport,
private val select: SelectInstance<R>,
private val block: suspend () -> R
-) : JobNode() {
+) : JobNode<JobSupport>(job) {
override fun invoke(cause: Throwable?) {
if (select.trySelect())
block.startCoroutineCancellable(select.completion)
}
+ override fun toString(): String = "SelectJoinOnCompletion[$select]"
}
private class SelectAwaitOnCompletion<T, R>(
+ job: JobSupport,
private val select: SelectInstance<R>,
private val block: suspend (T) -> R
-) : JobNode() {
+) : JobNode<JobSupport>(job) {
override fun invoke(cause: Throwable?) {
if (select.trySelect())
job.selectAwaitCompletion(select, block)
}
+ override fun toString(): String = "SelectAwaitOnCompletion[$select]"
}
// -------- invokeOnCancellation nodes
@@ -1444,31 +1452,38 @@ private class SelectAwaitOnCompletion<T, R>(
* Marker for node that shall be invoked on in _cancelling_ state.
* **Note: may be invoked multiple times.**
*/
-internal abstract class JobCancellingNode : JobNode()
+internal abstract class JobCancellingNode<out J : Job>(job: J) : JobNode<J>(job)
private class InvokeOnCancelling(
+ job: Job,
private val handler: CompletionHandler
-) : JobCancellingNode() {
+) : JobCancellingNode<Job>(job) {
// delegate handler shall be invoked at most once, so here is an additional flag
private val _invoked = atomic(0) // todo: replace with atomic boolean after migration to recent atomicFu
override fun invoke(cause: Throwable?) {
if (_invoked.compareAndSet(0, 1)) handler.invoke(cause)
}
+ override fun toString() = "InvokeOnCancelling[$classSimpleName@$hexAddress]"
}
internal class ChildHandleNode(
+ parent: JobSupport,
@JvmField val childJob: ChildJob
-) : JobCancellingNode(), ChildHandle {
+) : JobCancellingNode<JobSupport>(parent), ChildHandle {
override fun invoke(cause: Throwable?) = childJob.parentCancelled(job)
override fun childCancelled(cause: Throwable): Boolean = job.childCancelled(cause)
+ override fun toString(): String = "ChildHandle[$childJob]"
}
// Same as ChildHandleNode, but for cancellable continuation
internal class ChildContinuation(
+ parent: Job,
@JvmField val child: CancellableContinuationImpl<*>
-) : JobCancellingNode() {
+) : JobCancellingNode<Job>(parent) {
override fun invoke(cause: Throwable?) {
child.parentCancelled(child.getContinuationCancellationCause(job))
}
+ override fun toString(): String =
+ "ChildContinuation[$child]"
}
diff --git a/kotlinx-coroutines-core/common/src/MainCoroutineDispatcher.kt b/kotlinx-coroutines-core/common/src/MainCoroutineDispatcher.kt
index 602da6e0..daba38f0 100644
--- a/kotlinx-coroutines-core/common/src/MainCoroutineDispatcher.kt
+++ b/kotlinx-coroutines-core/common/src/MainCoroutineDispatcher.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/NonCancellable.kt b/kotlinx-coroutines-core/common/src/NonCancellable.kt
index a9c68f09..45803cf9 100644
--- a/kotlinx-coroutines-core/common/src/NonCancellable.kt
+++ b/kotlinx-coroutines-core/common/src/NonCancellable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION_ERROR")
diff --git a/kotlinx-coroutines-core/common/src/Runnable.common.kt b/kotlinx-coroutines-core/common/src/Runnable.common.kt
index 5a7f6678..692c700b 100644
--- a/kotlinx-coroutines-core/common/src/Runnable.common.kt
+++ b/kotlinx-coroutines-core/common/src/Runnable.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/SchedulerTask.common.kt b/kotlinx-coroutines-core/common/src/SchedulerTask.common.kt
index 45e2542b..dbdf45ea 100644
--- a/kotlinx-coroutines-core/common/src/SchedulerTask.common.kt
+++ b/kotlinx-coroutines-core/common/src/SchedulerTask.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Supervisor.kt b/kotlinx-coroutines-core/common/src/Supervisor.kt
index 01a8e705..542e4fef 100644
--- a/kotlinx-coroutines-core/common/src/Supervisor.kt
+++ b/kotlinx-coroutines-core/common/src/Supervisor.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:OptIn(ExperimentalContracts::class)
@file:Suppress("DEPRECATION_ERROR")
diff --git a/kotlinx-coroutines-core/common/src/Timeout.kt b/kotlinx-coroutines-core/common/src/Timeout.kt
index 264a2b9d..4bfff118 100644
--- a/kotlinx-coroutines-core/common/src/Timeout.kt
+++ b/kotlinx-coroutines-core/common/src/Timeout.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:OptIn(ExperimentalContracts::class)
diff --git a/kotlinx-coroutines-core/common/src/Unconfined.kt b/kotlinx-coroutines-core/common/src/Unconfined.kt
index 4f486458..a0997a51 100644
--- a/kotlinx-coroutines-core/common/src/Unconfined.kt
+++ b/kotlinx-coroutines-core/common/src/Unconfined.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/common/src/Yield.kt b/kotlinx-coroutines-core/common/src/Yield.kt
index 975a4893..0d8bd3bc 100644
--- a/kotlinx-coroutines-core/common/src/Yield.kt
+++ b/kotlinx-coroutines-core/common/src/Yield.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -9,8 +9,7 @@ import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
/**
- * Yields the thread (or thread pool) of the current coroutine dispatcher
- * to other coroutines on the same dispatcher to run if possible.
+ * Yields the thread (or thread pool) of the current coroutine dispatcher to other coroutines to run if possible.
*
* This suspending function is cancellable.
* If the [Job] of the current coroutine is cancelled or completed when this suspending function is invoked or while
diff --git a/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt b/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
index 9721583e..8edd2b31 100644
--- a/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
@@ -477,14 +477,7 @@ internal abstract class AbstractSendChannel<E>(
override val pollResult: Any? get() = element
override fun tryResumeSend(otherOp: PrepareOp?): Symbol? = RESUME_TOKEN.also { otherOp?.finishPrepare() }
override fun completeResumeSend() {}
-
- /**
- * This method should be never called, see special logic in [LinkedListChannel.onCancelIdempotentList].
- */
- override fun resumeSendClosed(closed: Closed<*>) {
- assert { false }
- }
-
+ override fun resumeSendClosed(closed: Closed<*>) {}
override fun toString(): String = "SendBuffered@$hexAddress($element)"
}
}
@@ -642,13 +635,6 @@ internal abstract class AbstractChannel<E>(
cancelInternal(cause)
final override fun cancel(cause: CancellationException?) {
- /*
- * Do not create an exception if channel is already cancelled.
- * Channel is closed for receive when either it is cancelled (then we are free to bail out)
- * or was closed and elements were received.
- * Then `onCancelIdempotent` does nothing for all implementations.
- */
- if (isClosedForReceive) return
cancelInternal(cause ?: CancellationException("$classSimpleName was cancelled"))
}
@@ -682,13 +668,6 @@ internal abstract class AbstractChannel<E>(
// Add to the list only **after** successful removal
list += previous as Send
}
- onCancelIdempotentList(list, closed)
- }
-
- /**
- * This method is overridden by [LinkedListChannel] to handle cancellation of [SendBuffered] elements from the list.
- */
- protected open fun onCancelIdempotentList(list: InlineList<Send>, closed: Closed<*>) {
list.forEachReversed { it.resumeSendClosed(closed) }
}
diff --git a/kotlinx-coroutines-core/common/src/channels/ArrayBroadcastChannel.kt b/kotlinx-coroutines-core/common/src/channels/ArrayBroadcastChannel.kt
index 600eb6a9..91b5473c 100644
--- a/kotlinx-coroutines-core/common/src/channels/ArrayBroadcastChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ArrayBroadcastChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
diff --git a/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt b/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt
index 4569ec72..80cb8aa0 100644
--- a/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ArrayChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
@@ -298,7 +298,7 @@ internal open class ArrayChannel<E>(
}
// then clean all queued senders
super.onCancelIdempotent(wasClosed)
- undeliveredElementException?.let { throw it } // throw UndeliveredElementException at the end if there was one
+ undeliveredElementException?.let { throw it } // throw cancel exception at the end if there was one
}
// ------ debug ------
diff --git a/kotlinx-coroutines-core/common/src/channels/Broadcast.kt b/kotlinx-coroutines-core/common/src/channels/Broadcast.kt
index 07e75976..0193ed06 100644
--- a/kotlinx-coroutines-core/common/src/channels/Broadcast.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Broadcast.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
diff --git a/kotlinx-coroutines-core/common/src/channels/BroadcastChannel.kt b/kotlinx-coroutines-core/common/src/channels/BroadcastChannel.kt
index 6cd79373..d356566f 100644
--- a/kotlinx-coroutines-core/common/src/channels/BroadcastChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/BroadcastChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("FunctionName")
diff --git a/kotlinx-coroutines-core/common/src/channels/BufferOverflow.kt b/kotlinx-coroutines-core/common/src/channels/BufferOverflow.kt
index 48b89ce6..a89c633f 100644
--- a/kotlinx-coroutines-core/common/src/channels/BufferOverflow.kt
+++ b/kotlinx-coroutines-core/common/src/channels/BufferOverflow.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
diff --git a/kotlinx-coroutines-core/common/src/channels/Channel.kt b/kotlinx-coroutines-core/common/src/channels/Channel.kt
index b8b81aac..72c08e1a 100644
--- a/kotlinx-coroutines-core/common/src/channels/Channel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Channel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("FunctionName")
@@ -90,7 +90,7 @@ public interface SendChannel<in E> {
/**
* Closes this channel.
* This is an idempotent operation &mdash; subsequent invocations of this function have no effect and return `false`.
- * Conceptually, it sends a special "close token" over this channel.
+ * Conceptually, its sends a special "close token" over this channel.
*
* Immediately after invocation of this function,
* [isClosedForSend] starts returning `true`. However, [isClosedForReceive][ReceiveChannel.isClosedForReceive]
@@ -498,7 +498,7 @@ public interface ChannelIterator<out E> {
* * When `capacity` is [Channel.CONFLATED] &mdash; it creates a _conflated_ channel
* This channel buffers at most one element and conflates all subsequent `send` and `offer` invocations,
* so that the receiver always gets the last element sent.
- * Back-to-back sent elements are conflated &mdash; only the last sent element is received,
+ * Back-to-send sent elements are conflated &mdash; only the last sent element is received,
* while previously sent elements **are lost**.
* [Sending][send] to this channel never suspends, and [offer] always returns `true`.
*
diff --git a/kotlinx-coroutines-core/common/src/channels/ChannelCoroutine.kt b/kotlinx-coroutines-core/common/src/channels/ChannelCoroutine.kt
index b2b257de..a75d4661 100644
--- a/kotlinx-coroutines-core/common/src/channels/ChannelCoroutine.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ChannelCoroutine.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
@@ -26,7 +26,6 @@ internal open class ChannelCoroutine<E>(
}
final override fun cancel(cause: CancellationException?) {
- if (isCancelled) return // Do not create an exception if the coroutine (-> the channel) is already cancelled
cancelInternal(cause ?: defaultCancellationException())
}
diff --git a/kotlinx-coroutines-core/common/src/channels/Channels.common.kt b/kotlinx-coroutines-core/common/src/channels/Channels.common.kt
index e3567e31..398d5ca4 100644
--- a/kotlinx-coroutines-core/common/src/channels/Channels.common.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Channels.common.kt
@@ -1,16 +1,14 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@file:JvmName("ChannelsKt")
@file:Suppress("DEPRECATION_ERROR")
-@file:OptIn(ExperimentalContracts::class)
package kotlinx.coroutines.channels
import kotlinx.coroutines.*
import kotlinx.coroutines.selects.*
-import kotlin.contracts.*
import kotlin.coroutines.*
import kotlin.jvm.*
@@ -91,19 +89,6 @@ public suspend inline fun <E> BroadcastChannel<E>.consumeEach(action: (E) -> Uni
// -------- Operations on ReceiveChannel --------
/**
- * Returns a [List] containing all elements.
- *
- * The operation is _terminal_.
- * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel].
- */
-@OptIn(ExperimentalStdlibApi::class)
-public suspend fun <E> ReceiveChannel<E>.toList(): List<E> = buildList {
- consumeEach {
- add(it)
- }
-}
-
-/**
* Returns a [CompletionHandler] that invokes [cancel][ReceiveChannel.cancel] on the [ReceiveChannel]
* with the corresponding cause. See also [ReceiveChannel.consume].
*
@@ -166,9 +151,6 @@ public fun consumesAll(vararg channels: ReceiveChannel<*>): CompletionHandler =
* The operation is _terminal_.
*/
public inline fun <E, R> ReceiveChannel<E>.consume(block: ReceiveChannel<E>.() -> R): R {
- contract {
- callsInPlace(block, InvocationKind.EXACTLY_ONCE)
- }
var cause: Throwable? = null
try {
return block()
@@ -1208,6 +1190,15 @@ public suspend fun <E, C : MutableCollection<in E>> ReceiveChannel<E>.toCollecti
}
/**
+ * Returns a [List] containing all elements.
+ *
+ * The operation is _terminal_.
+ * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel].
+ */
+public suspend fun <E> ReceiveChannel<E>.toList(): List<E> =
+ this.toMutableList()
+
+/**
* Returns a [Map] filled with all elements of this channel.
*
* The operation is _terminal_.
diff --git a/kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt b/kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt
index f1d092e3..5986dae3 100644
--- a/kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ConflatedBroadcastChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
diff --git a/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt b/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt
index 0e686447..75e421c6 100644
--- a/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
@@ -120,7 +120,7 @@ internal open class ConflatedChannel<E>(onUndeliveredElement: OnUndeliveredEleme
undeliveredElementException = updateValueLocked(EMPTY)
}
super.onCancelIdempotent(wasClosed)
- undeliveredElementException?.let { throw it } // throw UndeliveredElementException at the end if there was one
+ undeliveredElementException?.let { throw it } // throw exception at the end if there was one
}
private fun updateValueLocked(element: Any?): UndeliveredElementException? {
diff --git a/kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt b/kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt
index 83175273..2f464213 100644
--- a/kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
@@ -58,19 +58,5 @@ internal open class LinkedListChannel<E>(onUndeliveredElement: OnUndeliveredElem
}
}
}
-
- override fun onCancelIdempotentList(list: InlineList<Send>, closed: Closed<*>) {
- var undeliveredElementException: UndeliveredElementException? = null
- list.forEachReversed {
- when (it) {
- is SendBuffered<*> -> {
- @Suppress("UNCHECKED_CAST")
- undeliveredElementException = onUndeliveredElement?.callUndeliveredElementCatchingException(it.element as E, undeliveredElementException)
- }
- else -> it.resumeSendClosed(closed)
- }
- }
- undeliveredElementException?.let { throw it } // throw UndeliveredElementException at the end if there was one
- }
}
diff --git a/kotlinx-coroutines-core/common/src/channels/Produce.kt b/kotlinx-coroutines-core/common/src/channels/Produce.kt
index 3c183587..10a15e2a 100644
--- a/kotlinx-coroutines-core/common/src/channels/Produce.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Produce.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
diff --git a/kotlinx-coroutines-core/common/src/channels/RendezvousChannel.kt b/kotlinx-coroutines-core/common/src/channels/RendezvousChannel.kt
index e8ade513..857a9793 100644
--- a/kotlinx-coroutines-core/common/src/channels/RendezvousChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/RendezvousChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
diff --git a/kotlinx-coroutines-core/common/src/flow/Builders.kt b/kotlinx-coroutines-core/common/src/flow/Builders.kt
index 10dd3aef..7d84cd21 100644
--- a/kotlinx-coroutines-core/common/src/flow/Builders.kt
+++ b/kotlinx-coroutines-core/common/src/flow/Builders.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/flow/Channels.kt b/kotlinx-coroutines-core/common/src/flow/Channels.kt
index e883c3b4..762cdcad 100644
--- a/kotlinx-coroutines-core/common/src/flow/Channels.kt
+++ b/kotlinx-coroutines-core/common/src/flow/Channels.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@@ -201,7 +201,7 @@ public fun <T> BroadcastChannel<T>.asFlow(): Flow<T> = flow {
*/
@Deprecated(
message = "Use shareIn operator and the resulting SharedFlow as a replacement for BroadcastChannel",
- replaceWith = ReplaceWith("this.shareIn(scope, SharingStarted.Lazily, 0)"),
+ replaceWith = ReplaceWith("shareIn(scope, 0, SharingStarted.Lazily)"),
level = DeprecationLevel.WARNING
)
public fun <T> Flow<T>.broadcastIn(
diff --git a/kotlinx-coroutines-core/common/src/flow/Flow.kt b/kotlinx-coroutines-core/common/src/flow/Flow.kt
index 0ccd343e..19a5b43f 100644
--- a/kotlinx-coroutines-core/common/src/flow/Flow.kt
+++ b/kotlinx-coroutines-core/common/src/flow/Flow.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow
@@ -101,7 +101,7 @@ import kotlin.coroutines.*
* From the implementation point of view, it means that all flow implementations should
* only emit from the same coroutine.
* This constraint is efficiently enforced by the default [flow] builder.
- * The [flow] builder should be used if the flow implementation does not start any coroutines.
+ * The [flow] builder should be used if flow implementation does not start any coroutines.
* Its implementation prevents most of the development mistakes:
*
* ```
diff --git a/kotlinx-coroutines-core/common/src/flow/FlowCollector.kt b/kotlinx-coroutines-core/common/src/flow/FlowCollector.kt
index d1c1565c..8c6208bf 100644
--- a/kotlinx-coroutines-core/common/src/flow/FlowCollector.kt
+++ b/kotlinx-coroutines-core/common/src/flow/FlowCollector.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow
diff --git a/kotlinx-coroutines-core/common/src/flow/Migration.kt b/kotlinx-coroutines-core/common/src/flow/Migration.kt
index 57749523..11969a48 100644
--- a/kotlinx-coroutines-core/common/src/flow/Migration.kt
+++ b/kotlinx-coroutines-core/common/src/flow/Migration.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/flow/SharedFlow.kt b/kotlinx-coroutines-core/common/src/flow/SharedFlow.kt
index 048cd8b3..feb27495 100644
--- a/kotlinx-coroutines-core/common/src/flow/SharedFlow.kt
+++ b/kotlinx-coroutines-core/common/src/flow/SharedFlow.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow
@@ -68,15 +68,6 @@ import kotlin.native.concurrent.*
* the `onBufferOverflow` parameter, which is equal to one of the entries of the [BufferOverflow] enum. When a strategy other
* than [SUSPENDED][BufferOverflow.SUSPEND] is configured, emissions to the shared flow never suspend.
*
- * ### Unbuffered shared flow
- *
- * A default implementation of a shared flow that is created with `MutableSharedFlow()` constructor function
- * without parameters has no replay cache nor additional buffer.
- * [emit][MutableSharedFlow.emit] call to such a shared flow suspends until all subscribers receive the emitted value
- * and returns immediately if there are no subscribers.
- * Thus, [tryEmit][MutableSharedFlow.tryEmit] call succeeds and returns `true` only if
- * there are no subscribers (in which case the emitted value is immediately lost).
- *
* ### SharedFlow vs BroadcastChannel
*
* Conceptually shared flow is similar to [BroadcastChannel][BroadcastChannel]
@@ -148,17 +139,6 @@ public interface SharedFlow<out T> : Flow<T> {
*/
public interface MutableSharedFlow<T> : SharedFlow<T>, FlowCollector<T> {
/**
- * Emits a [value] to this shared flow, suspending on buffer overflow if the shared flow was created
- * with the default [BufferOverflow.SUSPEND] strategy.
- *
- * See [tryEmit] for a non-suspending variant of this function.
- *
- * This method is **thread-safe** and can be safely invoked from concurrent coroutines without
- * external synchronization.
- */
- override suspend fun emit(value: T)
-
- /**
* Tries to emit a [value] to this shared flow without suspending. It returns `true` if the value was
* emitted successfully. When this function returns `false`, it means that the call to a plain [emit]
* function will suspend until there is a buffer space available.
@@ -166,9 +146,6 @@ public interface MutableSharedFlow<T> : SharedFlow<T>, FlowCollector<T> {
* A shared flow configured with a [BufferOverflow] strategy other than [SUSPEND][BufferOverflow.SUSPEND]
* (either [DROP_OLDEST][BufferOverflow.DROP_OLDEST] or [DROP_LATEST][BufferOverflow.DROP_LATEST]) never
* suspends on [emit], and thus `tryEmit` to such a shared flow always returns `true`.
- *
- * This method is **thread-safe** and can be safely invoked from concurrent coroutines without
- * external synchronization.
*/
public fun tryEmit(value: T): Boolean
@@ -204,9 +181,6 @@ public interface MutableSharedFlow<T> : SharedFlow<T>, FlowCollector<T> {
* supported, and throws an [UnsupportedOperationException]. To reset a [MutableStateFlow]
* to an initial value, just update its [value][MutableStateFlow.value].
*
- * This method is **thread-safe** and can be safely invoked from concurrent coroutines without
- * external synchronization.
- *
* **Note: This is an experimental api.** This function may be removed or renamed in the future.
*/
@ExperimentalCoroutinesApi
diff --git a/kotlinx-coroutines-core/common/src/flow/SharingStarted.kt b/kotlinx-coroutines-core/common/src/flow/SharingStarted.kt
index ce568fb4..19e5fa36 100644
--- a/kotlinx-coroutines-core/common/src/flow/SharingStarted.kt
+++ b/kotlinx-coroutines-core/common/src/flow/SharingStarted.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow
@@ -38,7 +38,7 @@ public enum class SharingCommand {
/**
* A strategy for starting and stopping the sharing coroutine in [shareIn] and [stateIn] operators.
*
- * This functional interface provides a set of built-in strategies: [Eagerly], [Lazily], [WhileSubscribed], and
+ * This interface provides a set of built-in strategies: [Eagerly], [Lazily], [WhileSubscribed], and
* supports custom strategies by implementing this interface's [command] function.
*
* For example, it is possible to define a custom strategy that starts the upstream only when the number
@@ -46,9 +46,11 @@ public enum class SharingCommand {
* that it looks like a built-in strategy on the use-site:
*
* ```
- * fun SharingStarted.Companion.WhileSubscribedAtLeast(threshold: Int) =
- * SharingStarted { subscriptionCount: StateFlow<Int> ->
- * subscriptionCount.map { if (it >= threshold) SharingCommand.START else SharingCommand.STOP }
+ * fun SharingStarted.Companion.WhileSubscribedAtLeast(threshold: Int): SharingStarted =
+ * object : SharingStarted {
+ * override fun command(subscriptionCount: StateFlow<Int>): Flow<SharingCommand> =
+ * subscriptionCount
+ * .map { if (it >= threshold) SharingCommand.START else SharingCommand.STOP }
* }
* ```
*
@@ -58,7 +60,7 @@ public enum class SharingCommand {
* [`command`][command] flow implementation function. Back-to-back emissions of the same command have no effect.
* Only emission of a different command has effect:
*
- * * [START][SharingCommand.START] &mdash; the upstream flow is started.
+ * * [START][SharingCommand.START] &mdash; the upstream flow is stared.
* * [STOP][SharingCommand.STOP] &mdash; the upstream flow is stopped.
* * [STOP_AND_RESET_REPLAY_CACHE][SharingCommand.STOP_AND_RESET_REPLAY_CACHE] &mdash;
* the upstream flow is stopped and the [SharedFlow.replayCache] is reset to its initial state.
@@ -72,7 +74,7 @@ public enum class SharingCommand {
* The completion of the `command` flow normally has no effect (the upstream flow keeps running if it was running).
* The failure of the `command` flow cancels the sharing coroutine and the upstream flow.
*/
-public fun interface SharingStarted {
+public interface SharingStarted {
public companion object {
/**
* Sharing is started immediately and never stops.
diff --git a/kotlinx-coroutines-core/common/src/flow/StateFlow.kt b/kotlinx-coroutines-core/common/src/flow/StateFlow.kt
index fc8aa02f..a9a4ed3d 100644
--- a/kotlinx-coroutines-core/common/src/flow/StateFlow.kt
+++ b/kotlinx-coroutines-core/common/src/flow/StateFlow.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow
@@ -160,9 +160,6 @@ public interface MutableStateFlow<T> : StateFlow<T>, MutableSharedFlow<T> {
* The current value of this state flow.
*
* Setting a value that is [equal][Any.equals] to the previous one does nothing.
- *
- * This property is **thread-safe** and can be safely updated from concurrent coroutines without
- * external synchronization.
*/
public override var value: T
@@ -173,9 +170,6 @@ public interface MutableStateFlow<T> : StateFlow<T>, MutableSharedFlow<T> {
* This function use a regular comparison using [Any.equals]. If both [expect] and [update] are equal to the
* current [value], this function returns `true`, but it does not actually change the reference that is
* stored in the [value].
- *
- * This method is **thread-safe** and can be safely invoked from concurrent coroutines without
- * external synchronization.
*/
public fun compareAndSet(expect: T, update: T): Boolean
}
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/AbstractSharedFlow.kt b/kotlinx-coroutines-core/common/src/flow/internal/AbstractSharedFlow.kt
index 7114cc08..ccb53430 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/AbstractSharedFlow.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/AbstractSharedFlow.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
@@ -98,4 +98,4 @@ internal abstract class AbstractSharedFlow<S : AbstractSharedFlowSlot<*>> : Sync
if (slot != null) block(slot)
}
}
-}
+} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/ChannelFlow.kt b/kotlinx-coroutines-core/common/src/flow/internal/ChannelFlow.kt
index bf82cf9a..f3730cc7 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/ChannelFlow.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/ChannelFlow.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/Combine.kt b/kotlinx-coroutines-core/common/src/flow/internal/Combine.kt
index 7fde0636..bbdebd08 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/Combine.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/Combine.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("UNCHECKED_CAST", "NON_APPLICABLE_CALL_FOR_BUILDER_INFERENCE") // KT-32203
@@ -23,7 +23,7 @@ internal suspend fun <R, T> FlowCollector<R>.combineInternal(
val size = flows.size
if (size == 0) return@flowScope // bail-out for empty input
val latestValues = arrayOfNulls<Any?>(size)
- latestValues.fill(UNINITIALIZED) // Smaller bytecode & faster than Array(size) { UNINITIALIZED }
+ latestValues.fill(UNINITIALIZED) // Smaller bytecode & faster that Array(size) { UNINITIALIZED }
val resultChannel = Channel<Update>(size)
val nonClosed = LocalAtomicInt(size)
var remainingAbsentValues = size
@@ -137,7 +137,7 @@ internal fun <T1, T2, R> zipImpl(flow: Flow<T1>, flow2: Flow<T2>, transform: sus
} catch (e: AbortFlowException) {
e.checkOwnership(owner = this@unsafeFlow)
} finally {
- second.cancel()
+ if (!second.isClosedForReceive) second.cancel()
}
}
}
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/FlowCoroutine.kt b/kotlinx-coroutines-core/common/src/flow/internal/FlowCoroutine.kt
index b3955256..acc6ca04 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/FlowCoroutine.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/FlowCoroutine.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/FlowExceptions.common.kt b/kotlinx-coroutines-core/common/src/flow/internal/FlowExceptions.common.kt
index 6a6c369c..3064ed26 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/FlowExceptions.common.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/FlowExceptions.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/Merge.kt b/kotlinx-coroutines-core/common/src/flow/internal/Merge.kt
index 9eca8aa0..530bcc1e 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/Merge.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/Merge.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/NopCollector.kt b/kotlinx-coroutines-core/common/src/flow/internal/NopCollector.kt
index a2d7f04f..62a20a07 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/NopCollector.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/NopCollector.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/NullSurrogate.kt b/kotlinx-coroutines-core/common/src/flow/internal/NullSurrogate.kt
index c7327bd3..f20deb2d 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/NullSurrogate.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/NullSurrogate.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/SafeCollector.common.kt b/kotlinx-coroutines-core/common/src/flow/internal/SafeCollector.common.kt
index 006da41f..c89e94f5 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/SafeCollector.common.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/SafeCollector.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/common/src/flow/internal/SendingCollector.kt b/kotlinx-coroutines-core/common/src/flow/internal/SendingCollector.kt
index 5188a969..c2abafd2 100644
--- a/kotlinx-coroutines-core/common/src/flow/internal/SendingCollector.kt
+++ b/kotlinx-coroutines-core/common/src/flow/internal/SendingCollector.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Context.kt b/kotlinx-coroutines-core/common/src/flow/operators/Context.kt
index cbbb4196..a6d6b76d 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Context.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Context.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@@ -181,7 +181,7 @@ public fun <T> Flow<T>.buffer(capacity: Int = BUFFERED): Flow<T> = buffer(capaci
* **Conflation takes precedence over `buffer()` calls with any other capacity.**
*
* Note that any instance of [StateFlow] already behaves as if `conflate` operator is
- * applied to it, so applying `conflate` to a `StateFlow` has no effect.
+ * applied to it, so applying `conflate` to a `StateFlow` has not effect.
* See [StateFlow] documentation on Operator Fusion.
*/
public fun <T> Flow<T>.conflate(): Flow<T> = buffer(CONFLATED)
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Delay.kt b/kotlinx-coroutines-core/common/src/flow/operators/Delay.kt
index 6381c467..c95b4be9 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Delay.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Delay.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Distinct.kt b/kotlinx-coroutines-core/common/src/flow/operators/Distinct.kt
index 0d67f889..1a34af77 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Distinct.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Distinct.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@@ -83,4 +83,4 @@ private class DistinctFlowImpl<T>(
}
}
}
-}
+} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Emitters.kt b/kotlinx-coroutines-core/common/src/flow/operators/Emitters.kt
index e0d3aebc..244af9a7 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Emitters.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Emitters.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Errors.kt b/kotlinx-coroutines-core/common/src/flow/operators/Errors.kt
index 608221e0..c73ded9e 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Errors.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Errors.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Limit.kt b/kotlinx-coroutines-core/common/src/flow/operators/Limit.kt
index 8fbf1a2b..1d7ffd1d 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Limit.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Limit.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Lint.kt b/kotlinx-coroutines-core/common/src/flow/operators/Lint.kt
index 2f7bc358..7a70fbf7 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Lint.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Lint.kt
@@ -1,14 +1,13 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-@file:Suppress("unused", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
+@file:Suppress("unused")
package kotlinx.coroutines.flow
import kotlinx.coroutines.*
import kotlin.coroutines.*
-import kotlin.internal.InlineOnly
/**
* Applying [cancellable][Flow.cancellable] to a [SharedFlow] has no effect.
@@ -80,61 +79,4 @@ public fun FlowCollector<*>.cancel(cause: CancellationException? = null): Unit =
replaceWith = ReplaceWith("currentCoroutineContext()")
)
public val FlowCollector<*>.coroutineContext: CoroutineContext
- get() = noImpl()
-
-@Deprecated(
- message = "SharedFlow never completes, so this operator has no effect.",
- level = DeprecationLevel.WARNING,
- replaceWith = ReplaceWith("this")
-)
-@InlineOnly
-public inline fun <T> SharedFlow<T>.catch(noinline action: suspend FlowCollector<T>.(cause: Throwable) -> Unit): Flow<T> =
- (this as Flow<T>).catch(action)
-
-@Deprecated(
- message = "SharedFlow never completes, so this operator has no effect.",
- level = DeprecationLevel.WARNING,
- replaceWith = ReplaceWith("this")
-)
-@InlineOnly
-public inline fun <T> SharedFlow<T>.retry(
- retries: Long = Long.MAX_VALUE,
- noinline predicate: suspend (cause: Throwable) -> Boolean = { true }
-): Flow<T> =
- (this as Flow<T>).retry(retries, predicate)
-
-@Deprecated(
- message = "SharedFlow never completes, so this operator has no effect.",
- level = DeprecationLevel.WARNING,
- replaceWith = ReplaceWith("this")
-)
-@InlineOnly
-public inline fun <T> SharedFlow<T>.retryWhen(noinline predicate: suspend FlowCollector<T>.(cause: Throwable, attempt: Long) -> Boolean): Flow<T> =
- (this as Flow<T>).retryWhen(predicate)
-
-@Suppress("DeprecatedCallableAddReplaceWith")
-@Deprecated(
- message = "SharedFlow never completes, so this terminal operation never completes.",
- level = DeprecationLevel.WARNING
-)
-@InlineOnly
-public suspend inline fun <T> SharedFlow<T>.toList(): List<T> =
- (this as Flow<T>).toList()
-
-@Suppress("DeprecatedCallableAddReplaceWith")
-@Deprecated(
- message = "SharedFlow never completes, so this terminal operation never completes.",
- level = DeprecationLevel.WARNING
-)
-@InlineOnly
-public suspend inline fun <T> SharedFlow<T>.toSet(): Set<T> =
- (this as Flow<T>).toSet()
-
-@Suppress("DeprecatedCallableAddReplaceWith")
-@Deprecated(
- message = "SharedFlow never completes, so this terminal operation never completes.",
- level = DeprecationLevel.WARNING
-)
-@InlineOnly
-public suspend inline fun <T> SharedFlow<T>.count(): Int =
- (this as Flow<T>).count()
+ get() = noImpl() \ No newline at end of file
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Merge.kt b/kotlinx-coroutines-core/common/src/flow/operators/Merge.kt
index 04275375..340d8e31 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Merge.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Merge.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@@ -34,7 +34,7 @@ public val DEFAULT_CONCURRENCY: Int = systemProp(DEFAULT_CONCURRENCY_PROPERTY_NA
* Transforms elements emitted by the original flow by applying [transform], that returns another flow,
* and then concatenating and flattening these flows.
*
- * This method is a shortcut for `map(transform).flattenConcat()`. See [flattenConcat].
+ * This method is is a shortcut for `map(transform).flattenConcat()`. See [flattenConcat].
*
* Note that even though this operator looks very familiar, we discourage its usage in a regular application-specific flows.
* Most likely, suspending operation in [map] operator will be sufficient and linear transformations are much easier to reason about.
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Share.kt b/kotlinx-coroutines-core/common/src/flow/operators/Share.kt
index fe1d7216..fe737a5b 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Share.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Share.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Transform.kt b/kotlinx-coroutines-core/common/src/flow/operators/Transform.kt
index d163d9c0..e3552d28 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Transform.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Transform.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/flow/operators/Zip.kt b/kotlinx-coroutines-core/common/src/flow/operators/Zip.kt
index ed6f5722..790c0895 100644
--- a/kotlinx-coroutines-core/common/src/flow/operators/Zip.kt
+++ b/kotlinx-coroutines-core/common/src/flow/operators/Zip.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@@ -153,7 +153,7 @@ public fun <T1, T2, T3, T4, R> combine(
flow3: Flow<T3>,
flow4: Flow<T4>,
transform: suspend (T1, T2, T3, T4) -> R
-): Flow<R> = combineUnsafe(flow, flow2, flow3, flow4) { args: Array<*> ->
+): Flow<R> = combine(flow, flow2, flow3, flow4) { args: Array<*> ->
transform(
args[0] as T1,
args[1] as T2,
diff --git a/kotlinx-coroutines-core/common/src/flow/terminal/Collect.kt b/kotlinx-coroutines-core/common/src/flow/terminal/Collect.kt
index 42c66296..e8f2a9a3 100644
--- a/kotlinx-coroutines-core/common/src/flow/terminal/Collect.kt
+++ b/kotlinx-coroutines-core/common/src/flow/terminal/Collect.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@@ -87,8 +87,8 @@ public suspend inline fun <T> Flow<T>.collectIndexed(crossinline action: suspend
/**
* Terminal flow operator that collects the given flow with a provided [action].
- * The crucial difference from [collect] is that when the original flow emits a new value
- * then the [action] block for the previous value is cancelled.
+ * The crucial difference from [collect] is that when the original flow emits a new value, [action] block for previous
+ * value is cancelled.
*
* It can be demonstrated by the following example:
*
diff --git a/kotlinx-coroutines-core/common/src/flow/terminal/Collection.kt b/kotlinx-coroutines-core/common/src/flow/terminal/Collection.kt
index c973da89..6b05ca18 100644
--- a/kotlinx-coroutines-core/common/src/flow/terminal/Collection.kt
+++ b/kotlinx-coroutines-core/common/src/flow/terminal/Collection.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/flow/terminal/Count.kt b/kotlinx-coroutines-core/common/src/flow/terminal/Count.kt
index 5eb99fc8..d50c0272 100644
--- a/kotlinx-coroutines-core/common/src/flow/terminal/Count.kt
+++ b/kotlinx-coroutines-core/common/src/flow/terminal/Count.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/flow/terminal/Reduce.kt b/kotlinx-coroutines-core/common/src/flow/terminal/Reduce.kt
index a937adcc..83f5498e 100644
--- a/kotlinx-coroutines-core/common/src/flow/terminal/Reduce.kt
+++ b/kotlinx-coroutines-core/common/src/flow/terminal/Reduce.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/common/src/internal/ArrayQueue.kt b/kotlinx-coroutines-core/common/src/internal/ArrayQueue.kt
index 6b994b68..09806cd2 100644
--- a/kotlinx-coroutines-core/common/src/internal/ArrayQueue.kt
+++ b/kotlinx-coroutines-core/common/src/internal/ArrayQueue.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/common/src/internal/Atomic.kt b/kotlinx-coroutines-core/common/src/internal/Atomic.kt
index cf43764c..a27d5491 100644
--- a/kotlinx-coroutines-core/common/src/internal/Atomic.kt
+++ b/kotlinx-coroutines-core/common/src/internal/Atomic.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("NO_EXPLICIT_VISIBILITY_IN_API_MODE")
diff --git a/kotlinx-coroutines-core/common/src/internal/Concurrent.common.kt b/kotlinx-coroutines-core/common/src/internal/Concurrent.common.kt
index 9f2699ae..1836a528 100644
--- a/kotlinx-coroutines-core/common/src/internal/Concurrent.common.kt
+++ b/kotlinx-coroutines-core/common/src/internal/Concurrent.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/common/src/internal/ConcurrentLinkedList.kt b/kotlinx-coroutines-core/common/src/internal/ConcurrentLinkedList.kt
index 0e765838..128a1998 100644
--- a/kotlinx-coroutines-core/common/src/internal/ConcurrentLinkedList.kt
+++ b/kotlinx-coroutines-core/common/src/internal/ConcurrentLinkedList.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
@@ -237,4 +237,4 @@ internal inline class SegmentOrClosed<S : Segment<S>>(private val value: Any?) {
private const val POINTERS_SHIFT = 16
@SharedImmutable
-private val CLOSED = Symbol("CLOSED")
+private val CLOSED = Symbol("CLOSED") \ No newline at end of file
diff --git a/kotlinx-coroutines-core/common/src/internal/DispatchedContinuation.kt b/kotlinx-coroutines-core/common/src/internal/DispatchedContinuation.kt
index 2874e7d5..b7b2954f 100644
--- a/kotlinx-coroutines-core/common/src/internal/DispatchedContinuation.kt
+++ b/kotlinx-coroutines-core/common/src/internal/DispatchedContinuation.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
@@ -23,7 +23,7 @@ internal class DispatchedContinuation<in T>(
@JvmField
@Suppress("PropertyName")
internal var _state: Any? = UNDEFINED
- override val callerFrame: CoroutineStackFrame? get() = continuation as? CoroutineStackFrame
+ override val callerFrame: CoroutineStackFrame? = continuation as? CoroutineStackFrame
override fun getStackTraceElement(): StackTraceElement? = null
@JvmField // pre-cached value to avoid ctx.fold on every resumption
internal val countOrElement = threadContextElements(context)
@@ -235,7 +235,7 @@ internal class DispatchedContinuation<in T>(
@Suppress("NOTHING_TO_INLINE") // we need it inline to save us an entry on the stack
inline fun resumeUndispatchedWith(result: Result<T>) {
- withContinuationContext(continuation, countOrElement) {
+ withCoroutineContext(context, countOrElement) {
continuation.resumeWith(result)
}
}
diff --git a/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt b/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt
index d982f95b..1f4942a3 100644
--- a/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt
+++ b/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -23,7 +23,7 @@ internal const val MODE_ATOMIC = 0
* **DO NOT CHANGE THE CONSTANT VALUE**. It is being into the user code from [suspendCancellableCoroutine].
*/
@PublishedApi
-internal const val MODE_CANCELLABLE: Int = 1
+internal const val MODE_CANCELLABLE = 1
/**
* Cancellable dispatch mode for [suspendCancellableCoroutineReusable].
@@ -85,9 +85,9 @@ internal abstract class DispatchedTask<in T>(
try {
val delegate = delegate as DispatchedContinuation<T>
val continuation = delegate.continuation
- withContinuationContext(continuation, delegate.countOrElement) {
- val context = continuation.context
- val state = takeState() // NOTE: Must take state in any case, even if cancelled
+ val context = continuation.context
+ val state = takeState() // NOTE: Must take state in any case, even if cancelled
+ withCoroutineContext(context, delegate.countOrElement) {
val exception = getExceptionalResult(state)
/*
* Check whether continuation was originally resumed with an exception.
@@ -134,7 +134,7 @@ internal abstract class DispatchedTask<in T>(
* Fatal exception handling can be intercepted with [CoroutineExceptionHandler] element in the context of
* a failed coroutine, but such exceptions should be reported anyway.
*/
- public fun handleFatalException(exception: Throwable?, finallyException: Throwable?) {
+ internal fun handleFatalException(exception: Throwable?, finallyException: Throwable?) {
if (exception === null && finallyException === null) return
if (exception !== null && finallyException !== null) {
exception.addSuppressedThrowable(finallyException)
diff --git a/kotlinx-coroutines-core/common/src/internal/InlineList.kt b/kotlinx-coroutines-core/common/src/internal/InlineList.kt
index 34c1e893..bac8610c 100644
--- a/kotlinx-coroutines-core/common/src/internal/InlineList.kt
+++ b/kotlinx-coroutines-core/common/src/internal/InlineList.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("UNCHECKED_CAST")
diff --git a/kotlinx-coroutines-core/common/src/internal/LocalAtomics.common.kt b/kotlinx-coroutines-core/common/src/internal/LocalAtomics.common.kt
index 74848b2d..bcfb932d 100644
--- a/kotlinx-coroutines-core/common/src/internal/LocalAtomics.common.kt
+++ b/kotlinx-coroutines-core/common/src/internal/LocalAtomics.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/common/src/internal/LockFreeLinkedList.common.kt b/kotlinx-coroutines-core/common/src/internal/LockFreeLinkedList.common.kt
index 0e1d1b47..8508e392 100644
--- a/kotlinx-coroutines-core/common/src/internal/LockFreeLinkedList.common.kt
+++ b/kotlinx-coroutines-core/common/src/internal/LockFreeLinkedList.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("NO_EXPLICIT_VISIBILITY_IN_API_MODE")
diff --git a/kotlinx-coroutines-core/common/src/internal/LockFreeTaskQueue.kt b/kotlinx-coroutines-core/common/src/internal/LockFreeTaskQueue.kt
index 10c5c830..dfee8e9f 100644
--- a/kotlinx-coroutines-core/common/src/internal/LockFreeTaskQueue.kt
+++ b/kotlinx-coroutines-core/common/src/internal/LockFreeTaskQueue.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/common/src/internal/MainDispatcherFactory.kt b/kotlinx-coroutines-core/common/src/internal/MainDispatcherFactory.kt
index 0b863868..c3587af6 100644
--- a/kotlinx-coroutines-core/common/src/internal/MainDispatcherFactory.kt
+++ b/kotlinx-coroutines-core/common/src/internal/MainDispatcherFactory.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/common/src/internal/OnUndeliveredElement.kt b/kotlinx-coroutines-core/common/src/internal/OnUndeliveredElement.kt
index 0701d686..1744359e 100644
--- a/kotlinx-coroutines-core/common/src/internal/OnUndeliveredElement.kt
+++ b/kotlinx-coroutines-core/common/src/internal/OnUndeliveredElement.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/common/src/internal/ProbesSupport.common.kt b/kotlinx-coroutines-core/common/src/internal/ProbesSupport.common.kt
index a6d81361..763c1ca3 100644
--- a/kotlinx-coroutines-core/common/src/internal/ProbesSupport.common.kt
+++ b/kotlinx-coroutines-core/common/src/internal/ProbesSupport.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/common/src/internal/Scopes.kt b/kotlinx-coroutines-core/common/src/internal/Scopes.kt
index 98db37de..9bb2ce3d 100644
--- a/kotlinx-coroutines-core/common/src/internal/Scopes.kt
+++ b/kotlinx-coroutines-core/common/src/internal/Scopes.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
@@ -16,7 +16,7 @@ internal open class ScopeCoroutine<in T>(
context: CoroutineContext,
@JvmField val uCont: Continuation<T> // unintercepted continuation
) : AbstractCoroutine<T>(context, true), CoroutineStackFrame {
- final override val callerFrame: CoroutineStackFrame? get() = uCont as? CoroutineStackFrame
+ final override val callerFrame: CoroutineStackFrame? get() = uCont as CoroutineStackFrame?
final override fun getStackTraceElement(): StackTraceElement? = null
final override val isScopedCoroutine: Boolean get() = true
diff --git a/kotlinx-coroutines-core/common/src/internal/StackTraceRecovery.common.kt b/kotlinx-coroutines-core/common/src/internal/StackTraceRecovery.common.kt
index b91f30d3..15ba40f2 100644
--- a/kotlinx-coroutines-core/common/src/internal/StackTraceRecovery.common.kt
+++ b/kotlinx-coroutines-core/common/src/internal/StackTraceRecovery.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/common/src/internal/Symbol.kt b/kotlinx-coroutines-core/common/src/internal/Symbol.kt
index 84db2ef6..4fa8f540 100644
--- a/kotlinx-coroutines-core/common/src/internal/Symbol.kt
+++ b/kotlinx-coroutines-core/common/src/internal/Symbol.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
@@ -10,7 +10,7 @@ package kotlinx.coroutines.internal
* @suppress **This is unstable API and it is subject to change.**
*/
internal class Symbol(val symbol: String) {
- override fun toString(): String = "<$symbol>"
+ override fun toString(): String = symbol
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
inline fun <T> unbox(value: Any?): T = if (value === this) null as T else value as T
diff --git a/kotlinx-coroutines-core/common/src/internal/Synchronized.common.kt b/kotlinx-coroutines-core/common/src/internal/Synchronized.common.kt
index 059b234d..3afc7e18 100644
--- a/kotlinx-coroutines-core/common/src/internal/Synchronized.common.kt
+++ b/kotlinx-coroutines-core/common/src/internal/Synchronized.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/common/src/internal/SystemProps.common.kt b/kotlinx-coroutines-core/common/src/internal/SystemProps.common.kt
index ca84809b..4cb629e9 100644
--- a/kotlinx-coroutines-core/common/src/internal/SystemProps.common.kt
+++ b/kotlinx-coroutines-core/common/src/internal/SystemProps.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmName("SystemPropsKt")
diff --git a/kotlinx-coroutines-core/common/src/internal/ThreadContext.common.kt b/kotlinx-coroutines-core/common/src/internal/ThreadContext.common.kt
index 6d14e592..94695e8a 100644
--- a/kotlinx-coroutines-core/common/src/internal/ThreadContext.common.kt
+++ b/kotlinx-coroutines-core/common/src/internal/ThreadContext.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/common/src/internal/ThreadLocal.common.kt b/kotlinx-coroutines-core/common/src/internal/ThreadLocal.common.kt
index 890ae4e3..0f4ec342 100644
--- a/kotlinx-coroutines-core/common/src/internal/ThreadLocal.common.kt
+++ b/kotlinx-coroutines-core/common/src/internal/ThreadLocal.common.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/common/src/internal/ThreadSafeHeap.kt b/kotlinx-coroutines-core/common/src/internal/ThreadSafeHeap.kt
index 43b7e9de..df55c28f 100644
--- a/kotlinx-coroutines-core/common/src/internal/ThreadSafeHeap.kt
+++ b/kotlinx-coroutines-core/common/src/internal/ThreadSafeHeap.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/common/src/intrinsics/Cancellable.kt b/kotlinx-coroutines-core/common/src/intrinsics/Cancellable.kt
index 173f0afb..f814b152 100644
--- a/kotlinx-coroutines-core/common/src/intrinsics/Cancellable.kt
+++ b/kotlinx-coroutines-core/common/src/intrinsics/Cancellable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.intrinsics
diff --git a/kotlinx-coroutines-core/common/src/intrinsics/Undispatched.kt b/kotlinx-coroutines-core/common/src/intrinsics/Undispatched.kt
index 1273634e..525e322f 100644
--- a/kotlinx-coroutines-core/common/src/intrinsics/Undispatched.kt
+++ b/kotlinx-coroutines-core/common/src/intrinsics/Undispatched.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.intrinsics
diff --git a/kotlinx-coroutines-core/common/src/selects/Select.kt b/kotlinx-coroutines-core/common/src/selects/Select.kt
index 0d974007..99c54f84 100644
--- a/kotlinx-coroutines-core/common/src/selects/Select.kt
+++ b/kotlinx-coroutines-core/common/src/selects/Select.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:OptIn(ExperimentalContracts::class)
@@ -327,18 +327,19 @@ internal class SelectBuilderImpl<in R>(
private fun initCancellability() {
val parent = context[Job] ?: return
val newRegistration = parent.invokeOnCompletion(
- onCancelling = true, handler = SelectOnCancelling().asHandler)
+ onCancelling = true, handler = SelectOnCancelling(parent).asHandler)
parentHandle = newRegistration
// now check our state _after_ registering
if (isSelected) newRegistration.dispose()
}
- private inner class SelectOnCancelling : JobCancellingNode() {
+ private inner class SelectOnCancelling(job: Job) : JobCancellingNode<Job>(job) {
// Note: may be invoked multiple times, but only the first trySelect succeeds anyway
override fun invoke(cause: Throwable?) {
if (trySelect())
resumeSelectWithException(job.getCancellationException())
}
+ override fun toString(): String = "SelectOnCancelling[${this@SelectBuilderImpl}]"
}
@PublishedApi
@@ -552,7 +553,7 @@ internal class SelectBuilderImpl<in R>(
return decision
}
- override val atomicOp: AtomicOp<*>
+ override val atomicOp: AtomicOp<*>?
get() = otherOp.atomicOp
}
diff --git a/kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt b/kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt
index c33c5b1f..edcf123b 100644
--- a/kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt
+++ b/kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.selects
@@ -36,7 +36,7 @@ internal class UnbiasedSelectBuilderImpl<in R>(uCont: Continuation<R>) :
val clauses = arrayListOf<() -> Unit>()
@PublishedApi
- internal fun handleBuilderException(e: Throwable): Unit = instance.handleBuilderException(e)
+ internal fun handleBuilderException(e: Throwable) = instance.handleBuilderException(e)
@PublishedApi
internal fun initSelectResult(): Any? {
diff --git a/kotlinx-coroutines-core/common/src/selects/WhileSelect.kt b/kotlinx-coroutines-core/common/src/selects/WhileSelect.kt
index 98a9c672..33d4d7ec 100644
--- a/kotlinx-coroutines-core/common/src/selects/WhileSelect.kt
+++ b/kotlinx-coroutines-core/common/src/selects/WhileSelect.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.selects
diff --git a/kotlinx-coroutines-core/common/src/sync/Mutex.kt b/kotlinx-coroutines-core/common/src/sync/Mutex.kt
index 7d0a343d..73aaab5f 100644
--- a/kotlinx-coroutines-core/common/src/sync/Mutex.kt
+++ b/kotlinx-coroutines-core/common/src/sync/Mutex.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.sync
@@ -201,8 +201,7 @@ internal class MutexImpl(locked: Boolean) : Mutex, SelectClause2<Any?, Mutex> {
// try lock
val update = if (owner == null) EMPTY_LOCKED else Empty(owner)
if (_state.compareAndSet(state, update)) { // locked
- // TODO implement functional type in LockCont as soon as we get rid of legacy JS
- cont.resume(Unit) { unlock(owner) }
+ cont.resume(Unit)
return@sc
}
}
diff --git a/kotlinx-coroutines-core/common/src/sync/Semaphore.kt b/kotlinx-coroutines-core/common/src/sync/Semaphore.kt
index e8b28bc1..84b7f4f8 100644
--- a/kotlinx-coroutines-core/common/src/sync/Semaphore.kt
+++ b/kotlinx-coroutines-core/common/src/sync/Semaphore.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.sync
@@ -172,7 +172,7 @@ private class SemaphoreImpl(private val permits: Int, acquiredPermits: Int) : Se
if (addAcquireToQueue(cont)) return@sc
val p = _availablePermits.getAndDecrement()
if (p > 0) { // permit acquired
- cont.resume(Unit, onCancellationRelease)
+ cont.resume(Unit)
return@sc
}
}
@@ -206,8 +206,9 @@ private class SemaphoreImpl(private val permits: Int, acquiredPermits: Int) : Se
// On CAS failure -- the cell must be either PERMIT or BROKEN
// If the cell already has PERMIT from tryResumeNextFromQueue, try to grab it
if (segment.cas(i, PERMIT, TAKEN)) { // took permit thus eliminating acquire/release pair
- /// This continuation is not yet published, but still can be cancelled via outer job
- cont.resume(Unit, onCancellationRelease)
+ // The following resume must always succeed, since continuation was not published yet and we don't have
+ // to pass onCancellationRelease handle, since the coroutine did not suspend yet and cannot be cancelled
+ cont.resume(Unit)
return true
}
assert { segment.get(i) === BROKEN } // it must be broken in this case, no other way around it
diff --git a/kotlinx-coroutines-core/common/test/AtomicCancellationCommonTest.kt b/kotlinx-coroutines-core/common/test/AtomicCancellationCommonTest.kt
index a4101377..c763faf2 100644
--- a/kotlinx-coroutines-core/common/test/AtomicCancellationCommonTest.kt
+++ b/kotlinx-coroutines-core/common/test/AtomicCancellationCommonTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -32,38 +32,6 @@ class AtomicCancellationCommonTest : TestBase() {
}
@Test
- fun testUndispatchedLaunch() = runTest {
- expect(1)
- assertFailsWith<CancellationException> {
- withContext(Job()) {
- cancel()
- launch(start = CoroutineStart.UNDISPATCHED) {
- expect(2)
- yield()
- expectUnreached()
- }
- }
- }
- finish(3)
- }
-
- @Test
- fun testUndispatchedLaunchWithUnconfinedContext() = runTest {
- expect(1)
- assertFailsWith<CancellationException> {
- withContext(Dispatchers.Unconfined + Job()) {
- cancel()
- launch(start = CoroutineStart.UNDISPATCHED) {
- expect(2)
- yield()
- expectUnreached()
- }
- }
- }
- finish(3)
- }
-
- @Test
fun testDeferredAwaitCancellable() = runTest {
expect(1)
val deferred = async { // deferred, not yet complete
@@ -154,4 +122,4 @@ class AtomicCancellationCommonTest : TestBase() {
yield() // now yield
finish(4)
}
-}
+} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/common/test/AwaitTest.kt b/kotlinx-coroutines-core/common/test/AwaitTest.kt
index 10d5b919..0949b62c 100644
--- a/kotlinx-coroutines-core/common/test/AwaitTest.kt
+++ b/kotlinx-coroutines-core/common/test/AwaitTest.kt
@@ -351,32 +351,4 @@ class AwaitTest : TestBase() {
async(NonCancellable) { throw TestException() }
joinAll(job, job, job)
}
-
- @Test
- fun testAwaitAllDelegates() = runTest {
- expect(1)
- val deferred = CompletableDeferred<String>()
- val delegate = object : Deferred<String> by deferred {}
- launch {
- expect(3)
- deferred.complete("OK")
- }
- expect(2)
- awaitAll(delegate)
- finish(4)
- }
-
- @Test
- fun testCancelAwaitAllDelegate() = runTest {
- expect(1)
- val deferred = CompletableDeferred<String>()
- val delegate = object : Deferred<String> by deferred {}
- launch {
- expect(3)
- deferred.cancel()
- }
- expect(2)
- assertFailsWith<CancellationException> { awaitAll(delegate) }
- finish(4)
- }
}
diff --git a/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt b/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt
index 5a96c544..b20dd6b1 100644
--- a/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt
+++ b/kotlinx-coroutines-core/common/test/BuilderContractsTest.kt
@@ -1,10 +1,9 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
-import kotlinx.coroutines.channels.*
import kotlinx.coroutines.selects.*
import kotlin.test.*
@@ -45,22 +44,9 @@ class BuilderContractsTest : TestBase() {
Job().apply { complete() }.onJoin {}
}
consume(s)
-
-
- val ch: Int
- val i = Channel<Int>()
- i.consume {
- ch = 321
- }
- consume(ch)
}
private fun consume(a: Int) {
- /*
- * Verify the value is actually set correctly
- * (non-zero, VerificationError is not triggered, can be read)
- */
- assertNotEquals(0, a)
- assertEquals(a.hashCode(), a)
+ a.hashCode() // BE codegen verification
}
-}
+} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt b/kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt
index 5513dab7..0391e000 100644
--- a/kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt
+++ b/kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt
@@ -1,7 +1,3 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
package kotlinx.coroutines.channels
import kotlinx.atomicfu.*
@@ -55,20 +51,6 @@ class ChannelUndeliveredElementTest : TestBase() {
}
@Test
- fun testUnlimitedChannelCancelled() = runTest {
- val channel = Channel<Resource>(Channel.UNLIMITED) { it.cancel() }
- val resA = Resource("A")
- val resB = Resource("B")
- channel.send(resA) // goes to buffer
- channel.send(resB) // goes to buffer
- assertFalse(resA.isCancelled) // it is in buffer, not cancelled
- assertFalse(resB.isCancelled) // it is in buffer, not cancelled
- channel.cancel() // now cancel the channel
- assertTrue(resA.isCancelled) // now cancelled in buffer
- assertTrue(resB.isCancelled) // now cancelled in buffer
- }
-
- @Test
fun testConflatedResourceCancelled() = runTest {
val channel = Channel<Resource>(Channel.CONFLATED) { it.cancel() }
val resA = Resource("A")
@@ -119,4 +101,4 @@ class ChannelUndeliveredElementTest : TestBase() {
check(!_cancelled.getAndSet(true)) { "Already cancelled" }
}
}
-}
+} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/common/test/channels/ProduceTest.kt b/kotlinx-coroutines-core/common/test/channels/ProduceTest.kt
index 194504e7..6ddde001 100644
--- a/kotlinx-coroutines-core/common/test/channels/ProduceTest.kt
+++ b/kotlinx-coroutines-core/common/test/channels/ProduceTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
@@ -96,27 +96,6 @@ class ProduceTest : TestBase() {
}
@Test
- fun testCancelWhenTheChannelIsClosed() = runTest {
- val channel = produce<Int> {
- send(1)
- close()
- expect(2)
- launch {
- expect(3)
- hang { expect(5) }
- }
- }
-
- expect(1)
- channel.receive()
- yield()
- expect(4)
- channel.cancel()
- (channel as Job).join()
- finish(6)
- }
-
- @Test
fun testAwaitConsumerCancellation() = runTest {
val parent = Job()
val channel = produce<Int>(parent) {
diff --git a/kotlinx-coroutines-core/common/test/flow/channels/ChannelFlowTest.kt b/kotlinx-coroutines-core/common/test/flow/channels/ChannelFlowTest.kt
index 31a929b2..b115150a 100644
--- a/kotlinx-coroutines-core/common/test/flow/channels/ChannelFlowTest.kt
+++ b/kotlinx-coroutines-core/common/test/flow/channels/ChannelFlowTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow
@@ -194,17 +194,4 @@ class ChannelFlowTest : TestBase() {
assertEquals(listOf(1), flow.toList())
finish(3)
}
-
- @Test
- fun testCancelledOnCompletion() = runTest {
- val myFlow = callbackFlow<Any> {
- expect(2)
- close()
- hang { expect(3) }
- }
-
- expect(1)
- myFlow.collect()
- finish(4)
- }
}
diff --git a/kotlinx-coroutines-core/common/test/flow/sharing/ShareInTest.kt b/kotlinx-coroutines-core/common/test/flow/sharing/ShareInTest.kt
index 42cdb1e1..9020f5f3 100644
--- a/kotlinx-coroutines-core/common/test/flow/sharing/ShareInTest.kt
+++ b/kotlinx-coroutines-core/common/test/flow/sharing/ShareInTest.kt
@@ -187,9 +187,11 @@ class ShareInTest : TestBase() {
}
@Suppress("TestFunctionName")
- private fun SharingStarted.Companion.WhileSubscribedAtLeast(threshold: Int) =
- SharingStarted { subscriptionCount ->
- subscriptionCount.map { if (it >= threshold) SharingCommand.START else SharingCommand.STOP }
+ private fun SharingStarted.Companion.WhileSubscribedAtLeast(threshold: Int): SharingStarted =
+ object : SharingStarted {
+ override fun command(subscriptionCount: StateFlow<Int>): Flow<SharingCommand> =
+ subscriptionCount
+ .map { if (it >= threshold) SharingCommand.START else SharingCommand.STOP }
}
private class FlowState {
diff --git a/kotlinx-coroutines-core/common/test/sync/MutexTest.kt b/kotlinx-coroutines-core/common/test/sync/MutexTest.kt
index 4f428bc4..c5d0ccf1 100644
--- a/kotlinx-coroutines-core/common/test/sync/MutexTest.kt
+++ b/kotlinx-coroutines-core/common/test/sync/MutexTest.kt
@@ -4,7 +4,6 @@
package kotlinx.coroutines.sync
-import kotlinx.atomicfu.*
import kotlinx.coroutines.*
import kotlin.test.*
@@ -107,4 +106,4 @@ class MutexTest : TestBase() {
assertFalse(mutex.holdsLock(firstOwner))
assertFalse(mutex.holdsLock(secondOwner))
}
-}
+} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/js/src/CompletionHandler.kt b/kotlinx-coroutines-core/js/src/CompletionHandler.kt
index 2ff10702..e81e4351 100644
--- a/kotlinx-coroutines-core/js/src/CompletionHandler.kt
+++ b/kotlinx-coroutines-core/js/src/CompletionHandler.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/js/src/CoroutineContext.kt b/kotlinx-coroutines-core/js/src/CoroutineContext.kt
index e08345a1..c0b0c511 100644
--- a/kotlinx-coroutines-core/js/src/CoroutineContext.kt
+++ b/kotlinx-coroutines-core/js/src/CoroutineContext.kt
@@ -1,10 +1,9 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
-import kotlinx.coroutines.internal.*
import kotlin.browser.*
import kotlin.coroutines.*
@@ -50,13 +49,5 @@ public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext):
// No debugging facilities on JS
internal actual inline fun <T> withCoroutineContext(context: CoroutineContext, countOrElement: Any?, block: () -> T): T = block()
-internal actual inline fun <T> withContinuationContext(continuation: Continuation<*>, countOrElement: Any?, block: () -> T): T = block()
internal actual fun Continuation<*>.toDebugString(): String = toString()
internal actual val CoroutineContext.coroutineName: String? get() = null // not supported on JS
-
-internal actual class UndispatchedCoroutine<in T> actual constructor(
- context: CoroutineContext,
- uCont: Continuation<T>
-) : ScopeCoroutine<T>(context, uCont) {
- override fun afterResume(state: Any?) = uCont.resumeWith(recoverResult(state, uCont))
-}
diff --git a/kotlinx-coroutines-core/js/src/CoroutineExceptionHandlerImpl.kt b/kotlinx-coroutines-core/js/src/CoroutineExceptionHandlerImpl.kt
index 54a65e10..524d4b55 100644
--- a/kotlinx-coroutines-core/js/src/CoroutineExceptionHandlerImpl.kt
+++ b/kotlinx-coroutines-core/js/src/CoroutineExceptionHandlerImpl.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/js/src/Debug.kt b/kotlinx-coroutines-core/js/src/Debug.kt
index 7655b543..7cd9bedd 100644
--- a/kotlinx-coroutines-core/js/src/Debug.kt
+++ b/kotlinx-coroutines-core/js/src/Debug.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/js/src/Dispatchers.kt b/kotlinx-coroutines-core/js/src/Dispatchers.kt
index 8d3bac32..06b938d4 100644
--- a/kotlinx-coroutines-core/js/src/Dispatchers.kt
+++ b/kotlinx-coroutines-core/js/src/Dispatchers.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/js/src/EventLoop.kt b/kotlinx-coroutines-core/js/src/EventLoop.kt
index b3a13641..0039678a 100644
--- a/kotlinx-coroutines-core/js/src/EventLoop.kt
+++ b/kotlinx-coroutines-core/js/src/EventLoop.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/js/src/Exceptions.kt b/kotlinx-coroutines-core/js/src/Exceptions.kt
index 7c76bc6d..c82199a4 100644
--- a/kotlinx-coroutines-core/js/src/Exceptions.kt
+++ b/kotlinx-coroutines-core/js/src/Exceptions.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/js/src/JSDispatcher.kt b/kotlinx-coroutines-core/js/src/JSDispatcher.kt
index 6ad7d41b..e1b3dcd7 100644
--- a/kotlinx-coroutines-core/js/src/JSDispatcher.kt
+++ b/kotlinx-coroutines-core/js/src/JSDispatcher.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/js/src/Promise.kt b/kotlinx-coroutines-core/js/src/Promise.kt
index 336a3883..ab200323 100644
--- a/kotlinx-coroutines-core/js/src/Promise.kt
+++ b/kotlinx-coroutines-core/js/src/Promise.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/js/src/Runnable.kt b/kotlinx-coroutines-core/js/src/Runnable.kt
index b8e6980b..19710f97 100644
--- a/kotlinx-coroutines-core/js/src/Runnable.kt
+++ b/kotlinx-coroutines-core/js/src/Runnable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/js/src/SchedulerTask.kt b/kotlinx-coroutines-core/js/src/SchedulerTask.kt
index c0ecc4f2..29a92cfb 100644
--- a/kotlinx-coroutines-core/js/src/SchedulerTask.kt
+++ b/kotlinx-coroutines-core/js/src/SchedulerTask.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/js/src/Window.kt b/kotlinx-coroutines-core/js/src/Window.kt
index dad0c04b..8284daef 100644
--- a/kotlinx-coroutines-core/js/src/Window.kt
+++ b/kotlinx-coroutines-core/js/src/Window.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/js/src/flow/internal/FlowExceptions.kt b/kotlinx-coroutines-core/js/src/flow/internal/FlowExceptions.kt
index 000395ea..f818bfbb 100644
--- a/kotlinx-coroutines-core/js/src/flow/internal/FlowExceptions.kt
+++ b/kotlinx-coroutines-core/js/src/flow/internal/FlowExceptions.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/js/src/flow/internal/SafeCollector.kt b/kotlinx-coroutines-core/js/src/flow/internal/SafeCollector.kt
index b74b547d..ace633cc 100644
--- a/kotlinx-coroutines-core/js/src/flow/internal/SafeCollector.kt
+++ b/kotlinx-coroutines-core/js/src/flow/internal/SafeCollector.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/js/src/internal/Concurrent.kt b/kotlinx-coroutines-core/js/src/internal/Concurrent.kt
index 0a1b0310..5555137f 100644
--- a/kotlinx-coroutines-core/js/src/internal/Concurrent.kt
+++ b/kotlinx-coroutines-core/js/src/internal/Concurrent.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/js/src/internal/CopyOnWriteList.kt b/kotlinx-coroutines-core/js/src/internal/CopyOnWriteList.kt
index 335e35d3..8f42160b 100644
--- a/kotlinx-coroutines-core/js/src/internal/CopyOnWriteList.kt
+++ b/kotlinx-coroutines-core/js/src/internal/CopyOnWriteList.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/js/src/internal/LinkedList.kt b/kotlinx-coroutines-core/js/src/internal/LinkedList.kt
index f2711f50..b6985057 100644
--- a/kotlinx-coroutines-core/js/src/internal/LinkedList.kt
+++ b/kotlinx-coroutines-core/js/src/internal/LinkedList.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("unused", "NO_EXPLICIT_RETURN_TYPE_IN_API_MODE", "NO_EXPLICIT_VISIBILITY_IN_API_MODE")
diff --git a/kotlinx-coroutines-core/js/src/internal/LocalAtomics.kt b/kotlinx-coroutines-core/js/src/internal/LocalAtomics.kt
index 643fe85d..fffd76c4 100644
--- a/kotlinx-coroutines-core/js/src/internal/LocalAtomics.kt
+++ b/kotlinx-coroutines-core/js/src/internal/LocalAtomics.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/js/src/internal/ProbesSupport.kt b/kotlinx-coroutines-core/js/src/internal/ProbesSupport.kt
index 47d3fdba..a13a141f 100644
--- a/kotlinx-coroutines-core/js/src/internal/ProbesSupport.kt
+++ b/kotlinx-coroutines-core/js/src/internal/ProbesSupport.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/js/src/internal/StackTraceRecovery.kt b/kotlinx-coroutines-core/js/src/internal/StackTraceRecovery.kt
index 06107b8f..234bbcad 100644
--- a/kotlinx-coroutines-core/js/src/internal/StackTraceRecovery.kt
+++ b/kotlinx-coroutines-core/js/src/internal/StackTraceRecovery.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/js/src/internal/Synchronized.kt b/kotlinx-coroutines-core/js/src/internal/Synchronized.kt
index dcbb2021..0911dbe1 100644
--- a/kotlinx-coroutines-core/js/src/internal/Synchronized.kt
+++ b/kotlinx-coroutines-core/js/src/internal/Synchronized.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/js/src/internal/SystemProps.kt b/kotlinx-coroutines-core/js/src/internal/SystemProps.kt
index 4fb334ed..564630f6 100644
--- a/kotlinx-coroutines-core/js/src/internal/SystemProps.kt
+++ b/kotlinx-coroutines-core/js/src/internal/SystemProps.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/js/src/internal/ThreadContext.kt b/kotlinx-coroutines-core/js/src/internal/ThreadContext.kt
index 2370e42f..4a9513ab 100644
--- a/kotlinx-coroutines-core/js/src/internal/ThreadContext.kt
+++ b/kotlinx-coroutines-core/js/src/internal/ThreadContext.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/js/src/internal/ThreadLocal.kt b/kotlinx-coroutines-core/js/src/internal/ThreadLocal.kt
index e1825d67..09f501a4 100644
--- a/kotlinx-coroutines-core/js/src/internal/ThreadLocal.kt
+++ b/kotlinx-coroutines-core/js/src/internal/ThreadLocal.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/jvm/resources/DebugProbesKt.bin b/kotlinx-coroutines-core/jvm/resources/DebugProbesKt.bin
index ea8c9da4..76ee4115 100644
--- a/kotlinx-coroutines-core/jvm/resources/DebugProbesKt.bin
+++ b/kotlinx-coroutines-core/jvm/resources/DebugProbesKt.bin
Binary files differ
diff --git a/kotlinx-coroutines-core/jvm/resources/META-INF/proguard/coroutines.pro b/kotlinx-coroutines-core/jvm/resources/META-INF/proguard/coroutines.pro
index 1a9ae1c7..60c8d612 100644
--- a/kotlinx-coroutines-core/jvm/resources/META-INF/proguard/coroutines.pro
+++ b/kotlinx-coroutines-core/jvm/resources/META-INF/proguard/coroutines.pro
@@ -3,12 +3,12 @@
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
# Most of volatile fields are updated with AFU and should not be mangled
--keepclassmembers class kotlinx.coroutines.** {
+-keepclassmembernames class kotlinx.** {
volatile <fields>;
}
# Same story for the standard library's SafeContinuation that also uses AtomicReferenceFieldUpdater
--keepclassmembers class kotlin.coroutines.SafeContinuation {
+-keepclassmembernames class kotlin.coroutines.SafeContinuation {
volatile <fields>;
}
diff --git a/kotlinx-coroutines-core/jvm/src/Builders.kt b/kotlinx-coroutines-core/jvm/src/Builders.kt
index c1b878ce..e4504ccd 100644
--- a/kotlinx-coroutines-core/jvm/src/Builders.kt
+++ b/kotlinx-coroutines-core/jvm/src/Builders.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@@ -69,7 +69,7 @@ private class BlockingCoroutine<T>(
override fun afterCompletion(state: Any?) {
// wake up blocked thread
if (Thread.currentThread() != blockedThread)
- unpark(blockedThread)
+ LockSupport.unpark(blockedThread)
}
@Suppress("UNCHECKED_CAST")
diff --git a/kotlinx-coroutines-core/jvm/src/CommonPool.kt b/kotlinx-coroutines-core/jvm/src/CommonPool.kt
index 502630b0..22033131 100644
--- a/kotlinx-coroutines-core/jvm/src/CommonPool.kt
+++ b/kotlinx-coroutines-core/jvm/src/CommonPool.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -28,7 +28,7 @@ internal object CommonPool : ExecutorCoroutineDispatcher() {
* Note that until Java 10, if an application is run within a container,
* `Runtime.getRuntime().availableProcessors()` is not aware of container constraints and will return the real number of cores.
*/
- private const val DEFAULT_PARALLELISM_PROPERTY_NAME = "kotlinx.coroutines.default.parallelism"
+ public const val DEFAULT_PARALLELISM_PROPERTY_NAME = "kotlinx.coroutines.default.parallelism"
override val executor: Executor
get() = pool ?: getOrCreatePoolSync()
@@ -62,7 +62,7 @@ internal object CommonPool : ExecutorCoroutineDispatcher() {
?: return createPlainPool() // Fallback to plain thread pool
// Try to use commonPool unless parallelism was explicitly specified or in debug privatePool mode
if (!usePrivatePool && requestedParallelism < 0) {
- Try { fjpClass.getMethod("commonPool").invoke(null) as? ExecutorService }
+ Try { fjpClass.getMethod("commonPool")?.invoke(null) as? ExecutorService }
?.takeIf { isGoodCommonPool(fjpClass, it) }
?.let { return it }
}
diff --git a/kotlinx-coroutines-core/jvm/src/CompletionHandler.kt b/kotlinx-coroutines-core/jvm/src/CompletionHandler.kt
index 4835f796..706f6c49 100644
--- a/kotlinx-coroutines-core/jvm/src/CompletionHandler.kt
+++ b/kotlinx-coroutines-core/jvm/src/CompletionHandler.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/jvm/src/CoroutineContext.kt b/kotlinx-coroutines-core/jvm/src/CoroutineContext.kt
index e91bb9fd..5a69d48a 100644
--- a/kotlinx-coroutines-core/jvm/src/CoroutineContext.kt
+++ b/kotlinx-coroutines-core/jvm/src/CoroutineContext.kt
@@ -1,13 +1,13 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
import kotlinx.coroutines.internal.*
import kotlinx.coroutines.scheduling.*
+import java.util.concurrent.atomic.*
import kotlin.coroutines.*
-import kotlin.coroutines.jvm.internal.CoroutineStackFrame
internal const val COROUTINES_SCHEDULER_PROPERTY_NAME = "kotlinx.coroutines.scheduler"
@@ -48,102 +48,6 @@ internal actual inline fun <T> withCoroutineContext(context: CoroutineContext, c
}
}
-/**
- * Executes a block using a context of a given continuation.
- */
-internal actual inline fun <T> withContinuationContext(continuation: Continuation<*>, countOrElement: Any?, block: () -> T): T {
- val context = continuation.context
- val oldValue = updateThreadContext(context, countOrElement)
- val undispatchedCompletion = if (oldValue !== NO_THREAD_ELEMENTS) {
- // Only if some values were replaced we'll go to the slow path of figuring out where/how to restore them
- continuation.updateUndispatchedCompletion(context, oldValue)
- } else {
- null // fast path -- don't even try to find undispatchedCompletion as there's nothing to restore in the context
- }
- try {
- return block()
- } finally {
- if (undispatchedCompletion == null || undispatchedCompletion.clearThreadContext()) {
- restoreThreadContext(context, oldValue)
- }
- }
-}
-
-internal fun Continuation<*>.updateUndispatchedCompletion(context: CoroutineContext, oldValue: Any?): UndispatchedCoroutine<*>? {
- if (this !is CoroutineStackFrame) return null
- /*
- * Fast-path to detect whether we have unispatched coroutine at all in our stack.
- *
- * Implementation note.
- * If we ever find that stackwalking for thread-locals is way too slow, here is another idea:
- * 1) Store undispatched coroutine right in the `UndispatchedMarker` instance
- * 2) To avoid issues with cross-dispatch boundary, remove `UndispatchedMarker`
- * from the context when creating dispatched coroutine in `withContext`.
- * Another option is to "unmark it" instead of removing to save an allocation.
- * Both options should work, but it requires more careful studying of the performance
- * and, mostly, maintainability impact.
- */
- val potentiallyHasUndispatchedCorotuine = context[UndispatchedMarker] !== null
- if (!potentiallyHasUndispatchedCorotuine) return null
- val completion = undispatchedCompletion()
- completion?.saveThreadContext(context, oldValue)
- return completion
-}
-
-internal tailrec fun CoroutineStackFrame.undispatchedCompletion(): UndispatchedCoroutine<*>? {
- // Find direct completion of this continuation
- val completion: CoroutineStackFrame = when (this) {
- is DispatchedCoroutine<*> -> return null
- else -> callerFrame ?: return null // something else -- not supported
- }
- if (completion is UndispatchedCoroutine<*>) return completion // found UndispatchedCoroutine!
- return completion.undispatchedCompletion() // walk up the call stack with tail call
-}
-
-/**
- * Marker indicating that [UndispatchedCoroutine] exists somewhere up in the stack.
- * Used as a performance optimization to avoid stack walking where it is not nesessary.
- */
-private object UndispatchedMarker: CoroutineContext.Element, CoroutineContext.Key<UndispatchedMarker> {
- override val key: CoroutineContext.Key<*>
- get() = this
-}
-
-// Used by withContext when context changes, but dispatcher stays the same
-internal actual class UndispatchedCoroutine<in T>actual constructor (
- context: CoroutineContext,
- uCont: Continuation<T>
-) : ScopeCoroutine<T>(if (context[UndispatchedMarker] == null) context + UndispatchedMarker else context, uCont) {
-
- private var savedContext: CoroutineContext? = null
- private var savedOldValue: Any? = null
-
- fun saveThreadContext(context: CoroutineContext, oldValue: Any?) {
- savedContext = context
- savedOldValue = oldValue
- }
-
- fun clearThreadContext(): Boolean {
- if (savedContext == null) return false
- savedContext = null
- savedOldValue = null
- return true
- }
-
- override fun afterResume(state: Any?) {
- savedContext?.let { context ->
- restoreThreadContext(context, savedOldValue)
- savedContext = null
- savedOldValue = null
- }
- // resume undispatched -- update context but stay on the same dispatcher
- val result = recoverResult(state, uCont)
- withContinuationContext(uCont, null) {
- uCont.resumeWith(result)
- }
- }
-}
-
internal actual val CoroutineContext.coroutineName: String? get() {
if (!DEBUG) return null
val coroutineId = this[CoroutineId] ?: return null
diff --git a/kotlinx-coroutines-core/jvm/src/CoroutineExceptionHandlerImpl.kt b/kotlinx-coroutines-core/jvm/src/CoroutineExceptionHandlerImpl.kt
index 6d069692..af37e73c 100644
--- a/kotlinx-coroutines-core/jvm/src/CoroutineExceptionHandlerImpl.kt
+++ b/kotlinx-coroutines-core/jvm/src/CoroutineExceptionHandlerImpl.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/jvm/src/Debug.kt b/kotlinx-coroutines-core/jvm/src/Debug.kt
index 911914a0..8108d235 100644
--- a/kotlinx-coroutines-core/jvm/src/Debug.kt
+++ b/kotlinx-coroutines-core/jvm/src/Debug.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// Need InlineOnly for efficient bytecode on Android
diff --git a/kotlinx-coroutines-core/jvm/src/DebugStrings.kt b/kotlinx-coroutines-core/jvm/src/DebugStrings.kt
index 32bd07a7..2ccfebc6 100644
--- a/kotlinx-coroutines-core/jvm/src/DebugStrings.kt
+++ b/kotlinx-coroutines-core/jvm/src/DebugStrings.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt b/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt
index fe020276..787cbf9c 100644
--- a/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt
+++ b/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/jvm/src/Dispatchers.kt b/kotlinx-coroutines-core/jvm/src/Dispatchers.kt
index 25c0fbe9..8033fb38 100644
--- a/kotlinx-coroutines-core/jvm/src/Dispatchers.kt
+++ b/kotlinx-coroutines-core/jvm/src/Dispatchers.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("unused")
@@ -8,6 +8,7 @@ package kotlinx.coroutines
import kotlinx.coroutines.internal.*
import kotlinx.coroutines.scheduling.*
+import java.util.*
import kotlin.coroutines.*
/**
diff --git a/kotlinx-coroutines-core/jvm/src/EventLoop.kt b/kotlinx-coroutines-core/jvm/src/EventLoop.kt
index e49c7dc7..d86f632a 100644
--- a/kotlinx-coroutines-core/jvm/src/EventLoop.kt
+++ b/kotlinx-coroutines-core/jvm/src/EventLoop.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/jvm/src/Exceptions.kt b/kotlinx-coroutines-core/jvm/src/Exceptions.kt
index 007a0c98..0684ce23 100644
--- a/kotlinx-coroutines-core/jvm/src/Exceptions.kt
+++ b/kotlinx-coroutines-core/jvm/src/Exceptions.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("FunctionName")
diff --git a/kotlinx-coroutines-core/jvm/src/Executors.kt b/kotlinx-coroutines-core/jvm/src/Executors.kt
index 394304f2..8ffc22d8 100644
--- a/kotlinx-coroutines-core/jvm/src/Executors.kt
+++ b/kotlinx-coroutines-core/jvm/src/Executors.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/jvm/src/Future.kt b/kotlinx-coroutines-core/jvm/src/Future.kt
index 948ef606..bd16f49a 100644
--- a/kotlinx-coroutines-core/jvm/src/Future.kt
+++ b/kotlinx-coroutines-core/jvm/src/Future.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@@ -20,7 +20,7 @@ import java.util.concurrent.*
*/
@InternalCoroutinesApi
public fun Job.cancelFutureOnCompletion(future: Future<*>): DisposableHandle =
- invokeOnCompletion(handler = CancelFutureOnCompletion(future)) // TODO make it work only on cancellation as well?
+ invokeOnCompletion(handler = CancelFutureOnCompletion(this, future)) // TODO make it work only on cancellation as well?
/**
* Cancels a specified [future] when this job is cancelled.
@@ -33,13 +33,15 @@ public fun CancellableContinuation<*>.cancelFutureOnCancellation(future: Future<
invokeOnCancellation(handler = CancelFutureOnCancel(future))
private class CancelFutureOnCompletion(
+ job: Job,
private val future: Future<*>
-) : JobNode() {
+) : JobNode<Job>(job) {
override fun invoke(cause: Throwable?) {
// Don't interrupt when cancelling future on completion, because no one is going to reset this
// interruption flag and it will cause spurious failures elsewhere
future.cancel(false)
}
+ override fun toString() = "CancelFutureOnCompletion[$future]"
}
private class CancelFutureOnCancel(private val future: Future<*>) : CancelHandler() {
diff --git a/kotlinx-coroutines-core/jvm/src/Interruptible.kt b/kotlinx-coroutines-core/jvm/src/Interruptible.kt
index b873eadf..070aa624 100644
--- a/kotlinx-coroutines-core/jvm/src/Interruptible.kt
+++ b/kotlinx-coroutines-core/jvm/src/Interruptible.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/jvm/src/Runnable.kt b/kotlinx-coroutines-core/jvm/src/Runnable.kt
index 844f9fca..14d01105 100644
--- a/kotlinx-coroutines-core/jvm/src/Runnable.kt
+++ b/kotlinx-coroutines-core/jvm/src/Runnable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/jvm/src/SchedulerTask.kt b/kotlinx-coroutines-core/jvm/src/SchedulerTask.kt
index 6a00f45f..478df822 100644
--- a/kotlinx-coroutines-core/jvm/src/SchedulerTask.kt
+++ b/kotlinx-coroutines-core/jvm/src/SchedulerTask.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt
index 37fd70a2..1fd85110 100644
--- a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt
+++ b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/jvm/src/ThreadPoolDispatcher.kt b/kotlinx-coroutines-core/jvm/src/ThreadPoolDispatcher.kt
index 44a79d42..aa18cd38 100644
--- a/kotlinx-coroutines-core/jvm/src/ThreadPoolDispatcher.kt
+++ b/kotlinx-coroutines-core/jvm/src/ThreadPoolDispatcher.kt
@@ -1,11 +1,13 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
+import kotlinx.coroutines.internal.*
import java.util.concurrent.*
import java.util.concurrent.atomic.AtomicInteger
+import kotlin.coroutines.*
/**
* Creates a coroutine execution context using a single thread with built-in [yield] support.
diff --git a/kotlinx-coroutines-core/jvm/src/TimeSource.kt b/kotlinx-coroutines-core/jvm/src/TimeSource.kt
index 8d6dea2f..4b6fd991 100644
--- a/kotlinx-coroutines-core/jvm/src/TimeSource.kt
+++ b/kotlinx-coroutines-core/jvm/src/TimeSource.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
// Need InlineOnly for efficient bytecode on Android
diff --git a/kotlinx-coroutines-core/jvm/src/channels/Actor.kt b/kotlinx-coroutines-core/jvm/src/channels/Actor.kt
index 0212d740..a9054265 100644
--- a/kotlinx-coroutines-core/jvm/src/channels/Actor.kt
+++ b/kotlinx-coroutines-core/jvm/src/channels/Actor.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
diff --git a/kotlinx-coroutines-core/jvm/src/channels/Channels.kt b/kotlinx-coroutines-core/jvm/src/channels/Channels.kt
index 081a0583..2c949959 100644
--- a/kotlinx-coroutines-core/jvm/src/channels/Channels.kt
+++ b/kotlinx-coroutines-core/jvm/src/channels/Channels.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/kotlinx-coroutines-core/jvm/src/channels/TickerChannels.kt b/kotlinx-coroutines-core/jvm/src/channels/TickerChannels.kt
index 099e70b3..1e6797ac 100644
--- a/kotlinx-coroutines-core/jvm/src/channels/TickerChannels.kt
+++ b/kotlinx-coroutines-core/jvm/src/channels/TickerChannels.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.channels
diff --git a/kotlinx-coroutines-core/jvm/src/debug/AgentPremain.kt b/kotlinx-coroutines-core/jvm/src/debug/AgentPremain.kt
index 8ef0c182..5a1a1ed1 100644
--- a/kotlinx-coroutines-core/jvm/src/debug/AgentPremain.kt
+++ b/kotlinx-coroutines-core/jvm/src/debug/AgentPremain.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.debug
diff --git a/kotlinx-coroutines-core/jvm/src/debug/internal/ConcurrentWeakMap.kt b/kotlinx-coroutines-core/jvm/src/debug/internal/ConcurrentWeakMap.kt
index ffb9c2da..79f024cc 100644
--- a/kotlinx-coroutines-core/jvm/src/debug/internal/ConcurrentWeakMap.kt
+++ b/kotlinx-coroutines-core/jvm/src/debug/internal/ConcurrentWeakMap.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.debug.internal
diff --git a/kotlinx-coroutines-core/jvm/src/debug/internal/DebugCoroutineInfo.kt b/kotlinx-coroutines-core/jvm/src/debug/internal/DebugCoroutineInfo.kt
index 6c353929..9d9fa3fb 100644
--- a/kotlinx-coroutines-core/jvm/src/debug/internal/DebugCoroutineInfo.kt
+++ b/kotlinx-coroutines-core/jvm/src/debug/internal/DebugCoroutineInfo.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.debug.internal
@@ -27,4 +27,4 @@ internal class DebugCoroutineInfo(
public val lastObservedFrame: CoroutineStackFrame? = source.lastObservedFrame // field is used as of 1.4-M3
@get:JvmName("lastObservedStackTrace") // method with this name is used as of 1.4-M3
public val lastObservedStackTrace: List<StackTraceElement> = source.lastObservedStackTrace()
-}
+} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/src/debug/internal/DebugCoroutineInfoImpl.kt b/kotlinx-coroutines-core/jvm/src/debug/internal/DebugCoroutineInfoImpl.kt
index 07b9419f..cf007bb9 100644
--- a/kotlinx-coroutines-core/jvm/src/debug/internal/DebugCoroutineInfoImpl.kt
+++ b/kotlinx-coroutines-core/jvm/src/debug/internal/DebugCoroutineInfoImpl.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.debug.internal
@@ -72,7 +72,7 @@ internal class DebugCoroutineInfoImpl(
private fun creationStackTrace(): List<StackTraceElement> {
val bottom = creationStackBottom ?: return emptyList()
// Skip "Coroutine creation stacktrace" frame
- return sequence { yieldFrames(bottom.callerFrame) }.toList()
+ return sequence<StackTraceElement> { yieldFrames(bottom.callerFrame) }.toList()
}
private tailrec suspend fun SequenceScope<StackTraceElement>.yieldFrames(frame: CoroutineStackFrame?) {
diff --git a/kotlinx-coroutines-core/jvm/src/debug/internal/DebugProbesImpl.kt b/kotlinx-coroutines-core/jvm/src/debug/internal/DebugProbesImpl.kt
index 4c88cc97..83bc02c6 100644
--- a/kotlinx-coroutines-core/jvm/src/debug/internal/DebugProbesImpl.kt
+++ b/kotlinx-coroutines-core/jvm/src/debug/internal/DebugProbesImpl.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.debug.internal
@@ -477,40 +477,33 @@ internal object DebugProbesImpl {
/*
* Trim intervals of internal methods from the stacktrace (bounds are excluded from trimming)
- * E.g. for sequence [e, i1, i2, i3, e, i4, e, i5, i6, i7]
+ * E.g. for sequence [e, i1, i2, i3, e, i4, e, i5, i6, e7]
* output will be [e, i1, i3, e, i4, e, i5, i7]
- *
- * If an interval of internal methods ends in a synthetic method, the outermost non-synthetic method in that
- * interval will also be included.
*/
val result = ArrayList<StackTraceElement>(size - probeIndex + 1)
result += createArtificialFrame(ARTIFICIAL_FRAME_MESSAGE)
- var i = probeIndex + 1
- while (i < size) {
- if (stackTrace[i].isInternalMethod) {
- result += stackTrace[i] // we include the boundary of the span in any case
- // first index past the end of the span of internal methods that starts from `i`
- var j = i + 1
- while (j < size && stackTrace[j].isInternalMethod) {
- ++j
- }
- // index of the last non-synthetic internal methods in this span, or `i` if there are no such methods
- var k = j - 1
- while (k > i && stackTrace[k].fileName == null) {
- k -= 1
- }
- if (k > i && k < j - 1) {
- /* there are synthetic internal methods at the end of this span, but there is a non-synthetic method
- after `i`, so we include it. */
- result += stackTrace[k]
- }
- result += stackTrace[j - 1] // we include the other boundary of this span in any case, too
- i = j
+ var includeInternalFrame = true
+ for (i in (probeIndex + 1) until size - 1) {
+ val element = stackTrace[i]
+ if (!element.isInternalMethod) {
+ includeInternalFrame = true
+ result += element
+ continue
+ }
+
+ if (includeInternalFrame) {
+ result += element
+ includeInternalFrame = false
+ } else if (stackTrace[i + 1].isInternalMethod) {
+ continue
} else {
- result += stackTrace[i]
- ++i
+ result += element
+ includeInternalFrame = true
}
+
}
+
+ result += stackTrace[size - 1]
return result
}
diff --git a/kotlinx-coroutines-core/jvm/src/debug/internal/DebuggerInfo.kt b/kotlinx-coroutines-core/jvm/src/debug/internal/DebuggerInfo.kt
index 0b63cd23..3e9533b0 100644
--- a/kotlinx-coroutines-core/jvm/src/debug/internal/DebuggerInfo.kt
+++ b/kotlinx-coroutines-core/jvm/src/debug/internal/DebuggerInfo.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("UNUSED")
diff --git a/kotlinx-coroutines-core/jvm/src/debug/internal/StackTraceFrame.kt b/kotlinx-coroutines-core/jvm/src/debug/internal/StackTraceFrame.kt
index 40101192..37c60eeb 100644
--- a/kotlinx-coroutines-core/jvm/src/debug/internal/StackTraceFrame.kt
+++ b/kotlinx-coroutines-core/jvm/src/debug/internal/StackTraceFrame.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.debug.internal
@@ -14,4 +14,4 @@ internal class StackTraceFrame(
private val stackTraceElement: StackTraceElement
) : CoroutineStackFrame {
override fun getStackTraceElement(): StackTraceElement = stackTraceElement
-}
+} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/src/flow/internal/FlowExceptions.kt b/kotlinx-coroutines-core/jvm/src/flow/internal/FlowExceptions.kt
index d178060d..4fb958ac 100644
--- a/kotlinx-coroutines-core/jvm/src/flow/internal/FlowExceptions.kt
+++ b/kotlinx-coroutines-core/jvm/src/flow/internal/FlowExceptions.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/jvm/src/flow/internal/SafeCollector.kt b/kotlinx-coroutines-core/jvm/src/flow/internal/SafeCollector.kt
index ea973287..ab42b634 100644
--- a/kotlinx-coroutines-core/jvm/src/flow/internal/SafeCollector.kt
+++ b/kotlinx-coroutines-core/jvm/src/flow/internal/SafeCollector.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
@@ -36,7 +36,7 @@ internal actual class SafeCollector<T> actual constructor(
override val context: CoroutineContext
get() = completion?.context ?: EmptyCoroutineContext
- override fun invokeSuspend(result: Result<Any?>): Any {
+ override fun invokeSuspend(result: Result<Any?>): Any? {
result.onFailure { lastEmissionContext = DownstreamExceptionElement(it) }
completion?.resumeWith(result as Result<Unit>)
return COROUTINE_SUSPENDED
diff --git a/kotlinx-coroutines-core/jvm/src/internal/Concurrent.kt b/kotlinx-coroutines-core/jvm/src/internal/Concurrent.kt
index 050b9747..75b668a3 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/Concurrent.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/Concurrent.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
@@ -9,7 +9,7 @@ import java.util.*
import java.util.concurrent.*
import kotlin.concurrent.withLock as withLockJvm
-internal actual fun <E> subscriberList(): SubscribersList<E> = CopyOnWriteArrayList()
+internal actual fun <E> subscriberList(): SubscribersList<E> = CopyOnWriteArrayList<E>()
@Suppress("ACTUAL_WITHOUT_EXPECT")
internal actual typealias ReentrantLock = java.util.concurrent.locks.ReentrantLock
diff --git a/kotlinx-coroutines-core/jvm/src/internal/ExceptionsConstuctor.kt b/kotlinx-coroutines-core/jvm/src/internal/ExceptionsConstuctor.kt
index 60328ebd..a03163db 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/ExceptionsConstuctor.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/ExceptionsConstuctor.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/jvm/src/internal/FastServiceLoader.kt b/kotlinx-coroutines-core/jvm/src/internal/FastServiceLoader.kt
index e93de2aa..30cd09ef 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/FastServiceLoader.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/FastServiceLoader.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/jvm/src/internal/LocalAtomics.kt b/kotlinx-coroutines-core/jvm/src/internal/LocalAtomics.kt
index 9dda30b5..f508749e 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/LocalAtomics.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/LocalAtomics.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt b/kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt
index caad1e33..97f99781 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/LockFreeLinkedList.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("NO_EXPLICIT_VISIBILITY_IN_API_MODE")
@@ -11,13 +11,13 @@ import kotlinx.coroutines.*
private typealias Node = LockFreeLinkedListNode
@PublishedApi
-internal const val UNDECIDED: Int = 0
+internal const val UNDECIDED = 0
@PublishedApi
-internal const val SUCCESS: Int = 1
+internal const val SUCCESS = 1
@PublishedApi
-internal const val FAILURE: Int = 2
+internal const val FAILURE = 2
@PublishedApi
internal val CONDITION_FALSE: Any = Symbol("CONDITION_FALSE")
@@ -322,7 +322,7 @@ public actual open class LockFreeLinkedListNode {
private val _affectedNode = atomic<Node?>(null)
final override val affectedNode: Node? get() = _affectedNode.value
- final override val originalNext: Node get() = queue
+ final override val originalNext: Node? get() = queue
override fun retry(affected: Node, next: Any): Boolean = next !== queue
diff --git a/kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt b/kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt
index 3102fdfb..5b2b9ff6 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
@@ -35,7 +35,7 @@ internal object MainDispatcherLoader {
).iterator().asSequence().toList()
}
@Suppress("ConstantConditionIf")
- factories.maxByOrNull { it.loadPriority }?.tryCreateDispatcher(factories)
+ factories.maxBy { it.loadPriority }?.tryCreateDispatcher(factories)
?: createMissingDispatcher()
} catch (e: Throwable) {
// Service loader can throw an exception as well
diff --git a/kotlinx-coroutines-core/jvm/src/internal/ProbesSupport.kt b/kotlinx-coroutines-core/jvm/src/internal/ProbesSupport.kt
index 48e01fbe..2f4d1e05 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/ProbesSupport.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/ProbesSupport.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("NOTHING_TO_INLINE", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
diff --git a/kotlinx-coroutines-core/jvm/src/internal/StackTraceRecovery.kt b/kotlinx-coroutines-core/jvm/src/internal/StackTraceRecovery.kt
index 48e8790c..208d3f2e 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/StackTraceRecovery.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/StackTraceRecovery.kt
@@ -1,8 +1,8 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-@file:Suppress("UNCHECKED_CAST")
+@file:Suppress("UNCHECKED_CAST", "NO_EXPLICIT_VISIBILITY_IN_API_MODE")
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/jvm/src/internal/Synchronized.kt b/kotlinx-coroutines-core/jvm/src/internal/Synchronized.kt
index 6284f3a0..2b57b26c 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/Synchronized.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/Synchronized.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/jvm/src/internal/SystemProps.kt b/kotlinx-coroutines-core/jvm/src/internal/SystemProps.kt
index 73853720..bf34c1a9 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/SystemProps.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/SystemProps.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmName("SystemPropsKt")
diff --git a/kotlinx-coroutines-core/jvm/src/internal/ThreadContext.kt b/kotlinx-coroutines-core/jvm/src/internal/ThreadContext.kt
index 8536cef6..9d9d30e4 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/ThreadContext.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/ThreadContext.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
@@ -7,26 +7,17 @@ package kotlinx.coroutines.internal
import kotlinx.coroutines.*
import kotlin.coroutines.*
-@JvmField
-internal val NO_THREAD_ELEMENTS = Symbol("NO_THREAD_ELEMENTS")
+
+private val ZERO = Symbol("ZERO")
// Used when there are >= 2 active elements in the context
-@Suppress("UNCHECKED_CAST")
-private class ThreadState(@JvmField val context: CoroutineContext, n: Int) {
- private val values = arrayOfNulls<Any>(n)
- private val elements = arrayOfNulls<ThreadContextElement<Any?>>(n)
+private class ThreadState(val context: CoroutineContext, n: Int) {
+ private var a = arrayOfNulls<Any>(n)
private var i = 0
- fun append(element: ThreadContextElement<*>, value: Any?) {
- values[i] = value
- elements[i++] = element as ThreadContextElement<Any?>
- }
-
- fun restore(context: CoroutineContext) {
- for (i in elements.indices.reversed()) {
- elements[i]!!.restoreThreadContext(context, values[i])
- }
- }
+ fun append(value: Any?) { a[i++] = value }
+ fun take() = a[i++]
+ fun start() { i = 0 }
}
// Counts ThreadContextElements in the context
@@ -51,7 +42,17 @@ private val findOne =
private val updateState =
fun (state: ThreadState, element: CoroutineContext.Element): ThreadState {
if (element is ThreadContextElement<*>) {
- state.append(element, element.updateThreadContext(state.context))
+ state.append(element.updateThreadContext(state.context))
+ }
+ return state
+ }
+
+// Restores state for all ThreadContextElements in the context from the given ThreadState
+private val restoreState =
+ fun (state: ThreadState, element: CoroutineContext.Element): ThreadState {
+ @Suppress("UNCHECKED_CAST")
+ if (element is ThreadContextElement<*>) {
+ (element as ThreadContextElement<Any?>).restoreThreadContext(state.context, state.take())
}
return state
}
@@ -59,13 +60,12 @@ private val updateState =
internal actual fun threadContextElements(context: CoroutineContext): Any = context.fold(0, countAll)!!
// countOrElement is pre-cached in dispatched continuation
-// returns NO_THREAD_ELEMENTS if the contest does not have any ThreadContextElements
internal fun updateThreadContext(context: CoroutineContext, countOrElement: Any?): Any? {
@Suppress("NAME_SHADOWING")
val countOrElement = countOrElement ?: threadContextElements(context)
@Suppress("IMPLICIT_BOXING_IN_IDENTITY_EQUALS")
return when {
- countOrElement === 0 -> NO_THREAD_ELEMENTS // very fast path when there are no active ThreadContextElements
+ countOrElement === 0 -> ZERO // very fast path when there are no active ThreadContextElements
// ^^^ identity comparison for speed, we know zero always has the same identity
countOrElement is Int -> {
// slow path for multiple active ThreadContextElements, allocates ThreadState for multiple old values
@@ -82,10 +82,11 @@ internal fun updateThreadContext(context: CoroutineContext, countOrElement: Any?
internal fun restoreThreadContext(context: CoroutineContext, oldState: Any?) {
when {
- oldState === NO_THREAD_ELEMENTS -> return // very fast path when there are no ThreadContextElements
+ oldState === ZERO -> return // very fast path when there are no ThreadContextElements
oldState is ThreadState -> {
// slow path with multiple stored ThreadContextElements
- oldState.restore(context)
+ oldState.start()
+ context.fold(oldState, restoreState)
}
else -> {
// fast path for one ThreadContextElement, but need to find it
diff --git a/kotlinx-coroutines-core/jvm/src/internal/ThreadLocal.kt b/kotlinx-coroutines-core/jvm/src/internal/ThreadLocal.kt
index 0207334a..ff0970a2 100644
--- a/kotlinx-coroutines-core/jvm/src/internal/ThreadLocal.kt
+++ b/kotlinx-coroutines-core/jvm/src/internal/ThreadLocal.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/jvm/src/scheduling/CoroutineScheduler.kt b/kotlinx-coroutines-core/jvm/src/scheduling/CoroutineScheduler.kt
index 84d9d9f8..62cf80f7 100644
--- a/kotlinx-coroutines-core/jvm/src/scheduling/CoroutineScheduler.kt
+++ b/kotlinx-coroutines-core/jvm/src/scheduling/CoroutineScheduler.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.scheduling
@@ -146,7 +146,7 @@ internal class CoroutineScheduler(
*
* Note, [newIndex] can be zero for the worker that is being terminated (removed from [workers]).
*/
- fun parkedWorkersStackTopUpdate(worker: Worker, oldIndex: Int, newIndex: Int) {
+ internal fun parkedWorkersStackTopUpdate(worker: Worker, oldIndex: Int, newIndex: Int) {
parkedWorkersStack.loop { top ->
val index = (top and PARKED_INDEX_MASK).toInt()
val updVersion = (top + PARKED_VERSION_INC) and PARKED_VERSION_MASK
@@ -169,12 +169,12 @@ internal class CoroutineScheduler(
* It does nothing is this worker is already physically linked to the stack.
* This method is invoked only from the worker thread itself.
* This invocation always precedes [LockSupport.parkNanos].
- * See [Worker.tryPark].
+ * See [Worker.doPark].
*
* Returns `true` if worker was added to the stack by this invocation, `false` if it was already
* registered in the stack.
*/
- fun parkedWorkersStackPush(worker: Worker): Boolean {
+ internal fun parkedWorkersStackPush(worker: Worker): Boolean {
if (worker.nextParkedWorker !== NOT_IN_STACK) return false // already in stack, bail out
/*
* The below loop can be entered only if this worker was not in the stack and, since no other thread
@@ -403,7 +403,7 @@ internal class CoroutineScheduler(
}
}
- fun createTask(block: Runnable, taskContext: TaskContext): Task {
+ internal fun createTask(block: Runnable, taskContext: TaskContext): Task {
val nanoTime = schedulerTimeSource.nanoTime()
if (block is Task) {
block.submissionTime = nanoTime
@@ -422,7 +422,7 @@ internal class CoroutineScheduler(
tryUnpark() // Try unpark again in case there was race between permit release and parking
}
- fun signalCpuWork() {
+ internal fun signalCpuWork() {
if (tryUnpark()) return
if (tryCreateWorker()) return
tryUnpark()
@@ -654,7 +654,7 @@ internal class CoroutineScheduler(
* Releases CPU token if worker has any and changes state to [newState].
* Returns `true` if CPU permit was returned to the pool
*/
- fun tryReleaseCpu(newState: WorkerState): Boolean {
+ internal fun tryReleaseCpu(newState: WorkerState): Boolean {
val previousState = state
val hadCpu = previousState == WorkerState.CPU_ACQUIRED
if (hadCpu) releaseCpuPermit()
@@ -721,19 +721,7 @@ internal class CoroutineScheduler(
}
assert { localQueue.size == 0 }
workerCtl.value = PARKED // Update value once
- /*
- * inStack() prevents spurious wakeups, while workerCtl.value == PARKED
- * prevents the following race:
- *
- * - T2 scans the queue, adds itself to the stack, goes to rescan
- * - T2 suspends in 'workerCtl.value = PARKED' line
- * - T1 pops T2 from the stack, claims workerCtl, suspends
- * - T2 fails 'while (inStack())' check, goes to full rescan
- * - T2 adds itself to the stack, parks
- * - T1 unparks T2, bails out with success
- * - T2 unparks and loops in 'while (inStack())'
- */
- while (inStack() && workerCtl.value == PARKED) { // Prevent spurious wakeups
+ while (inStack()) { // Prevent spurious wakeups
if (isTerminated || state == WorkerState.TERMINATED) break
tryReleaseCpu(WorkerState.PARKING)
interrupted() // Cleanup interruptions
@@ -774,7 +762,7 @@ internal class CoroutineScheduler(
* Marsaglia xorshift RNG with period 2^32-1 for work stealing purposes.
* ThreadLocalRandom cannot be used to support Android and ThreadLocal<Random> is up to 15% slower on Ktor benchmarks
*/
- fun nextInt(upperBound: Int): Int {
+ internal fun nextInt(upperBound: Int): Int {
var r = rngState
r = r xor (r shl 13)
r = r xor (r shr 17)
diff --git a/kotlinx-coroutines-core/jvm/src/scheduling/Dispatcher.kt b/kotlinx-coroutines-core/jvm/src/scheduling/Dispatcher.kt
index 7227b07c..202c6e1d 100644
--- a/kotlinx-coroutines-core/jvm/src/scheduling/Dispatcher.kt
+++ b/kotlinx-coroutines-core/jvm/src/scheduling/Dispatcher.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.scheduling
diff --git a/kotlinx-coroutines-core/jvm/src/scheduling/Tasks.kt b/kotlinx-coroutines-core/jvm/src/scheduling/Tasks.kt
index da867c98..a317b975 100644
--- a/kotlinx-coroutines-core/jvm/src/scheduling/Tasks.kt
+++ b/kotlinx-coroutines-core/jvm/src/scheduling/Tasks.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.scheduling
@@ -52,7 +52,7 @@ internal val IDLE_WORKER_KEEP_ALIVE_NS = TimeUnit.SECONDS.toNanos(
)
@JvmField
-internal var schedulerTimeSource: SchedulerTimeSource = NanoTimeSource
+internal var schedulerTimeSource: TimeSource = NanoTimeSource
/**
* Marker indicating that task is CPU-bound and will not block
@@ -108,11 +108,10 @@ internal class TaskImpl(
// Open for tests
internal class GlobalQueue : LockFreeTaskQueue<Task>(singleConsumer = false)
-// Was previously TimeSource, renamed due to KT-42625 and KT-23727
-internal abstract class SchedulerTimeSource {
+internal abstract class TimeSource {
abstract fun nanoTime(): Long
}
-internal object NanoTimeSource : SchedulerTimeSource() {
+internal object NanoTimeSource : TimeSource() {
override fun nanoTime() = System.nanoTime()
}
diff --git a/kotlinx-coroutines-core/jvm/src/scheduling/WorkQueue.kt b/kotlinx-coroutines-core/jvm/src/scheduling/WorkQueue.kt
index 6a9a8a5a..354b3a1b 100644
--- a/kotlinx-coroutines-core/jvm/src/scheduling/WorkQueue.kt
+++ b/kotlinx-coroutines-core/jvm/src/scheduling/WorkQueue.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.scheduling
diff --git a/kotlinx-coroutines-core/jvm/src/test_/TestCoroutineContext.kt b/kotlinx-coroutines-core/jvm/src/test_/TestCoroutineContext.kt
index 8526ca21..649c9537 100644
--- a/kotlinx-coroutines-core/jvm/src/test_/TestCoroutineContext.kt
+++ b/kotlinx-coroutines-core/jvm/src/test_/TestCoroutineContext.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.test
diff --git a/kotlinx-coroutines-core/jvm/test/AbstractLincheckTest.kt b/kotlinx-coroutines-core/jvm/test/AbstractLincheckTest.kt
deleted file mode 100644
index 5ba7acf9..00000000
--- a/kotlinx-coroutines-core/jvm/test/AbstractLincheckTest.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-package kotlinx.coroutines
-
-import org.jetbrains.kotlinx.lincheck.*
-import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.*
-import org.jetbrains.kotlinx.lincheck.strategy.stress.*
-import org.jetbrains.kotlinx.lincheck.verifier.*
-import org.junit.*
-
-abstract class AbstractLincheckTest : VerifierState() {
- open fun <O: Options<O, *>> O.customize(isStressTest: Boolean): O = this
- open fun ModelCheckingOptions.customize(isStressTest: Boolean): ModelCheckingOptions = this
- open fun StressOptions.customize(isStressTest: Boolean): StressOptions = this
-
- @Test
- fun modelCheckingTest() = ModelCheckingOptions()
- .iterations(if (isStressTest) 100 else 20)
- .invocationsPerIteration(if (isStressTest) 10_000 else 1_000)
- .commonConfiguration()
- .customize(isStressTest)
- .check(this::class)
-
- @Test
- fun stressTest() = StressOptions()
- .iterations(if (isStressTest) 100 else 20)
- .invocationsPerIteration(if (isStressTest) 10_000 else 1_000)
- .commonConfiguration()
- .customize(isStressTest)
- .check(this::class)
-
- private fun <O : Options<O, *>> O.commonConfiguration(): O = this
- .actorsBefore(if (isStressTest) 3 else 1)
- .threads(3)
- .actorsPerThread(if (isStressTest) 4 else 2)
- .actorsAfter(if (isStressTest) 3 else 0)
- .customize(isStressTest)
-
- override fun extractState(): Any = error("Not implemented")
-} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/test/LCStressOptionsDefault.kt b/kotlinx-coroutines-core/jvm/test/LCStressOptionsDefault.kt
new file mode 100644
index 00000000..62ded9f9
--- /dev/null
+++ b/kotlinx-coroutines-core/jvm/test/LCStressOptionsDefault.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+package kotlinx.coroutines
+
+import org.jetbrains.kotlinx.lincheck.*
+import org.jetbrains.kotlinx.lincheck.strategy.stress.*
+import kotlin.reflect.*
+
+class LCStressOptionsDefault : StressOptions() {
+ init {
+ iterations(100 * stressTestMultiplierCbrt)
+ invocationsPerIteration(1000 * stressTestMultiplierCbrt)
+ actorsBefore(if (isStressTest) 3 else 0)
+ threads(3)
+ actorsPerThread(if (isStressTest) 3 else 2)
+ }
+}
+
+fun Options<*,*>.check(testClass: KClass<*>) = LinChecker.check(testClass.java, this) \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/test/ThreadContextElementRestoreTest.kt b/kotlinx-coroutines-core/jvm/test/ThreadContextElementRestoreTest.kt
deleted file mode 100644
index e2ab4d72..00000000
--- a/kotlinx-coroutines-core/jvm/test/ThreadContextElementRestoreTest.kt
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines
-
-import org.junit.Test
-import kotlin.coroutines.*
-import kotlin.test.*
-
-class ThreadContextElementRestoreTest : TestBase() {
- private val tl = ThreadLocal<String?>()
-
- // Checks that ThreadLocal context is properly restored after executing the given block inside
- // withContext(tl.asContextElement("OK")) code running in different outer contexts
- private inline fun check(crossinline block: suspend () -> Unit) = runTest {
- val mainDispatcher = coroutineContext[ContinuationInterceptor] as CoroutineDispatcher
- // Scenario #1: withContext(ThreadLocal) direct from runTest
- withContext(tl.asContextElement("OK")) {
- block()
- assertEquals("OK", tl.get())
- }
- assertEquals(null, tl.get())
- // Scenario #2: withContext(ThreadLocal) from coroutineScope
- coroutineScope {
- withContext(tl.asContextElement("OK")) {
- block()
- assertEquals("OK", tl.get())
- }
- assertEquals(null, tl.get())
- }
- // Scenario #3: withContext(ThreadLocal) from undispatched withContext
- withContext(CoroutineName("NAME")) {
- withContext(tl.asContextElement("OK")) {
- block()
- assertEquals("OK", tl.get())
- }
- assertEquals(null, tl.get())
- }
- // Scenario #4: withContext(ThreadLocal) from dispatched withContext
- withContext(wrapperDispatcher()) {
- withContext(tl.asContextElement("OK")) {
- block()
- assertEquals("OK", tl.get())
- }
- assertEquals(null, tl.get())
- }
- // Scenario #5: withContext(ThreadLocal) from withContext(ThreadLocal)
- withContext(tl.asContextElement(null)) {
- withContext(tl.asContextElement("OK")) {
- block()
- assertEquals("OK", tl.get())
- }
- assertEquals(null, tl.get())
- }
- // Scenario #6: withContext(ThreadLocal) from withTimeout
- withTimeout(1000) {
- withContext(tl.asContextElement("OK")) {
- block()
- assertEquals("OK", tl.get())
- }
- assertEquals(null, tl.get())
- }
- // Scenario #7: withContext(ThreadLocal) from withContext(Unconfined)
- withContext(Dispatchers.Unconfined) {
- withContext(tl.asContextElement("OK")) {
- block()
- assertEquals("OK", tl.get())
- }
- assertEquals(null, tl.get())
- }
- // Scenario #8: withContext(ThreadLocal) from withContext(Default)
- withContext(Dispatchers.Default) {
- withContext(tl.asContextElement("OK")) {
- block()
- assertEquals("OK", tl.get())
- }
- assertEquals(null, tl.get())
- }
- // Scenario #9: withContext(ThreadLocal) from withContext(mainDispatcher)
- withContext(mainDispatcher) {
- withContext(tl.asContextElement("OK")) {
- block()
- assertEquals("OK", tl.get())
- }
- assertEquals(null, tl.get())
- }
- }
-
- @Test
- fun testSimpleNoSuspend() =
- check {}
-
- @Test
- fun testSimpleDelay() = check {
- delay(1)
- }
-
- @Test
- fun testSimpleYield() = check {
- yield()
- }
-
- private suspend fun deepDelay() {
- deepDelay2(); deepDelay2()
- }
-
- private suspend fun deepDelay2() {
- delay(1); delay(1)
- }
-
- @Test
- fun testDeepDelay() = check {
- deepDelay()
- }
-
- private suspend fun deepYield() {
- deepYield2(); deepYield2()
- }
-
- private suspend fun deepYield2() {
- yield(); yield()
- }
-
- @Test
- fun testDeepYield() = check {
- deepYield()
- }
-
- @Test
- fun testCoroutineScopeDelay() = check {
- coroutineScope {
- delay(1)
- }
- }
-
- @Test
- fun testCoroutineScopeYield() = check {
- coroutineScope {
- yield()
- }
- }
-
- @Test
- fun testWithContextUndispatchedDelay() = check {
- withContext(CoroutineName("INNER")) {
- delay(1)
- }
- }
-
- @Test
- fun testWithContextUndispatchedYield() = check {
- withContext(CoroutineName("INNER")) {
- yield()
- }
- }
-
- @Test
- fun testWithContextDispatchedDelay() = check {
- withContext(wrapperDispatcher()) {
- delay(1)
- }
- }
-
- @Test
- fun testWithContextDispatchedYield() = check {
- withContext(wrapperDispatcher()) {
- yield()
- }
- }
-
- @Test
- fun testWithTimeoutDelay() = check {
- withTimeout(1000) {
- delay(1)
- }
- }
-
- @Test
- fun testWithTimeoutYield() = check {
- withTimeout(1000) {
- yield()
- }
- }
-
- @Test
- fun testWithUnconfinedContextDelay() = check {
- withContext(Dispatchers.Unconfined) {
- delay(1)
- }
- }
- @Test
- fun testWithUnconfinedContextYield() = check {
- withContext(Dispatchers.Unconfined) {
- yield()
- }
- }
-}
diff --git a/kotlinx-coroutines-core/jvm/test/ThreadContextOrderTest.kt b/kotlinx-coroutines-core/jvm/test/ThreadContextOrderTest.kt
deleted file mode 100644
index 49f4a12e..00000000
--- a/kotlinx-coroutines-core/jvm/test/ThreadContextOrderTest.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package kotlinx.coroutines
-
-import kotlinx.coroutines.internal.*
-import org.junit.Test
-import kotlin.coroutines.*
-import kotlin.test.*
-
-class ThreadContextOrderTest : TestBase() {
- /*
- * The test verifies that two thread context elements are correctly nested:
- * The restoration order is the reverse of update order.
- */
- private val transactionalContext = ThreadLocal<String>()
- private val loggingContext = ThreadLocal<String>()
-
- private val transactionalElement = object : ThreadContextElement<String> {
- override val key = ThreadLocalKey(transactionalContext)
-
- override fun updateThreadContext(context: CoroutineContext): String {
- assertEquals("test", loggingContext.get())
- val previous = transactionalContext.get()
- transactionalContext.set("tr coroutine")
- return previous
- }
-
- override fun restoreThreadContext(context: CoroutineContext, oldState: String) {
- assertEquals("test", loggingContext.get())
- assertEquals("tr coroutine", transactionalContext.get())
- transactionalContext.set(oldState)
- }
- }
-
- private val loggingElement = object : ThreadContextElement<String> {
- override val key = ThreadLocalKey(loggingContext)
-
- override fun updateThreadContext(context: CoroutineContext): String {
- val previous = loggingContext.get()
- loggingContext.set("log coroutine")
- return previous
- }
-
- override fun restoreThreadContext(context: CoroutineContext, oldState: String) {
- assertEquals("log coroutine", loggingContext.get())
- assertEquals("tr coroutine", transactionalContext.get())
- loggingContext.set(oldState)
- }
- }
-
- @Test
- fun testCorrectOrder() = runTest {
- transactionalContext.set("test")
- loggingContext.set("test")
- launch(transactionalElement + loggingElement) {
- assertEquals("log coroutine", loggingContext.get())
- assertEquals("tr coroutine", transactionalContext.get())
- }
- assertEquals("test", loggingContext.get())
- assertEquals("test", transactionalContext.get())
-
- }
-}
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt
index f04b100a..15e12614 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt
@@ -2,7 +2,7 @@
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-// This file was automatically generated from coroutines-basics.md by Knit tool. Do not edit.
+// This file was automatically generated from basics.md by Knit tool. Do not edit.
package kotlinx.coroutines.guide.exampleBasic01
import kotlinx.coroutines.*
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt
index bfece26b..4f178ca6 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt
@@ -2,7 +2,7 @@
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-// This file was automatically generated from coroutines-basics.md by Knit tool. Do not edit.
+// This file was automatically generated from basics.md by Knit tool. Do not edit.
package kotlinx.coroutines.guide.exampleBasic02
import kotlinx.coroutines.*
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt
index 8541f604..f80113c5 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt
@@ -2,7 +2,7 @@
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-// This file was automatically generated from coroutines-basics.md by Knit tool. Do not edit.
+// This file was automatically generated from basics.md by Knit tool. Do not edit.
package kotlinx.coroutines.guide.exampleBasic03
import kotlinx.coroutines.*
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt
index 69f82771..33c928a0 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt
@@ -2,7 +2,7 @@
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-// This file was automatically generated from coroutines-basics.md by Knit tool. Do not edit.
+// This file was automatically generated from basics.md by Knit tool. Do not edit.
package kotlinx.coroutines.guide.exampleBasic04
import kotlinx.coroutines.*
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt
index 9d530b5f..52b490d2 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt
@@ -2,7 +2,7 @@
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-// This file was automatically generated from coroutines-basics.md by Knit tool. Do not edit.
+// This file was automatically generated from basics.md by Knit tool. Do not edit.
package kotlinx.coroutines.guide.exampleBasic05
import kotlinx.coroutines.*
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt
index b53d3b89..a1b5bc5f 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt
@@ -2,7 +2,7 @@
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-// This file was automatically generated from coroutines-basics.md by Knit tool. Do not edit.
+// This file was automatically generated from basics.md by Knit tool. Do not edit.
package kotlinx.coroutines.guide.exampleBasic06
import kotlinx.coroutines.*
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt
index cd854ce8..32c02b86 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt
@@ -2,7 +2,7 @@
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-// This file was automatically generated from coroutines-basics.md by Knit tool. Do not edit.
+// This file was automatically generated from basics.md by Knit tool. Do not edit.
package kotlinx.coroutines.guide.exampleBasic07
import kotlinx.coroutines.*
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-08.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-08.kt
index 0a346e0b..bb7786f2 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-08.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-08.kt
@@ -2,7 +2,7 @@
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-// This file was automatically generated from coroutines-basics.md by Knit tool. Do not edit.
+// This file was automatically generated from basics.md by Knit tool. Do not edit.
package kotlinx.coroutines.guide.exampleBasic08
import kotlinx.coroutines.*
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-basic-09.kt b/kotlinx-coroutines-core/jvm/test/guide/example-basic-09.kt
index c9783ee5..9f998b52 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-basic-09.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-basic-09.kt
@@ -2,7 +2,7 @@
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-// This file was automatically generated from coroutines-basics.md by Knit tool. Do not edit.
+// This file was automatically generated from basics.md by Knit tool. Do not edit.
package kotlinx.coroutines.guide.exampleBasic09
import kotlinx.coroutines.*
diff --git a/kotlinx-coroutines-core/jvm/test/guide/test/BasicsGuideTest.kt b/kotlinx-coroutines-core/jvm/test/guide/test/BasicsGuideTest.kt
index 765cd0b9..ea5003b0 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/test/BasicsGuideTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/test/BasicsGuideTest.kt
@@ -2,7 +2,7 @@
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-// This file was automatically generated from coroutines-basics.md by Knit tool. Do not edit.
+// This file was automatically generated from basics.md by Knit tool. Do not edit.
package kotlinx.coroutines.guide.test
import kotlinx.coroutines.knit.*
diff --git a/kotlinx-coroutines-core/jvm/test/lincheck/SemaphoreLincheckTest.kt b/kotlinx-coroutines-core/jvm/test/lincheck/SemaphoreLincheckTest.kt
deleted file mode 100644
index 84ce773c..00000000
--- a/kotlinx-coroutines-core/jvm/test/lincheck/SemaphoreLincheckTest.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-@file:Suppress("unused")
-package kotlinx.coroutines.lincheck
-
-import kotlinx.coroutines.*
-import kotlinx.coroutines.sync.*
-import org.jetbrains.kotlinx.lincheck.*
-import org.jetbrains.kotlinx.lincheck.annotations.Operation
-import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.*
-
-abstract class SemaphoreLincheckTestBase(permits: Int) : AbstractLincheckTest() {
- private val semaphore = Semaphore(permits)
-
- @Operation
- fun tryAcquire() = semaphore.tryAcquire()
-
- @Operation(promptCancellation = true)
- suspend fun acquire() = semaphore.acquire()
-
- @Operation(handleExceptionsAsResult = [IllegalStateException::class])
- fun release() = semaphore.release()
-
- override fun <O : Options<O, *>> O.customize(isStressTest: Boolean): O =
- actorsBefore(0)
-
- override fun extractState() = semaphore.availablePermits
-
- override fun ModelCheckingOptions.customize(isStressTest: Boolean) =
- checkObstructionFreedom()
-}
-
-class Semaphore1LincheckTest : SemaphoreLincheckTestBase(1)
-class Semaphore2LincheckTest : SemaphoreLincheckTestBase(2) \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/test/lincheck/ChannelsLincheckTest.kt b/kotlinx-coroutines-core/jvm/test/linearizability/ChannelsLCStressTest.kt
index fbd5c0d8..8836fdc7 100644
--- a/kotlinx-coroutines-core/jvm/test/lincheck/ChannelsLincheckTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/linearizability/ChannelsLCStressTest.kt
@@ -3,7 +3,7 @@
*/
@file:Suppress("unused")
-package kotlinx.coroutines.lincheck
+package kotlinx.coroutines.linearizability
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
@@ -11,37 +11,37 @@ import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
import kotlinx.coroutines.channels.Channel.Factory.RENDEZVOUS
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
import kotlinx.coroutines.selects.*
-import org.jetbrains.kotlinx.lincheck.*
import org.jetbrains.kotlinx.lincheck.annotations.*
import org.jetbrains.kotlinx.lincheck.annotations.Operation
import org.jetbrains.kotlinx.lincheck.paramgen.*
import org.jetbrains.kotlinx.lincheck.verifier.*
+import org.junit.*
-class RendezvousChannelLincheckTest : ChannelLincheckTestBase(
+class RendezvousChannelLCStressTest : ChannelLCStressTestBase(
c = Channel(RENDEZVOUS),
sequentialSpecification = SequentialRendezvousChannel::class.java
)
class SequentialRendezvousChannel : SequentialIntChannelBase(RENDEZVOUS)
-class Array1ChannelLincheckTest : ChannelLincheckTestBase(
+class Array1ChannelLCStressTest : ChannelLCStressTestBase(
c = Channel(1),
sequentialSpecification = SequentialArray1RendezvousChannel::class.java
)
class SequentialArray1RendezvousChannel : SequentialIntChannelBase(1)
-class Array2ChannelLincheckTest : ChannelLincheckTestBase(
+class Array2ChannelLCStressTest : ChannelLCStressTestBase(
c = Channel(2),
sequentialSpecification = SequentialArray2RendezvousChannel::class.java
)
class SequentialArray2RendezvousChannel : SequentialIntChannelBase(2)
-class UnlimitedChannelLincheckTest : ChannelLincheckTestBase(
+class UnlimitedChannelLCStressTest : ChannelLCStressTestBase(
c = Channel(UNLIMITED),
sequentialSpecification = SequentialUnlimitedChannel::class.java
)
class SequentialUnlimitedChannel : SequentialIntChannelBase(UNLIMITED)
-class ConflatedChannelLincheckTest : ChannelLincheckTestBase(
+class ConflatedChannelLCStressTest : ChannelLCStressTestBase(
c = Channel(CONFLATED),
sequentialSpecification = SequentialConflatedChannel::class.java
)
@@ -51,11 +51,8 @@ class SequentialConflatedChannel : SequentialIntChannelBase(CONFLATED)
Param(name = "value", gen = IntGen::class, conf = "1:5"),
Param(name = "closeToken", gen = IntGen::class, conf = "1:3")
)
-abstract class ChannelLincheckTestBase(
- private val c: Channel<Int>,
- private val sequentialSpecification: Class<*>
-) : AbstractLincheckTest() {
- @Operation(promptCancellation = true)
+abstract class ChannelLCStressTestBase(private val c: Channel<Int>, private val sequentialSpecification: Class<*>) {
+ @Operation
suspend fun send(@Param(name = "value") value: Int): Any = try {
c.send(value)
} catch (e: NumberedCancellationException) {
@@ -77,7 +74,7 @@ abstract class ChannelLincheckTestBase(
e.testResult
}
- @Operation(promptCancellation = true)
+ @Operation
suspend fun receive(): Any = try {
c.receive()
} catch (e: NumberedCancellationException) {
@@ -99,7 +96,7 @@ abstract class ChannelLincheckTestBase(
e.testResult
}
- @Operation(causesBlocking = true)
+ @Operation
fun close(@Param(name = "closeToken") token: Int): Boolean = c.close(NumberedCancellationException(token))
// TODO: this operation should be (and can be!) linearizable, but is not
@@ -116,8 +113,11 @@ abstract class ChannelLincheckTestBase(
// @Operation
fun isEmpty() = c.isEmpty
- override fun <O : Options<O, *>> O.customize(isStressTest: Boolean): O =
- actorsBefore(0).sequentialSpecification(sequentialSpecification)
+ @Test
+ fun test() = LCStressOptionsDefault()
+ .actorsBefore(0)
+ .sequentialSpecification(sequentialSpecification)
+ .check(this::class)
}
private class NumberedCancellationException(number: Int) : CancellationException() {
diff --git a/kotlinx-coroutines-core/jvm/test/lincheck/LockFreeListLincheckTest.kt b/kotlinx-coroutines-core/jvm/test/linearizability/LockFreeListLCStressTest.kt
index 4f1bb6ad..5f91c640 100644
--- a/kotlinx-coroutines-core/jvm/test/lincheck/LockFreeListLincheckTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/linearizability/LockFreeListLCStressTest.kt
@@ -3,17 +3,18 @@
*/
@file:Suppress("unused")
-package kotlinx.coroutines.lincheck
+package kotlinx.coroutines.linearizability
import kotlinx.coroutines.*
import kotlinx.coroutines.internal.*
import org.jetbrains.kotlinx.lincheck.annotations.*
import org.jetbrains.kotlinx.lincheck.annotations.Operation
import org.jetbrains.kotlinx.lincheck.paramgen.*
-import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.*
+import org.jetbrains.kotlinx.lincheck.verifier.*
+import kotlin.test.*
@Param(name = "value", gen = IntGen::class, conf = "1:5")
-class LockFreeListLincheckTest : AbstractLincheckTest() {
+class LockFreeListLCStressTest : VerifierState() {
class Node(val value: Int): LockFreeLinkedListNode()
private val q: LockFreeLinkedListHead = LockFreeLinkedListHead()
@@ -42,12 +43,12 @@ class LockFreeListLincheckTest : AbstractLincheckTest() {
private fun Any.isSame(value: Int) = this is Node && this.value == value
+ @Test
+ fun testAddRemoveLinearizability() = LCStressOptionsDefault().check(this::class)
+
override fun extractState(): Any {
val elements = ArrayList<Int>()
q.forEach<Node> { elements.add(it.value) }
return elements
}
-
- override fun ModelCheckingOptions.customize(isStressTest: Boolean) =
- checkObstructionFreedom()
} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/test/lincheck/LockFreeTaskQueueLincheckTest.kt b/kotlinx-coroutines-core/jvm/test/linearizability/LockFreeTaskQueueLCStressTest.kt
index 2a9164e1..de494cc1 100644
--- a/kotlinx-coroutines-core/jvm/test/lincheck/LockFreeTaskQueueLincheckTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/linearizability/LockFreeTaskQueueLCStressTest.kt
@@ -3,21 +3,19 @@
*/
@file:Suppress("unused")
-package kotlinx.coroutines.lincheck
+package kotlinx.coroutines.linearizability
import kotlinx.coroutines.*
import kotlinx.coroutines.internal.*
-import org.jetbrains.kotlinx.lincheck.*
import org.jetbrains.kotlinx.lincheck.annotations.*
import org.jetbrains.kotlinx.lincheck.annotations.Operation
import org.jetbrains.kotlinx.lincheck.paramgen.*
-import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.*
+import org.jetbrains.kotlinx.lincheck.verifier.*
import org.jetbrains.kotlinx.lincheck.verifier.quiescent.*
+import kotlin.test.*
@Param(name = "value", gen = IntGen::class, conf = "1:3")
-internal abstract class AbstractLockFreeTaskQueueWithoutRemoveLincheckTest(
- val singleConsumer: Boolean
-) : AbstractLincheckTest() {
+internal abstract class AbstractLockFreeTaskQueueWithoutRemoveLCStressTest protected constructor(singleConsumer: Boolean) : VerifierState() {
@JvmField
protected val q = LockFreeTaskQueue<Int>(singleConsumer = singleConsumer)
@@ -27,24 +25,20 @@ internal abstract class AbstractLockFreeTaskQueueWithoutRemoveLincheckTest(
@Operation
fun addLast(@Param(name = "value") value: Int) = q.addLast(value)
- override fun <O : Options<O, *>> O.customize(isStressTest: Boolean): O =
- verifier(QuiescentConsistencyVerifier::class.java)
+ @QuiescentConsistent
+ @Operation(group = "consumer")
+ fun removeFirstOrNull() = q.removeFirstOrNull()
override fun extractState() = q.map { it } to q.isClosed()
- override fun ModelCheckingOptions.customize(isStressTest: Boolean) =
- checkObstructionFreedom()
+ @Test
+ fun testWithRemoveForQuiescentConsistency() = LCStressOptionsDefault()
+ .verifier(QuiescentConsistencyVerifier::class.java)
+ .check(this::class)
}
-internal class MCLockFreeTaskQueueWithRemoveLincheckTest : AbstractLockFreeTaskQueueWithoutRemoveLincheckTest(singleConsumer = false) {
- @QuiescentConsistent
- @Operation(blocking = true)
- fun removeFirstOrNull() = q.removeFirstOrNull()
-}
+@OpGroupConfig(name = "consumer", nonParallel = false)
+internal class MCLockFreeTaskQueueWithRemoveLCStressTest : AbstractLockFreeTaskQueueWithoutRemoveLCStressTest(singleConsumer = false)
@OpGroupConfig(name = "consumer", nonParallel = true)
-internal class SCLockFreeTaskQueueWithRemoveLincheckTest : AbstractLockFreeTaskQueueWithoutRemoveLincheckTest(singleConsumer = true) {
- @QuiescentConsistent
- @Operation(group = "consumer")
- fun removeFirstOrNull() = q.removeFirstOrNull()
-} \ No newline at end of file
+internal class SCLockFreeTaskQueueWithRemoveLCStressTest : AbstractLockFreeTaskQueueWithoutRemoveLCStressTest(singleConsumer = true) \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/test/lincheck/MutexLincheckTest.kt b/kotlinx-coroutines-core/jvm/test/linearizability/MutexLCStressTest.kt
index 6e350660..9542b5d8 100644
--- a/kotlinx-coroutines-core/jvm/test/lincheck/MutexLincheckTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/linearizability/MutexLCStressTest.kt
@@ -2,31 +2,30 @@
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("unused")
-package kotlinx.coroutines.lincheck
+package kotlinx.coroutines.linearizability
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
-import org.jetbrains.kotlinx.lincheck.*
import org.jetbrains.kotlinx.lincheck.annotations.Operation
-import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.*
+import org.jetbrains.kotlinx.lincheck.verifier.*
+import org.junit.*
-class MutexLincheckTest : AbstractLincheckTest() {
+class MutexLCStressTest : VerifierState() {
private val mutex = Mutex()
@Operation
fun tryLock() = mutex.tryLock()
- @Operation(promptCancellation = true)
+ @Operation
suspend fun lock() = mutex.lock()
@Operation(handleExceptionsAsResult = [IllegalStateException::class])
fun unlock() = mutex.unlock()
- override fun <O : Options<O, *>> O.customize(isStressTest: Boolean): O =
- actorsBefore(0)
-
- override fun ModelCheckingOptions.customize(isStressTest: Boolean) =
- checkObstructionFreedom()
+ @Test
+ fun test() = LCStressOptionsDefault()
+ .actorsBefore(0)
+ .check(this::class)
override fun extractState() = mutex.isLocked
} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/test/lincheck/SegmentListRemoveLincheckTest.kt b/kotlinx-coroutines-core/jvm/test/linearizability/SegmentListRemoveLCStressTest.kt
index 5a8d7b47..5daed998 100644
--- a/kotlinx-coroutines-core/jvm/test/lincheck/SegmentListRemoveLincheckTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/linearizability/SegmentListRemoveLCStressTest.kt
@@ -4,16 +4,18 @@
@file:Suppress("unused")
-package kotlinx.coroutines.lincheck
+package kotlinx.coroutines.linearizability
import kotlinx.coroutines.*
import kotlinx.coroutines.internal.*
-import org.jetbrains.kotlinx.lincheck.*
import org.jetbrains.kotlinx.lincheck.annotations.*
+import org.jetbrains.kotlinx.lincheck.annotations.Operation
import org.jetbrains.kotlinx.lincheck.paramgen.*
-import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.*
+import org.jetbrains.kotlinx.lincheck.verifier.*
+import org.junit.*
-class SegmentListRemoveLincheckTest : AbstractLincheckTest() {
+
+class SegmentListRemoveLCStressTest : VerifierState() {
private val q = SegmentBasedQueue<Int>()
private val segments: Array<OneElementSegment<Int>>
@@ -27,9 +29,6 @@ class SegmentListRemoveLincheckTest : AbstractLincheckTest() {
segments[index].removeSegment()
}
- override fun <O : Options<O, *>> O.customize(isStressTest: Boolean): O = this
- .actorsBefore(0).actorsAfter(0)
-
override fun extractState() = segments.map { it.logicallyRemoved }
@Validate
@@ -38,6 +37,9 @@ class SegmentListRemoveLincheckTest : AbstractLincheckTest() {
q.checkAllSegmentsAreNotLogicallyRemoved()
}
- override fun ModelCheckingOptions.customize(isStressTest: Boolean) =
- checkObstructionFreedom()
+ @Test
+ fun test() = LCStressOptionsDefault()
+ .actorsBefore(0)
+ .actorsAfter(0)
+ .check(this::class)
} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/test/lincheck/SegmentQueueLincheckTest.kt b/kotlinx-coroutines-core/jvm/test/linearizability/SegmentQueueLCStressTest.kt
index 76a59e39..89bf8dfa 100644
--- a/kotlinx-coroutines-core/jvm/test/lincheck/SegmentQueueLincheckTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/linearizability/SegmentQueueLCStressTest.kt
@@ -3,17 +3,18 @@
*/
@file:Suppress("unused")
-package kotlinx.coroutines.lincheck
+package kotlinx.coroutines.linearizability
import kotlinx.coroutines.*
import kotlinx.coroutines.internal.SegmentBasedQueue
import org.jetbrains.kotlinx.lincheck.annotations.*
import org.jetbrains.kotlinx.lincheck.annotations.Operation
import org.jetbrains.kotlinx.lincheck.paramgen.*
-import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.*
+import org.jetbrains.kotlinx.lincheck.verifier.*
+import org.junit.*
@Param(name = "value", gen = IntGen::class, conf = "1:5")
-class SegmentQueueLincheckTest : AbstractLincheckTest() {
+class SegmentQueueLCStressTest : VerifierState() {
private val q = SegmentBasedQueue<Int>()
@Operation
@@ -39,6 +40,6 @@ class SegmentQueueLincheckTest : AbstractLincheckTest() {
return elements to closed
}
- override fun ModelCheckingOptions.customize(isStressTest: Boolean) =
- checkObstructionFreedom()
+ @Test
+ fun test() = LCStressOptionsDefault().check(this::class)
} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/test/linearizability/SemaphoreLCStressTest.kt b/kotlinx-coroutines-core/jvm/test/linearizability/SemaphoreLCStressTest.kt
new file mode 100644
index 00000000..52902f49
--- /dev/null
+++ b/kotlinx-coroutines-core/jvm/test/linearizability/SemaphoreLCStressTest.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+@file:Suppress("unused")
+package kotlinx.coroutines.linearizability
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.sync.*
+import org.jetbrains.kotlinx.lincheck.annotations.Operation
+import org.jetbrains.kotlinx.lincheck.verifier.*
+import org.junit.*
+
+abstract class SemaphoreLCStressTestBase(permits: Int) : VerifierState() {
+ private val semaphore = Semaphore(permits)
+
+ @Operation
+ fun tryAcquire() = semaphore.tryAcquire()
+
+ @Operation
+ suspend fun acquire() = semaphore.acquire()
+
+ @Operation(handleExceptionsAsResult = [IllegalStateException::class])
+ fun release() = semaphore.release()
+
+ @Test
+ fun test() = LCStressOptionsDefault()
+ .actorsBefore(0)
+ .check(this::class)
+
+ override fun extractState() = semaphore.availablePermits
+}
+
+class Semaphore1LCStressTest : SemaphoreLCStressTestBase(1)
+class Semaphore2LCStressTest : SemaphoreLCStressTestBase(2) \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/test/scheduling/BlockingCoroutineDispatcherMixedStealingStressTest.kt b/kotlinx-coroutines-core/jvm/test/scheduling/BlockingCoroutineDispatcherMixedStealingStressTest.kt
index 3a55f8c4..1fe0d838 100644
--- a/kotlinx-coroutines-core/jvm/test/scheduling/BlockingCoroutineDispatcherMixedStealingStressTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/scheduling/BlockingCoroutineDispatcherMixedStealingStressTest.kt
@@ -77,4 +77,4 @@ class BlockingCoroutineDispatcherMixedStealingStressTest : SchedulerTestBase() {
cpuBlocker.await()
}
}
-}
+} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/test/scheduling/TestTimeSource.kt b/kotlinx-coroutines-core/jvm/test/scheduling/TestTimeSource.kt
index 233e4420..a5c83d32 100644
--- a/kotlinx-coroutines-core/jvm/test/scheduling/TestTimeSource.kt
+++ b/kotlinx-coroutines-core/jvm/test/scheduling/TestTimeSource.kt
@@ -1,11 +1,11 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.scheduling
-internal class TestTimeSource(var time: Long) : SchedulerTimeSource() {
+internal class TestTimeSource(var time: Long) : TimeSource() {
override fun nanoTime() = time
diff --git a/kotlinx-coroutines-core/jvm/test/sync/MutexStressTest.kt b/kotlinx-coroutines-core/jvm/test/sync/MutexStressTest.kt
index 027f3c51..bb713b25 100644
--- a/kotlinx-coroutines-core/jvm/test/sync/MutexStressTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/sync/MutexStressTest.kt
@@ -90,21 +90,4 @@ class MutexStressTest : TestBase() {
}
}
}
-
- @Test
- fun testShouldBeUnlockedOnCancellation() = runTest {
- val mutex = Mutex()
- val n = 1000 * stressTestMultiplier
- repeat(n) {
- val job = launch(Dispatchers.Default) {
- mutex.lock()
- mutex.unlock()
- }
- mutex.withLock {
- job.cancel()
- }
- job.join()
- assertFalse { mutex.isLocked }
- }
- }
-}
+} \ No newline at end of file
diff --git a/kotlinx-coroutines-core/jvm/test/sync/SemaphoreStressTest.kt b/kotlinx-coroutines-core/jvm/test/sync/SemaphoreStressTest.kt
index 2ceed64b..374a1e3d 100644
--- a/kotlinx-coroutines-core/jvm/test/sync/SemaphoreStressTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/sync/SemaphoreStressTest.kt
@@ -2,7 +2,7 @@ package kotlinx.coroutines.sync
import kotlinx.coroutines.*
import org.junit.Test
-import kotlin.test.*
+import kotlin.test.assertEquals
class SemaphoreStressTest : TestBase() {
@Test
@@ -90,21 +90,4 @@ class SemaphoreStressTest : TestBase() {
}
}
}
-
- @Test
- fun testShouldBeUnlockedOnCancellation() = runTest {
- val semaphore = Semaphore(1)
- val n = 1000 * stressTestMultiplier
- repeat(n) {
- val job = launch(Dispatchers.Default) {
- semaphore.acquire()
- semaphore.release()
- }
- semaphore.withPermit {
- job.cancel()
- }
- job.join()
- assertTrue { semaphore.availablePermits == 1 }
- }
- }
}
diff --git a/kotlinx-coroutines-core/knit.properties b/kotlinx-coroutines-core/knit.properties
index 5b57398b..93ce87db 100644
--- a/kotlinx-coroutines-core/knit.properties
+++ b/kotlinx-coroutines-core/knit.properties
@@ -1,5 +1,5 @@
#
-# Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+# Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
#
knit.package=kotlinx.coroutines.examples
diff --git a/kotlinx-coroutines-core/native/src/Builders.kt b/kotlinx-coroutines-core/native/src/Builders.kt
index 7425a055..3554dc60 100644
--- a/kotlinx-coroutines-core/native/src/Builders.kt
+++ b/kotlinx-coroutines-core/native/src/Builders.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/native/src/CompletionHandler.kt b/kotlinx-coroutines-core/native/src/CompletionHandler.kt
index 4835f796..706f6c49 100644
--- a/kotlinx-coroutines-core/native/src/CompletionHandler.kt
+++ b/kotlinx-coroutines-core/native/src/CompletionHandler.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/native/src/CoroutineContext.kt b/kotlinx-coroutines-core/native/src/CoroutineContext.kt
index 47afd8ad..4ec1289e 100644
--- a/kotlinx-coroutines-core/native/src/CoroutineContext.kt
+++ b/kotlinx-coroutines-core/native/src/CoroutineContext.kt
@@ -1,10 +1,9 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
-import kotlinx.coroutines.internal.*
import kotlin.coroutines.*
import kotlin.native.concurrent.*
@@ -39,13 +38,5 @@ public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext):
// No debugging facilities on native
internal actual inline fun <T> withCoroutineContext(context: CoroutineContext, countOrElement: Any?, block: () -> T): T = block()
-internal actual inline fun <T> withContinuationContext(continuation: Continuation<*>, countOrElement: Any?, block: () -> T): T = block()
internal actual fun Continuation<*>.toDebugString(): String = toString()
internal actual val CoroutineContext.coroutineName: String? get() = null // not supported on native
-
-internal actual class UndispatchedCoroutine<in T> actual constructor(
- context: CoroutineContext,
- uCont: Continuation<T>
-) : ScopeCoroutine<T>(context, uCont) {
- override fun afterResume(state: Any?) = uCont.resumeWith(recoverResult(state, uCont))
-}
diff --git a/kotlinx-coroutines-core/native/src/CoroutineExceptionHandlerImpl.kt b/kotlinx-coroutines-core/native/src/CoroutineExceptionHandlerImpl.kt
index b0aa8633..dff845b2 100644
--- a/kotlinx-coroutines-core/native/src/CoroutineExceptionHandlerImpl.kt
+++ b/kotlinx-coroutines-core/native/src/CoroutineExceptionHandlerImpl.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/native/src/Debug.kt b/kotlinx-coroutines-core/native/src/Debug.kt
index a0a8d272..1fa0ec7f 100644
--- a/kotlinx-coroutines-core/native/src/Debug.kt
+++ b/kotlinx-coroutines-core/native/src/Debug.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/native/src/Dispatchers.kt b/kotlinx-coroutines-core/native/src/Dispatchers.kt
index 4e5facfe..c06b7c2f 100644
--- a/kotlinx-coroutines-core/native/src/Dispatchers.kt
+++ b/kotlinx-coroutines-core/native/src/Dispatchers.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/native/src/EventLoop.kt b/kotlinx-coroutines-core/native/src/EventLoop.kt
index 925cbe99..b397d6f1 100644
--- a/kotlinx-coroutines-core/native/src/EventLoop.kt
+++ b/kotlinx-coroutines-core/native/src/EventLoop.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/native/src/Exceptions.kt b/kotlinx-coroutines-core/native/src/Exceptions.kt
index 7c76bc6d..c82199a4 100644
--- a/kotlinx-coroutines-core/native/src/Exceptions.kt
+++ b/kotlinx-coroutines-core/native/src/Exceptions.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/native/src/Runnable.kt b/kotlinx-coroutines-core/native/src/Runnable.kt
index b8e6980b..19710f97 100644
--- a/kotlinx-coroutines-core/native/src/Runnable.kt
+++ b/kotlinx-coroutines-core/native/src/Runnable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/native/src/SchedulerTask.kt b/kotlinx-coroutines-core/native/src/SchedulerTask.kt
index 781e3221..4154d53e 100644
--- a/kotlinx-coroutines-core/native/src/SchedulerTask.kt
+++ b/kotlinx-coroutines-core/native/src/SchedulerTask.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/native/src/WorkerMain.native.kt b/kotlinx-coroutines-core/native/src/WorkerMain.native.kt
index bf8fe6ae..84cc9f42 100644
--- a/kotlinx-coroutines-core/native/src/WorkerMain.native.kt
+++ b/kotlinx-coroutines-core/native/src/WorkerMain.native.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/native/src/flow/internal/FlowExceptions.kt b/kotlinx-coroutines-core/native/src/flow/internal/FlowExceptions.kt
index bc7a1ffc..47054719 100644
--- a/kotlinx-coroutines-core/native/src/flow/internal/FlowExceptions.kt
+++ b/kotlinx-coroutines-core/native/src/flow/internal/FlowExceptions.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/native/src/flow/internal/SafeCollector.kt b/kotlinx-coroutines-core/native/src/flow/internal/SafeCollector.kt
index b74b547d..ace633cc 100644
--- a/kotlinx-coroutines-core/native/src/flow/internal/SafeCollector.kt
+++ b/kotlinx-coroutines-core/native/src/flow/internal/SafeCollector.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.flow.internal
diff --git a/kotlinx-coroutines-core/native/src/internal/Concurrent.kt b/kotlinx-coroutines-core/native/src/internal/Concurrent.kt
index b379c6ac..486dc8f0 100644
--- a/kotlinx-coroutines-core/native/src/internal/Concurrent.kt
+++ b/kotlinx-coroutines-core/native/src/internal/Concurrent.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/native/src/internal/CopyOnWriteList.kt b/kotlinx-coroutines-core/native/src/internal/CopyOnWriteList.kt
index 30f063a5..b925317b 100644
--- a/kotlinx-coroutines-core/native/src/internal/CopyOnWriteList.kt
+++ b/kotlinx-coroutines-core/native/src/internal/CopyOnWriteList.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/native/src/internal/LinkedList.kt b/kotlinx-coroutines-core/native/src/internal/LinkedList.kt
index a8aed044..99ab042f 100644
--- a/kotlinx-coroutines-core/native/src/internal/LinkedList.kt
+++ b/kotlinx-coroutines-core/native/src/internal/LinkedList.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("NO_EXPLICIT_RETURN_TYPE_IN_API_MODE", "NO_EXPLICIT_VISIBILITY_IN_API_MODE")
diff --git a/kotlinx-coroutines-core/native/src/internal/LocalAtomics.kt b/kotlinx-coroutines-core/native/src/internal/LocalAtomics.kt
index c8c6fffe..398cb63b 100644
--- a/kotlinx-coroutines-core/native/src/internal/LocalAtomics.kt
+++ b/kotlinx-coroutines-core/native/src/internal/LocalAtomics.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/native/src/internal/ProbesSupport.kt b/kotlinx-coroutines-core/native/src/internal/ProbesSupport.kt
index 47d3fdba..a13a141f 100644
--- a/kotlinx-coroutines-core/native/src/internal/ProbesSupport.kt
+++ b/kotlinx-coroutines-core/native/src/internal/ProbesSupport.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/native/src/internal/StackTraceRecovery.kt b/kotlinx-coroutines-core/native/src/internal/StackTraceRecovery.kt
index d93af9f4..49f043da 100644
--- a/kotlinx-coroutines-core/native/src/internal/StackTraceRecovery.kt
+++ b/kotlinx-coroutines-core/native/src/internal/StackTraceRecovery.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/native/src/internal/Synchronized.kt b/kotlinx-coroutines-core/native/src/internal/Synchronized.kt
index dcbb2021..0911dbe1 100644
--- a/kotlinx-coroutines-core/native/src/internal/Synchronized.kt
+++ b/kotlinx-coroutines-core/native/src/internal/Synchronized.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/native/src/internal/SystemProps.kt b/kotlinx-coroutines-core/native/src/internal/SystemProps.kt
index 4fb334ed..564630f6 100644
--- a/kotlinx-coroutines-core/native/src/internal/SystemProps.kt
+++ b/kotlinx-coroutines-core/native/src/internal/SystemProps.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/native/src/internal/ThreadContext.kt b/kotlinx-coroutines-core/native/src/internal/ThreadContext.kt
index 2370e42f..4a9513ab 100644
--- a/kotlinx-coroutines-core/native/src/internal/ThreadContext.kt
+++ b/kotlinx-coroutines-core/native/src/internal/ThreadContext.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/native/src/internal/ThreadLocal.kt b/kotlinx-coroutines-core/native/src/internal/ThreadLocal.kt
index e1825d67..09f501a4 100644
--- a/kotlinx-coroutines-core/native/src/internal/ThreadLocal.kt
+++ b/kotlinx-coroutines-core/native/src/internal/ThreadLocal.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.internal
diff --git a/kotlinx-coroutines-core/nativeDarwin/src/WorkerMain.kt b/kotlinx-coroutines-core/nativeDarwin/src/WorkerMain.kt
index 010bd030..3445cb98 100644
--- a/kotlinx-coroutines-core/nativeDarwin/src/WorkerMain.kt
+++ b/kotlinx-coroutines-core/nativeDarwin/src/WorkerMain.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-core/nativeOther/src/WorkerMain.kt b/kotlinx-coroutines-core/nativeOther/src/WorkerMain.kt
index f3bd99a4..cac0530e 100644
--- a/kotlinx-coroutines-core/nativeOther/src/WorkerMain.kt
+++ b/kotlinx-coroutines-core/nativeOther/src/WorkerMain.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
diff --git a/kotlinx-coroutines-debug/README.md b/kotlinx-coroutines-debug/README.md
index f048040b..5525f912 100644
--- a/kotlinx-coroutines-debug/README.md
+++ b/kotlinx-coroutines-debug/README.md
@@ -61,7 +61,7 @@ stacktraces will be dumped to the console.
### Using as JVM agent
Debug module can also be used as a standalone JVM agent to enable debug probes on the application startup.
-You can run your application with an additional argument: `-javaagent:kotlinx-coroutines-debug-1.4.3.jar`.
+You can run your application with an additional argument: `-javaagent:kotlinx-coroutines-debug-1.4.1.jar`.
Additionally, on Linux and Mac OS X you can use `kill -5 $pid` command in order to force your application to print all alive coroutines.
When used as Java agent, `"kotlinx.coroutines.debug.enable.creation.stack.trace"` system property can be used to control
[DebugProbes.enableCreationStackTraces] along with agent startup.
@@ -138,8 +138,8 @@ Coroutine "coroutine#2":DeferredCoroutine{Active}@289d1c02, state: SUSPENDED
Dumping only deferred
"coroutine#2":DeferredCoroutine{Active}, continuation is SUSPENDED at line kotlinx.coroutines.DeferredCoroutine.await$suspendImpl(Builders.common.kt:99)
- "coroutine#3":DeferredCoroutine{Active}, continuation is SUSPENDED at line ExampleKt.computeOne(Example.kt:14)
- "coroutine#4":DeferredCoroutine{Active}, continuation is SUSPENDED at line ExampleKt.computeTwo(Example.kt:19)
+ "coroutine#3":DeferredCoroutine{Active}, continuation is SUSPENDED at line ExampleKt.computeOne(Example.kt:14)
+ "coroutine#4":DeferredCoroutine{Active}, continuation is SUSPENDED at line ExampleKt.computeTwo(Example.kt:19)
```
### Status of the API
@@ -264,13 +264,10 @@ More than one file was found with OS independent path 'win32-x86-64/attach_hotsp
-->
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
-
[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
-
<!--- MODULE kotlinx-coroutines-debug -->
<!--- INDEX kotlinx.coroutines.debug -->
-
[DebugProbes]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-debug/kotlinx.coroutines.debug/-debug-probes/index.html
[DebugProbes.install]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-debug/kotlinx.coroutines.debug/-debug-probes/install.html
[DebugProbes.dumpCoroutines]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-debug/kotlinx.coroutines.debug/-debug-probes/dump-coroutines.html
@@ -278,9 +275,6 @@ More than one file was found with OS independent path 'win32-x86-64/attach_hotsp
[DebugProbes.printJob]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-debug/kotlinx.coroutines.debug/-debug-probes/print-job.html
[DebugProbes.printScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-debug/kotlinx.coroutines.debug/-debug-probes/print-scope.html
[DebugProbes.enableCreationStackTraces]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-debug/kotlinx.coroutines.debug/-debug-probes/enable-creation-stack-traces.html
-
<!--- INDEX kotlinx.coroutines.debug.junit4 -->
-
[CoroutinesTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-debug/kotlinx.coroutines.debug.junit4/-coroutines-timeout/index.html
-
<!--- END -->
diff --git a/kotlinx-coroutines-debug/build.gradle b/kotlinx-coroutines-debug/build.gradle
index 46f894d1..ab7f28c6 100644
--- a/kotlinx-coroutines-debug/build.gradle
+++ b/kotlinx-coroutines-debug/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
apply plugin: "com.github.johnrengelman.shadow"
@@ -28,16 +28,6 @@ dependencies {
api "net.java.dev.jna:jna-platform:$jna_version"
}
-// TODO: JVM IR generates different stacktrace so temporary disable stacktrace tests
-if (rootProject.ext.jvm_ir_enabled) {
- tasks.named('test', Test) {
- filter {
-// excludeTest('kotlinx.coroutines.debug.CoroutinesDumpTest', 'testCreationStackTrace')
- excludeTestsMatching('kotlinx.coroutines.debug.DebugProbesTest')
- }
- }
-}
-
jar {
manifest {
attributes "Premain-Class": "kotlinx.coroutines.debug.AgentPremain"
diff --git a/kotlinx-coroutines-debug/src/CoroutineInfo.kt b/kotlinx-coroutines-debug/src/CoroutineInfo.kt
index 62728ada..ce1478ad 100644
--- a/kotlinx-coroutines-debug/src/CoroutineInfo.kt
+++ b/kotlinx-coroutines-debug/src/CoroutineInfo.kt
@@ -1,7 +1,7 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "UNUSED")
+@file:Suppress("NO_EXPLICIT_VISIBILITY_IN_API_MODE", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "UNUSED")
package kotlinx.coroutines.debug
import kotlinx.coroutines.*
diff --git a/kotlinx-coroutines-debug/src/CoroutinesBlockHoundIntegration.kt b/kotlinx-coroutines-debug/src/CoroutinesBlockHoundIntegration.kt
index 7dd7d58d..091e8eb1 100644
--- a/kotlinx-coroutines-debug/src/CoroutinesBlockHoundIntegration.kt
+++ b/kotlinx-coroutines-debug/src/CoroutinesBlockHoundIntegration.kt
@@ -1,7 +1,3 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
package kotlinx.coroutines.debug
diff --git a/kotlinx-coroutines-debug/src/DebugProbes.kt b/kotlinx-coroutines-debug/src/DebugProbes.kt
index 373864ad..254385f9 100644
--- a/kotlinx-coroutines-debug/src/DebugProbes.kt
+++ b/kotlinx-coroutines-debug/src/DebugProbes.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("UNUSED", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
diff --git a/kotlinx-coroutines-debug/src/internal/Attach.kt b/kotlinx-coroutines-debug/src/internal/Attach.kt
index f38447f7..cd4cc2a5 100644
--- a/kotlinx-coroutines-debug/src/internal/Attach.kt
+++ b/kotlinx-coroutines-debug/src/internal/Attach.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("unused")
package kotlinx.coroutines.debug.internal
diff --git a/kotlinx-coroutines-debug/src/internal/NoOpProbes.kt b/kotlinx-coroutines-debug/src/internal/NoOpProbes.kt
index 34f1afec..4854f5d7 100644
--- a/kotlinx-coroutines-debug/src/internal/NoOpProbes.kt
+++ b/kotlinx-coroutines-debug/src/internal/NoOpProbes.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("unused", "UNUSED_PARAMETER")
diff --git a/kotlinx-coroutines-debug/src/junit4/CoroutinesTimeout.kt b/kotlinx-coroutines-debug/src/junit4/CoroutinesTimeout.kt
index 12bc9475..0510764a 100644
--- a/kotlinx-coroutines-debug/src/junit4/CoroutinesTimeout.kt
+++ b/kotlinx-coroutines-debug/src/junit4/CoroutinesTimeout.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.debug.junit4
diff --git a/kotlinx-coroutines-debug/src/junit4/CoroutinesTimeoutStatement.kt b/kotlinx-coroutines-debug/src/junit4/CoroutinesTimeoutStatement.kt
index 4baf409d..72413b91 100644
--- a/kotlinx-coroutines-debug/src/junit4/CoroutinesTimeoutStatement.kt
+++ b/kotlinx-coroutines-debug/src/junit4/CoroutinesTimeoutStatement.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.debug.junit4
diff --git a/kotlinx-coroutines-debug/test/DebugProbesTest.kt b/kotlinx-coroutines-debug/test/DebugProbesTest.kt
index 01b2da00..3b32db3a 100644
--- a/kotlinx-coroutines-debug/test/DebugProbesTest.kt
+++ b/kotlinx-coroutines-debug/test/DebugProbesTest.kt
@@ -45,7 +45,6 @@ class DebugProbesTest : DebugTestBase() {
"\tat kotlinx.coroutines.DeferredCoroutine.await\$suspendImpl(Builders.common.kt)\n" +
"\tat kotlinx.coroutines.debug.DebugProbesTest.oneMoreNestedMethod(DebugProbesTest.kt)\n" +
"\tat kotlinx.coroutines.debug.DebugProbesTest.nestedMethod(DebugProbesTest.kt)\n" +
- "\tat kotlinx.coroutines.debug.DebugProbesTest\$testAsyncWithProbes\$1\$1.invokeSuspend(DebugProbesTest.kt:62)\n" +
"\t(Coroutine creation stacktrace)\n" +
"\tat kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsJvmKt.createCoroutineUnintercepted(IntrinsicsJvm.kt)\n" +
"\tat kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt)\n" +
@@ -77,7 +76,6 @@ class DebugProbesTest : DebugTestBase() {
"\tat kotlinx.coroutines.DeferredCoroutine.await\$suspendImpl(Builders.common.kt)\n" +
"\tat kotlinx.coroutines.debug.DebugProbesTest.oneMoreNestedMethod(DebugProbesTest.kt:71)\n" +
"\tat kotlinx.coroutines.debug.DebugProbesTest.nestedMethod(DebugProbesTest.kt:66)\n" +
- "\tat kotlinx.coroutines.debug.DebugProbesTest\$testAsyncWithSanitizedProbes\$1\$1.invokeSuspend(DebugProbesTest.kt:87)\n" +
"\t(Coroutine creation stacktrace)\n" +
"\tat kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsJvmKt.createCoroutineUnintercepted(IntrinsicsJvm.kt:116)\n" +
"\tat kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:23)\n" +
diff --git a/kotlinx-coroutines-debug/test/SanitizedProbesTest.kt b/kotlinx-coroutines-debug/test/SanitizedProbesTest.kt
index 67a283d0..bf6cbdf1 100644
--- a/kotlinx-coroutines-debug/test/SanitizedProbesTest.kt
+++ b/kotlinx-coroutines-debug/test/SanitizedProbesTest.kt
@@ -63,7 +63,6 @@ class SanitizedProbesTest : DebugTestBase() {
"\t(Coroutine creation stacktrace)\n" +
"\tat kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsJvmKt.createCoroutineUnintercepted(IntrinsicsJvm.kt:116)\n" +
"\tat kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:23)\n" +
- "\tat kotlinx.coroutines.BuildersKt__Builders_commonKt.async\$default(Builders.common.kt)\n" +
"\tat kotlinx.coroutines.BuildersKt.async\$default(Unknown Source)\n" +
"\tat definitely.not.kotlinx.coroutines.SanitizedProbesTest.createActiveDeferred(SanitizedProbesTest.kt:62)\n" +
"\tat definitely.not.kotlinx.coroutines.SanitizedProbesTest.access\$createActiveDeferred(SanitizedProbesTest.kt:16)\n" +
@@ -88,11 +87,10 @@ class SanitizedProbesTest : DebugTestBase() {
"\tat kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsJvmKt.createCoroutineUnintercepted(IntrinsicsJvm.kt:116)",
"Coroutine \"coroutine#2\":StandaloneCoroutine{Active}@1b68b9a4, state: SUSPENDED\n" +
- "\tat definitely.not.kotlinx.coroutines.SanitizedProbesTest\$launchSelector\$1\$1\$1.invokeSuspend(SanitizedProbesTest.kt)\n" +
+ "\tat definitely.not.kotlinx.coroutines.SanitizedProbesTest\$launchSelector\$1.invokeSuspend(SanitizedProbesTest.kt:143)\n" +
"\t(Coroutine creation stacktrace)\n" +
"\tat kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsJvmKt.createCoroutineUnintercepted(IntrinsicsJvm.kt:116)\n" +
"\tat kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:25)\n" +
- "\tat kotlinx.coroutines.BuildersKt__Builders_commonKt.launch\$default(Builders.common.kt)\n" +
"\tat kotlinx.coroutines.BuildersKt.launch\$default(Unknown Source)\n" +
"\tat definitely.not.kotlinx.coroutines.SanitizedProbesTest.launchSelector(SanitizedProbesTest.kt:100)\n" +
"\tat definitely.not.kotlinx.coroutines.SanitizedProbesTest.access\$launchSelector(SanitizedProbesTest.kt:16)\n" +
diff --git a/kotlinx-coroutines-test/README.md b/kotlinx-coroutines-test/README.md
index dd18d966..afcd4a3b 100644
--- a/kotlinx-coroutines-test/README.md
+++ b/kotlinx-coroutines-test/README.md
@@ -9,7 +9,7 @@ This package provides testing utilities for effectively testing coroutines.
Add `kotlinx-coroutines-test` to your project test dependencies:
```
dependencies {
- testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.3'
+ testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.1'
}
```
@@ -431,7 +431,6 @@ If you have any suggestions for improvements to this experimental API please sha
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
-
[Dispatchers.Main]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html
[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html
[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
@@ -441,10 +440,8 @@ If you have any suggestions for improvements to this experimental API please sha
[CoroutineStart]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html
[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
[ExperimentalCoroutinesApi]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-experimental-coroutines-api/index.html
-
<!--- MODULE kotlinx-coroutines-test -->
<!--- INDEX kotlinx.coroutines.test -->
-
[setMain]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/kotlinx.coroutines.-dispatchers/set-main.html
[runBlockingTest]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/run-blocking-test.html
[UncompletedCoroutinesError]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-uncompleted-coroutines-error/index.html
@@ -457,5 +454,4 @@ If you have any suggestions for improvements to this experimental API please sha
[TestCoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-exception-handler/index.html
[TestCoroutineScope.cleanupTestCoroutines]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-scope/cleanup-test-coroutines.html
[DelayController.cleanupTestCoroutines]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-delay-controller/cleanup-test-coroutines.html
-
<!--- END -->
diff --git a/kotlinx-coroutines-test/build.gradle.kts b/kotlinx-coroutines-test/build.gradle.kts
index fef0a146..825c95f4 100644
--- a/kotlinx-coroutines-test/build.gradle.kts
+++ b/kotlinx-coroutines-test/build.gradle.kts
@@ -1,7 +1,3 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
dependencies {
implementation(project(":kotlinx-coroutines-debug"))
}
diff --git a/kotlinx-coroutines-test/resources/META-INF/proguard/coroutines.pro b/kotlinx-coroutines-test/resources/META-INF/proguard/coroutines.pro
index 1fdfb787..41c9eb07 100644
--- a/kotlinx-coroutines-test/resources/META-INF/proguard/coroutines.pro
+++ b/kotlinx-coroutines-test/resources/META-INF/proguard/coroutines.pro
@@ -4,6 +4,6 @@
-keepnames class kotlinx.coroutines.android.AndroidDispatcherFactory {}
# Most of volatile fields are updated with AFU and should not be mangled
--keepclassmembers class kotlinx.coroutines.** {
+-keepclassmembernames class kotlinx.** {
volatile <fields>;
}
diff --git a/kotlinx-coroutines-test/src/DelayController.kt b/kotlinx-coroutines-test/src/DelayController.kt
index 6e722227..a777d4b9 100644
--- a/kotlinx-coroutines-test/src/DelayController.kt
+++ b/kotlinx-coroutines-test/src/DelayController.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.test
diff --git a/kotlinx-coroutines-test/src/TestBuilders.kt b/kotlinx-coroutines-test/src/TestBuilders.kt
index b40769ee..88fa01b7 100644
--- a/kotlinx-coroutines-test/src/TestBuilders.kt
+++ b/kotlinx-coroutines-test/src/TestBuilders.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.test
diff --git a/kotlinx-coroutines-test/src/TestCoroutineDispatcher.kt b/kotlinx-coroutines-test/src/TestCoroutineDispatcher.kt
index f6464789..cad2636f 100644
--- a/kotlinx-coroutines-test/src/TestCoroutineDispatcher.kt
+++ b/kotlinx-coroutines-test/src/TestCoroutineDispatcher.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.test
diff --git a/kotlinx-coroutines-test/src/TestCoroutineExceptionHandler.kt b/kotlinx-coroutines-test/src/TestCoroutineExceptionHandler.kt
index 66eb2359..ed08fbcd 100644
--- a/kotlinx-coroutines-test/src/TestCoroutineExceptionHandler.kt
+++ b/kotlinx-coroutines-test/src/TestCoroutineExceptionHandler.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.test
diff --git a/kotlinx-coroutines-test/src/TestCoroutineScope.kt b/kotlinx-coroutines-test/src/TestCoroutineScope.kt
index 7c1ff872..4034fcaa 100644
--- a/kotlinx-coroutines-test/src/TestCoroutineScope.kt
+++ b/kotlinx-coroutines-test/src/TestCoroutineScope.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.test
diff --git a/kotlinx-coroutines-test/src/TestDispatchers.kt b/kotlinx-coroutines-test/src/TestDispatchers.kt
index bf068f9d..a247ca83 100644
--- a/kotlinx-coroutines-test/src/TestDispatchers.kt
+++ b/kotlinx-coroutines-test/src/TestDispatchers.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("unused")
@file:JvmName("TestDispatchers")
diff --git a/kotlinx-coroutines-test/src/internal/MainTestDispatcher.kt b/kotlinx-coroutines-test/src/internal/MainTestDispatcher.kt
index af1eee42..baa1aa5f 100644
--- a/kotlinx-coroutines-test/src/internal/MainTestDispatcher.kt
+++ b/kotlinx-coroutines-test/src/internal/MainTestDispatcher.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.test.internal
diff --git a/reactive/knit.properties b/reactive/knit.properties
index 452cd2f1..18aecba6 100644
--- a/reactive/knit.properties
+++ b/reactive/knit.properties
@@ -1,6 +1,6 @@
#
-# Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+# Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
#
knit.package=kotlinx.coroutines.rx2.guide
-knit.dir=kotlinx-coroutines-rx2/test/guide/
+knit.dir=kotlinx-coroutines-rx2/test/guide/ \ No newline at end of file
diff --git a/reactive/kotlinx-coroutines-jdk9/build.gradle.kts b/reactive/kotlinx-coroutines-jdk9/build.gradle.kts
index 38c6735c..c721746f 100644
--- a/reactive/kotlinx-coroutines-jdk9/build.gradle.kts
+++ b/reactive/kotlinx-coroutines-jdk9/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
dependencies {
diff --git a/reactive/kotlinx-coroutines-jdk9/src/Await.kt b/reactive/kotlinx-coroutines-jdk9/src/Await.kt
index 4febf407..88268890 100644
--- a/reactive/kotlinx-coroutines-jdk9/src/Await.kt
+++ b/reactive/kotlinx-coroutines-jdk9/src/Await.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.jdk9
diff --git a/reactive/kotlinx-coroutines-jdk9/src/Publish.kt b/reactive/kotlinx-coroutines-jdk9/src/Publish.kt
index 3db0d5da..6fd9a5e7 100644
--- a/reactive/kotlinx-coroutines-jdk9/src/Publish.kt
+++ b/reactive/kotlinx-coroutines-jdk9/src/Publish.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.jdk9
diff --git a/reactive/kotlinx-coroutines-jdk9/src/ReactiveFlow.kt b/reactive/kotlinx-coroutines-jdk9/src/ReactiveFlow.kt
index d3942a16..5d546dff 100644
--- a/reactive/kotlinx-coroutines-jdk9/src/ReactiveFlow.kt
+++ b/reactive/kotlinx-coroutines-jdk9/src/ReactiveFlow.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.jdk9
diff --git a/reactive/kotlinx-coroutines-reactive/README.md b/reactive/kotlinx-coroutines-reactive/README.md
index b6466b2d..aed26226 100644
--- a/reactive/kotlinx-coroutines-reactive/README.md
+++ b/reactive/kotlinx-coroutines-reactive/README.md
@@ -32,16 +32,11 @@ Suspending extension functions and suspending iteration:
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
<!--- INDEX kotlinx.coroutines.flow -->
-
[Flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html
-
<!--- INDEX kotlinx.coroutines.channels -->
-
[ProducerScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-producer-scope/index.html
-
<!--- MODULE kotlinx-coroutines-reactive -->
<!--- INDEX kotlinx.coroutines.reactive -->
-
[kotlinx.coroutines.reactive.publish]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/publish.html
[Publisher.asFlow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/as-flow.html
[Flow.asPublisher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/kotlinx.coroutines.flow.-flow/as-publisher.html
@@ -50,7 +45,6 @@ Suspending extension functions and suspending iteration:
[org.reactivestreams.Publisher.awaitFirstOrElse]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/await-first-or-else.html
[org.reactivestreams.Publisher.awaitFirstOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/await-first-or-null.html
[org.reactivestreams.Publisher.awaitSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.reactive/org.reactivestreams.-publisher/await-single.html
-
<!--- END -->
# Package kotlinx.coroutines.reactive
diff --git a/reactive/kotlinx-coroutines-reactive/build.gradle.kts b/reactive/kotlinx-coroutines-reactive/build.gradle.kts
index 128d4d86..2ace4f9f 100644
--- a/reactive/kotlinx-coroutines-reactive/build.gradle.kts
+++ b/reactive/kotlinx-coroutines-reactive/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
val reactiveStreamsVersion = property("reactive_streams_version")
diff --git a/reactive/kotlinx-coroutines-reactive/src/Await.kt b/reactive/kotlinx-coroutines-reactive/src/Await.kt
index e9f69550..7956c260 100644
--- a/reactive/kotlinx-coroutines-reactive/src/Await.kt
+++ b/reactive/kotlinx-coroutines-reactive/src/Await.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.reactive
diff --git a/reactive/kotlinx-coroutines-reactive/src/Channel.kt b/reactive/kotlinx-coroutines-reactive/src/Channel.kt
index 352a505a..26f14ec6 100644
--- a/reactive/kotlinx-coroutines-reactive/src/Channel.kt
+++ b/reactive/kotlinx-coroutines-reactive/src/Channel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.reactive
diff --git a/reactive/kotlinx-coroutines-reactive/src/ContextInjector.kt b/reactive/kotlinx-coroutines-reactive/src/ContextInjector.kt
index 043e223d..d5390fd6 100644
--- a/reactive/kotlinx-coroutines-reactive/src/ContextInjector.kt
+++ b/reactive/kotlinx-coroutines-reactive/src/ContextInjector.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.reactive
diff --git a/reactive/kotlinx-coroutines-reactive/src/Convert.kt b/reactive/kotlinx-coroutines-reactive/src/Convert.kt
index 8f4b26d3..727eff8b 100644
--- a/reactive/kotlinx-coroutines-reactive/src/Convert.kt
+++ b/reactive/kotlinx-coroutines-reactive/src/Convert.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.reactive
diff --git a/reactive/kotlinx-coroutines-reactive/src/Migration.kt b/reactive/kotlinx-coroutines-reactive/src/Migration.kt
index 1bba746c..4e0dca63 100644
--- a/reactive/kotlinx-coroutines-reactive/src/Migration.kt
+++ b/reactive/kotlinx-coroutines-reactive/src/Migration.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
diff --git a/reactive/kotlinx-coroutines-reactive/src/Publish.kt b/reactive/kotlinx-coroutines-reactive/src/Publish.kt
index 35878b04..ddfd7f8a 100644
--- a/reactive/kotlinx-coroutines-reactive/src/Publish.kt
+++ b/reactive/kotlinx-coroutines-reactive/src/Publish.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
diff --git a/reactive/kotlinx-coroutines-reactive/src/ReactiveFlow.kt b/reactive/kotlinx-coroutines-reactive/src/ReactiveFlow.kt
index 614e9ead..5834220c 100644
--- a/reactive/kotlinx-coroutines-reactive/src/ReactiveFlow.kt
+++ b/reactive/kotlinx-coroutines-reactive/src/ReactiveFlow.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.reactive
diff --git a/reactive/kotlinx-coroutines-reactor/README.md b/reactive/kotlinx-coroutines-reactor/README.md
index 70283106..cd4a42a3 100644
--- a/reactive/kotlinx-coroutines-reactor/README.md
+++ b/reactive/kotlinx-coroutines-reactor/README.md
@@ -32,18 +32,13 @@ Conversion functions:
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
-
[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html
-
<!--- INDEX kotlinx.coroutines.channels -->
<!--- INDEX kotlinx.coroutines.flow -->
-
[Flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html
-
<!--- MODULE kotlinx-coroutines-reactor -->
<!--- INDEX kotlinx.coroutines.reactor -->
-
[mono]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/mono.html
[flux]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/flux.html
[Flow.asFlux]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/kotlinx.coroutines.flow.-flow/as-flux.html
@@ -52,7 +47,6 @@ Conversion functions:
[kotlinx.coroutines.Deferred.asMono]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/kotlinx.coroutines.-deferred/as-mono.html
[kotlinx.coroutines.channels.ReceiveChannel.asFlux]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/kotlinx.coroutines.channels.-receive-channel/as-flux.html
[reactor.core.scheduler.Scheduler.asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactor/kotlinx.coroutines.reactor/reactor.core.scheduler.-scheduler/as-coroutine-dispatcher.html
-
<!--- END -->
# Package kotlinx.coroutines.reactor
diff --git a/reactive/kotlinx-coroutines-reactor/build.gradle.kts b/reactive/kotlinx-coroutines-reactor/build.gradle.kts
index 03af7f4f..d5fd208a 100644
--- a/reactive/kotlinx-coroutines-reactor/build.gradle.kts
+++ b/reactive/kotlinx-coroutines-reactor/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
val reactorVersion = version("reactor")
@@ -9,10 +9,6 @@ dependencies {
compile(project(":kotlinx-coroutines-reactive"))
}
-java {
- targetCompatibility = JavaVersion.VERSION_1_8
- sourceCompatibility = JavaVersion.VERSION_1_8
-}
tasks {
compileKotlin {
diff --git a/reactive/kotlinx-coroutines-reactor/src/Convert.kt b/reactive/kotlinx-coroutines-reactor/src/Convert.kt
index 7807549c..dc264f8d 100644
--- a/reactive/kotlinx-coroutines-reactor/src/Convert.kt
+++ b/reactive/kotlinx-coroutines-reactor/src/Convert.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.reactor
diff --git a/reactive/kotlinx-coroutines-reactor/src/Flux.kt b/reactive/kotlinx-coroutines-reactor/src/Flux.kt
index 8d4f9cc9..addc528c 100644
--- a/reactive/kotlinx-coroutines-reactor/src/Flux.kt
+++ b/reactive/kotlinx-coroutines-reactor/src/Flux.kt
@@ -1,6 +1,6 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
diff --git a/reactive/kotlinx-coroutines-reactor/src/Migration.kt b/reactive/kotlinx-coroutines-reactor/src/Migration.kt
index ec5674d9..f0c24bb0 100644
--- a/reactive/kotlinx-coroutines-reactor/src/Migration.kt
+++ b/reactive/kotlinx-coroutines-reactor/src/Migration.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmName("FlowKt")
diff --git a/reactive/kotlinx-coroutines-reactor/src/Mono.kt b/reactive/kotlinx-coroutines-reactor/src/Mono.kt
index 2d595c96..503c891e 100644
--- a/reactive/kotlinx-coroutines-reactor/src/Mono.kt
+++ b/reactive/kotlinx-coroutines-reactor/src/Mono.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
diff --git a/reactive/kotlinx-coroutines-reactor/src/ReactorContext.kt b/reactive/kotlinx-coroutines-reactor/src/ReactorContext.kt
index be4b2c7d..69467ad8 100644
--- a/reactive/kotlinx-coroutines-reactor/src/ReactorContext.kt
+++ b/reactive/kotlinx-coroutines-reactor/src/ReactorContext.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.reactor
@@ -24,7 +24,7 @@ import kotlinx.coroutines.reactive.*
* #### Propagating ReactorContext to Reactor's Context
* ```
* val flux = myDatabaseService.getUsers()
- * .contextWrite { ctx -> println(ctx); ctx }
+ * .subscriberContext() { ctx -> println(ctx); ctx }
* flux.await() // Will print "null"
*
* // Now add ReactorContext
@@ -43,7 +43,7 @@ import kotlinx.coroutines.reactive.*
* .subscribe() // Will print 'Reactor context in Flow: null'
* // Add subscriber's context
* flow.asFlux()
- * .contextWrite { ctx -> ctx.put("answer", 42) }
+ * .subscriberContext { ctx -> ctx.put("answer", 42) }
* .subscribe() // Will print "Reactor context in Flow: Context{'answer'=42}"
* ```
*/
diff --git a/reactive/kotlinx-coroutines-reactor/src/ReactorContextInjector.kt b/reactive/kotlinx-coroutines-reactor/src/ReactorContextInjector.kt
index f65d2ec2..a9d140a9 100644
--- a/reactive/kotlinx-coroutines-reactor/src/ReactorContextInjector.kt
+++ b/reactive/kotlinx-coroutines-reactor/src/ReactorContextInjector.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.reactor
@@ -18,8 +18,8 @@ internal class ReactorContextInjector : ContextInjector {
override fun <T> injectCoroutineContext(publisher: Publisher<T>, coroutineContext: CoroutineContext): Publisher<T> {
val reactorContext = coroutineContext[ReactorContext]?.context ?: return publisher
return when(publisher) {
- is Mono -> publisher.contextWrite(reactorContext)
- is Flux -> publisher.contextWrite(reactorContext)
+ is Mono -> publisher.subscriberContext(reactorContext)
+ is Flux -> publisher.subscriberContext(reactorContext)
else -> publisher
}
}
diff --git a/reactive/kotlinx-coroutines-reactor/src/ReactorFlow.kt b/reactive/kotlinx-coroutines-reactor/src/ReactorFlow.kt
index 0fc743f9..a478ab1e 100644
--- a/reactive/kotlinx-coroutines-reactor/src/ReactorFlow.kt
+++ b/reactive/kotlinx-coroutines-reactor/src/ReactorFlow.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.reactor
diff --git a/reactive/kotlinx-coroutines-reactor/src/Scheduler.kt b/reactive/kotlinx-coroutines-reactor/src/Scheduler.kt
index 03b052b6..4fb55143 100644
--- a/reactive/kotlinx-coroutines-reactor/src/Scheduler.kt
+++ b/reactive/kotlinx-coroutines-reactor/src/Scheduler.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.reactor
diff --git a/reactive/kotlinx-coroutines-reactor/test/FlowAsFluxTest.kt b/reactive/kotlinx-coroutines-reactor/test/FlowAsFluxTest.kt
index dbe97b17..cecc8959 100644
--- a/reactive/kotlinx-coroutines-reactor/test/FlowAsFluxTest.kt
+++ b/reactive/kotlinx-coroutines-reactor/test/FlowAsFluxTest.kt
@@ -18,8 +18,8 @@ class FlowAsFluxTest : TestBase() {
(1..4).forEach { i -> emit(createMono(i).awaitFirst()) }
}
.asFlux()
- .contextWrite(Context.of(1, "1"))
- .contextWrite(Context.of(2, "2", 3, "3", 4, "4"))
+ .subscriberContext(Context.of(1, "1"))
+ .subscriberContext(Context.of(2, "2", 3, "3", 4, "4"))
val list = flux.collectList().block()!!
assertEquals(listOf("1", "2", "3", "4"), list)
}
@@ -36,7 +36,7 @@ class FlowAsFluxTest : TestBase() {
it.next("OK")
it.complete()
}
- .contextWrite { ctx ->
+ .subscriberContext { ctx ->
expect(2)
assertEquals("CTX", ctx.get(1))
ctx
@@ -58,7 +58,7 @@ class FlowAsFluxTest : TestBase() {
it.next("OK")
it.complete()
}
- .contextWrite { ctx ->
+ .subscriberContext { ctx ->
expect(2)
assertEquals("CTX", ctx.get(1))
ctx
diff --git a/reactive/kotlinx-coroutines-reactor/test/MonoTest.kt b/reactive/kotlinx-coroutines-reactor/test/MonoTest.kt
index 0271483f..551988b8 100644
--- a/reactive/kotlinx-coroutines-reactor/test/MonoTest.kt
+++ b/reactive/kotlinx-coroutines-reactor/test/MonoTest.kt
@@ -235,7 +235,7 @@ class MonoTest : TestBase() {
} finally {
throw TestException() // would not be able to handle it since mono is disposed
}
- }.contextWrite { Context.of("reactor.onOperatorError.local", handler) }
+ }.subscriberContext { Context.of("reactor.onOperatorError.local", handler) }
mono.subscribe(object : Subscriber<Unit> {
override fun onSubscribe(s: Subscription) {
expect(2)
diff --git a/reactive/kotlinx-coroutines-reactor/test/ReactorContextTest.kt b/reactive/kotlinx-coroutines-reactor/test/ReactorContextTest.kt
index aff29241..3681261b 100644
--- a/reactive/kotlinx-coroutines-reactor/test/ReactorContextTest.kt
+++ b/reactive/kotlinx-coroutines-reactor/test/ReactorContextTest.kt
@@ -18,8 +18,8 @@ class ReactorContextTest : TestBase() {
buildString {
(1..7).forEach { append(ctx.getOrDefault(it, "noValue")) }
}
- } .contextWrite(Context.of(2, "2", 3, "3", 4, "4", 5, "5"))
- .contextWrite { ctx -> ctx.put(6, "6") }
+ } .subscriberContext(Context.of(2, "2", 3, "3", 4, "4", 5, "5"))
+ .subscriberContext { ctx -> ctx.put(6, "6") }
assertEquals(mono.awaitFirst(), "1234567")
}
@@ -29,8 +29,8 @@ class ReactorContextTest : TestBase() {
val ctx = reactorContext()
(1..7).forEach { send(ctx.getOrDefault(it, "noValue")) }
}
- .contextWrite(Context.of(2, "2", 3, "3", 4, "4", 5, "5"))
- .contextWrite { ctx -> ctx.put(6, "6") }
+ .subscriberContext(Context.of(2, "2", 3, "3", 4, "4", 5, "5"))
+ .subscriberContext { ctx -> ctx.put(6, "6") }
val list = flux.collectList().block()!!
assertEquals((1..7).map { it.toString() }, list)
}
@@ -42,7 +42,7 @@ class ReactorContextTest : TestBase() {
buildString {
(1..3).forEach { append(ctx.getOrDefault(it, "noValue")) }
}
- } .contextWrite(Context.of(2, "2"))
+ } .subscriberContext(Context.of(2, "2"))
.awaitFirst()
assertEquals(result, "123")
}
diff --git a/reactive/kotlinx-coroutines-rx2/README.md b/reactive/kotlinx-coroutines-rx2/README.md
index 40fe122f..f0fbeb00 100644
--- a/reactive/kotlinx-coroutines-rx2/README.md
+++ b/reactive/kotlinx-coroutines-rx2/README.md
@@ -52,22 +52,15 @@ Conversion functions:
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
-
[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html
-
<!--- INDEX kotlinx.coroutines.channels -->
-
[ProducerScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-producer-scope/index.html
[ReceiveChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/index.html
-
<!--- INDEX kotlinx.coroutines.flow -->
-
[Flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html
-
<!--- MODULE kotlinx-coroutines-rx2 -->
<!--- INDEX kotlinx.coroutines.rx2 -->
-
[rxCompletable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/rx-completable.html
[rxMaybe]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/rx-maybe.html
[rxSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/rx-single.html
@@ -91,7 +84,6 @@ Conversion functions:
[kotlinx.coroutines.Deferred.asSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/kotlinx.coroutines.-deferred/as-single.html
[kotlinx.coroutines.channels.ReceiveChannel.asObservable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/kotlinx.coroutines.channels.-receive-channel/as-observable.html
[io.reactivex.Scheduler.asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.rx2/io.reactivex.-scheduler/as-coroutine-dispatcher.html
-
<!--- END -->
# Package kotlinx.coroutines.rx2
diff --git a/reactive/kotlinx-coroutines-rx2/build.gradle b/reactive/kotlinx-coroutines-rx2/build.gradle
index 73f76c3d..6d2c4abc 100644
--- a/reactive/kotlinx-coroutines-rx2/build.gradle
+++ b/reactive/kotlinx-coroutines-rx2/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
dependencies {
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxAwait.kt b/reactive/kotlinx-coroutines-rx2/src/RxAwait.kt
index 6e162c9a..d9435b6b 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxAwait.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxAwait.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx2
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxCancellable.kt b/reactive/kotlinx-coroutines-rx2/src/RxCancellable.kt
index 0fe43f1c..f7596f27 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxCancellable.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxCancellable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx2
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxChannel.kt b/reactive/kotlinx-coroutines-rx2/src/RxChannel.kt
index a129196a..633693e7 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxChannel.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx2
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt b/reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt
index d0a43fb1..bc91fa53 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxConvert.kt b/reactive/kotlinx-coroutines-rx2/src/RxConvert.kt
index 14c24942..41c82ed0 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxConvert.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxConvert.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx2
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt b/reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt
index 8dfe9576..78d397c3 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt b/reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt
index f5ed48b9..bfbcb38d 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxObservable.kt b/reactive/kotlinx-coroutines-rx2/src/RxObservable.kt
index 6d11cb9c..2f483879 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxObservable.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxObservable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxScheduler.kt b/reactive/kotlinx-coroutines-rx2/src/RxScheduler.kt
index 0262fc12..9952eb91 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxScheduler.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxScheduler.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx2
diff --git a/reactive/kotlinx-coroutines-rx2/src/RxSingle.kt b/reactive/kotlinx-coroutines-rx2/src/RxSingle.kt
index b8012b6d..23040601 100644
--- a/reactive/kotlinx-coroutines-rx2/src/RxSingle.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/RxSingle.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
diff --git a/reactive/kotlinx-coroutines-rx3/README.md b/reactive/kotlinx-coroutines-rx3/README.md
index f9d3c5a8..3aa73eb9 100644
--- a/reactive/kotlinx-coroutines-rx3/README.md
+++ b/reactive/kotlinx-coroutines-rx3/README.md
@@ -49,21 +49,14 @@ Conversion functions:
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
-
[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/index.html
-
<!--- INDEX kotlinx.coroutines.channels -->
-
[ProducerScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-producer-scope/index.html
-
<!--- INDEX kotlinx.coroutines.flow -->
-
[Flow]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html
-
<!--- MODULE kotlinx-coroutines-rx3 -->
<!--- INDEX kotlinx.coroutines.rx3 -->
-
[rxCompletable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx3/kotlinx.coroutines.rx3/rx-completable.html
[rxMaybe]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx3/kotlinx.coroutines.rx3/rx-maybe.html
[rxSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx3/kotlinx.coroutines.rx3/rx-single.html
@@ -84,7 +77,6 @@ Conversion functions:
[kotlinx.coroutines.Job.asCompletable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx3/kotlinx.coroutines.rx3/kotlinx.coroutines.-job/as-completable.html
[kotlinx.coroutines.Deferred.asSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx3/kotlinx.coroutines.rx3/kotlinx.coroutines.-deferred/as-single.html
[io.reactivex.rxjava3.core.Scheduler.asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx3/kotlinx.coroutines.rx3/io.reactivex.rxjava3.core.-scheduler/as-coroutine-dispatcher.html
-
<!--- END -->
# Package kotlinx.coroutines.rx3
diff --git a/reactive/kotlinx-coroutines-rx3/build.gradle b/reactive/kotlinx-coroutines-rx3/build.gradle
index a5de40d8..ced694ab 100644
--- a/reactive/kotlinx-coroutines-rx3/build.gradle
+++ b/reactive/kotlinx-coroutines-rx3/build.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
targetCompatibility = JavaVersion.VERSION_1_8
diff --git a/reactive/kotlinx-coroutines-rx3/src/RxAwait.kt b/reactive/kotlinx-coroutines-rx3/src/RxAwait.kt
index 8ac0a10c..e52556e4 100644
--- a/reactive/kotlinx-coroutines-rx3/src/RxAwait.kt
+++ b/reactive/kotlinx-coroutines-rx3/src/RxAwait.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx3
diff --git a/reactive/kotlinx-coroutines-rx3/src/RxCancellable.kt b/reactive/kotlinx-coroutines-rx3/src/RxCancellable.kt
index 29951598..0b57b8bb 100644
--- a/reactive/kotlinx-coroutines-rx3/src/RxCancellable.kt
+++ b/reactive/kotlinx-coroutines-rx3/src/RxCancellable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx3
diff --git a/reactive/kotlinx-coroutines-rx3/src/RxChannel.kt b/reactive/kotlinx-coroutines-rx3/src/RxChannel.kt
index 76333f2e..737cf671 100644
--- a/reactive/kotlinx-coroutines-rx3/src/RxChannel.kt
+++ b/reactive/kotlinx-coroutines-rx3/src/RxChannel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx3
diff --git a/reactive/kotlinx-coroutines-rx3/src/RxCompletable.kt b/reactive/kotlinx-coroutines-rx3/src/RxCompletable.kt
index f4c5d7e7..54b412f1 100644
--- a/reactive/kotlinx-coroutines-rx3/src/RxCompletable.kt
+++ b/reactive/kotlinx-coroutines-rx3/src/RxCompletable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx3
diff --git a/reactive/kotlinx-coroutines-rx3/src/RxConvert.kt b/reactive/kotlinx-coroutines-rx3/src/RxConvert.kt
index 63e30f26..0978423a 100644
--- a/reactive/kotlinx-coroutines-rx3/src/RxConvert.kt
+++ b/reactive/kotlinx-coroutines-rx3/src/RxConvert.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx3
diff --git a/reactive/kotlinx-coroutines-rx3/src/RxFlowable.kt b/reactive/kotlinx-coroutines-rx3/src/RxFlowable.kt
index 445a6140..2de46a6a 100644
--- a/reactive/kotlinx-coroutines-rx3/src/RxFlowable.kt
+++ b/reactive/kotlinx-coroutines-rx3/src/RxFlowable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx3
diff --git a/reactive/kotlinx-coroutines-rx3/src/RxMaybe.kt b/reactive/kotlinx-coroutines-rx3/src/RxMaybe.kt
index ca1d5b59..4d55ef5f 100644
--- a/reactive/kotlinx-coroutines-rx3/src/RxMaybe.kt
+++ b/reactive/kotlinx-coroutines-rx3/src/RxMaybe.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx3
diff --git a/reactive/kotlinx-coroutines-rx3/src/RxObservable.kt b/reactive/kotlinx-coroutines-rx3/src/RxObservable.kt
index 7bd07750..102d06ea 100644
--- a/reactive/kotlinx-coroutines-rx3/src/RxObservable.kt
+++ b/reactive/kotlinx-coroutines-rx3/src/RxObservable.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx3
diff --git a/reactive/kotlinx-coroutines-rx3/src/RxScheduler.kt b/reactive/kotlinx-coroutines-rx3/src/RxScheduler.kt
index 24c3f118..a426aea6 100644
--- a/reactive/kotlinx-coroutines-rx3/src/RxScheduler.kt
+++ b/reactive/kotlinx-coroutines-rx3/src/RxScheduler.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx3
diff --git a/reactive/kotlinx-coroutines-rx3/src/RxSingle.kt b/reactive/kotlinx-coroutines-rx3/src/RxSingle.kt
index f4d07fb4..225df93a 100644
--- a/reactive/kotlinx-coroutines-rx3/src/RxSingle.kt
+++ b/reactive/kotlinx-coroutines-rx3/src/RxSingle.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.rx3
diff --git a/settings.gradle b/settings.gradle
index 37fa6757..3a078917 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
pluginManagement {
diff --git a/site/build.gradle.kts b/site/build.gradle.kts
index 003ae762..eba7b1a1 100644
--- a/site/build.gradle.kts
+++ b/site/build.gradle.kts
@@ -1,7 +1,3 @@
-/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
import groovy.lang.*
/*
diff --git a/site/docs/index.md b/site/docs/index.md
index 92eb0948..3e6bb934 100644
--- a/site/docs/index.md
+++ b/site/docs/index.md
@@ -18,7 +18,6 @@ Library support for Kotlin coroutines. This reference is a companion to
| [kotlinx-coroutines-reactive](kotlinx-coroutines-reactive) | Utilities for [Reactive Streams](https://www.reactive-streams.org) |
| [kotlinx-coroutines-reactor](kotlinx-coroutines-reactor) | Utilities for [Reactor](https://projectreactor.io) |
| [kotlinx-coroutines-rx2](kotlinx-coroutines-rx2) | Utilities for [RxJava 2.x](https://github.com/ReactiveX/RxJava) |
-| [kotlinx-coroutines-rx3](kotlinx-coroutines-rx3) | Utilities for [RxJava 3.x](https://github.com/ReactiveX/RxJava) |
| [kotlinx-coroutines-android](kotlinx-coroutines-android) | `Main` dispatcher for Android applications |
| [kotlinx-coroutines-javafx](kotlinx-coroutines-javafx) | `JavaFx` dispatcher for JavaFX UI applications |
| [kotlinx-coroutines-swing](kotlinx-coroutines-swing) | `Swing` dispatcher for Swing UI applications |
diff --git a/stdlib-stubs/build.gradle.kts b/stdlib-stubs/build.gradle.kts
index 201ac43c..6b9d6555 100644
--- a/stdlib-stubs/build.gradle.kts
+++ b/stdlib-stubs/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
diff --git a/stdlib-stubs/src/Continuation.kt b/stdlib-stubs/src/Continuation.kt
index 66d672af..662f9dae 100644
--- a/stdlib-stubs/src/Continuation.kt
+++ b/stdlib-stubs/src/Continuation.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlin.coroutines
diff --git a/stdlib-stubs/src/ContinuationInterceptor.kt b/stdlib-stubs/src/ContinuationInterceptor.kt
index 5c96e82d..ebf0a335 100644
--- a/stdlib-stubs/src/ContinuationInterceptor.kt
+++ b/stdlib-stubs/src/ContinuationInterceptor.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlin.coroutines
diff --git a/stdlib-stubs/src/CoroutineContext.kt b/stdlib-stubs/src/CoroutineContext.kt
index 6861198d..ac216a0b 100644
--- a/stdlib-stubs/src/CoroutineContext.kt
+++ b/stdlib-stubs/src/CoroutineContext.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlin.coroutines
diff --git a/stdlib-stubs/src/Result.kt b/stdlib-stubs/src/Result.kt
index d873ac89..611074a7 100644
--- a/stdlib-stubs/src/Result.kt
+++ b/stdlib-stubs/src/Result.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlin
diff --git a/ui/coroutines-guide-ui.md b/ui/coroutines-guide-ui.md
index 7673c8f2..9c1251fe 100644
--- a/ui/coroutines-guide-ui.md
+++ b/ui/coroutines-guide-ui.md
@@ -1,7 +1,7 @@
# Guide to UI programming with coroutines
This guide assumes familiarity with basic coroutine concepts that are
-covered in [Guide to kotlinx.coroutines](../docs/topics/coroutines-guide.md) and gives specific
+covered in [Guide to kotlinx.coroutines](../docs/coroutines-guide.md) and gives specific
examples on how to use coroutines in UI applications.
All UI application libraries have one thing in common. They have the single main thread where all state of the UI
@@ -110,7 +110,7 @@ Add dependencies on `kotlinx-coroutines-android` module to the `dependencies { .
`app/build.gradle` file:
```groovy
-implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3"
+implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1"
```
You can clone [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) project from GitHub onto your
@@ -456,7 +456,7 @@ See [the corresponding documentation](https://developer.android.com/topic/librar
Parent-child relation between jobs forms a hierarchy. A coroutine that performs some background job on behalf of
the activity can create further children coroutines. The whole tree of coroutines gets cancelled
when the parent job is cancelled. An example of that is shown in the
-["Children of a coroutine"](../docs/topics/coroutine-context-and-dispatchers.md#children-of-a-coroutine) section of the guide to coroutines.
+["Children of a coroutine"](../docs/coroutine-context-and-dispatchers.md#children-of-a-coroutine) section of the guide to coroutines.
<!--- CLEAR -->
@@ -607,7 +607,6 @@ After delay
<!--- MODULE kotlinx-coroutines-core -->
<!--- INDEX kotlinx.coroutines -->
-
[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
@@ -619,20 +618,15 @@ After delay
[CoroutineStart]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html
[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
[CoroutineStart.UNDISPATCHED]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/-u-n-d-i-s-p-a-t-c-h-e-d.html
-
<!--- INDEX kotlinx.coroutines.channels -->
-
[actor]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/actor.html
[SendChannel.offer]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/offer.html
[SendChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-send-channel/index.html
[Channel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel/index.html
[Channel.CONFLATED]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel/-c-o-n-f-l-a-t-e-d.html
-
<!--- MODULE kotlinx-coroutines-javafx -->
<!--- INDEX kotlinx.coroutines.javafx -->
-
[kotlinx.coroutines.Dispatchers.JavaFx]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-javafx/kotlinx.coroutines.javafx/kotlinx.coroutines.-dispatchers/-java-fx.html
-
<!--- MODULE kotlinx-coroutines-android -->
<!--- INDEX kotlinx.coroutines.android -->
<!--- END -->
diff --git a/ui/knit.properties b/ui/knit.properties
index 76a1d77a..3ad209a4 100644
--- a/ui/knit.properties
+++ b/ui/knit.properties
@@ -1,7 +1,7 @@
#
-# Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+# Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
#
knit.dir=kotlinx-coroutines-javafx/test/guide/
knit.package=kotlinx.coroutines.javafx.guide
-knit.include=knit.code.include
+knit.include=knit.code.include \ No newline at end of file
diff --git a/ui/kotlinx-coroutines-android/android-unit-tests/build.gradle.kts b/ui/kotlinx-coroutines-android/android-unit-tests/build.gradle.kts
index 18adf4bd..2acc058d 100644
--- a/ui/kotlinx-coroutines-android/android-unit-tests/build.gradle.kts
+++ b/ui/kotlinx-coroutines-android/android-unit-tests/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
dependencies {
diff --git a/ui/kotlinx-coroutines-android/android-unit-tests/src/EmptyCoroutineScopeImpl.kt b/ui/kotlinx-coroutines-android/android-unit-tests/src/EmptyCoroutineScopeImpl.kt
index 1c5c6abd..a08f44ad 100644
--- a/ui/kotlinx-coroutines-android/android-unit-tests/src/EmptyCoroutineScopeImpl.kt
+++ b/ui/kotlinx-coroutines-android/android-unit-tests/src/EmptyCoroutineScopeImpl.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.android
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/build.gradle.kts b/ui/kotlinx-coroutines-android/animation-app/app/build.gradle.kts
new file mode 100644
index 00000000..517f1f63
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/build.gradle.kts
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ id("com.android.application")
+ kotlin("android")
+ kotlin("android.extensions")
+}
+
+android {
+ compileSdkVersion = "29"
+ defaultConfig {
+ applicationId = "org.jetbrains.kotlinx.animation"
+ minSdkVersion(14)
+ targetSdkVersion(29)
+ versionCode = 1
+ versionName = "1.0"
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+}
+
+dependencies {
+ implementation("androidx.appcompat:appcompat:1.0.2")
+ implementation("androidx.constraintlayout:constraintlayout:1.1.3")
+ implementation("com.google.android.material:material:1.0.0")
+ implementation("androidx.lifecycle:lifecycle-extensions:2.0.0")
+
+ implementation(kotlin("stdlib-jdk7"))
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:${property("coroutines_version")}")
+
+ testImplementation("junit:junit:4.12")
+ androidTestImplementation("androidx.test:runner:1.2.0")
+ androidTestImplementation("androidx.test.espresso:espresso-core:3.2.0")
+}
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/AndroidManifest.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..34d0dd14
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.jetbrains.kotlinx.animation">
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity
+ android:name="org.jetbrains.kotlinx.animation.MainActivity"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme.NoActionBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/Animation.kt b/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/Animation.kt
new file mode 100644
index 00000000..88e0baee
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/Animation.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.kotlinx.animation
+
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModel
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.RectF
+import android.util.AttributeSet
+import android.view.View
+import kotlinx.coroutines.*
+import kotlinx.coroutines.android.*
+import java.util.*
+
+sealed class AnimatedShape {
+ var x = 0.5f // 0 .. 1
+ var y = 0.5f // 0 .. 1
+ var color = Color.BLACK
+ var r = 0.05f
+}
+
+class AnimatedCircle : AnimatedShape()
+class AnimatedSquare : AnimatedShape()
+
+private val NO_SHAPES = emptySet<AnimatedShape>()
+
+class AnimationView(
+ context: Context, attributeSet: AttributeSet
+) : View(context, attributeSet), Observer<Set<AnimatedShape>> {
+ private var shapes = NO_SHAPES
+ private val paint = Paint()
+ private val rect = RectF()
+
+ override fun onChanged(shapes: Set<AnimatedShape>?) {
+ this.shapes = shapes ?: NO_SHAPES
+ invalidate()
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ val scale = minOf(width, height) / 2.0f
+ shapes.forEach { shape ->
+ val x = (shape.x - 0.5f) * scale + width / 2
+ val y = (shape.y - 0.5f) * scale + height / 2
+ val r = shape.r * scale
+ rect.set(x - r, y - r, x + r, y + r)
+ paint.color = shape.color
+ when (shape) {
+ is AnimatedCircle -> canvas.drawArc(rect, 0.0f, 360.0f, true, paint)
+ is AnimatedSquare -> canvas.drawRect(rect, paint)
+ }
+ }
+ }
+}
+
+private val rnd = Random()
+
+class AnimationModel : ViewModel(), CoroutineScope {
+
+ override val coroutineContext = Job() + Dispatchers.Main
+
+ private val shapes = MutableLiveData<Set<AnimatedShape>>()
+
+ fun observe(owner: LifecycleOwner, observer: Observer<Set<AnimatedShape>>) =
+ shapes.observe(owner, observer)
+
+ fun update(shape: AnimatedShape) {
+ val old = shapes.value ?: NO_SHAPES
+ shapes.value = if (shape in old) old else old + shape
+ }
+
+ fun addAnimation() {
+ launch {
+ animateShape(if (rnd.nextBoolean()) AnimatedCircle() else AnimatedSquare())
+ }
+ }
+
+ fun clearAnimations() {
+ coroutineContext.cancelChildren()
+ shapes.value = NO_SHAPES
+ }
+}
+
+private fun norm(x: Float, y: Float) = Math.hypot(x.toDouble(), y.toDouble()).toFloat()
+
+private const val ACC = 1e-18f
+private const val MAX_SPEED = 2e-9f // in screen_fraction/nanos
+private const val INIT_POS = 0.8f
+
+private fun Random.nextColor() = Color.rgb(nextInt(256), nextInt(256), nextInt(256))
+private fun Random.nextPos() = nextFloat() * INIT_POS + (1 - INIT_POS) / 2
+private fun Random.nextSpeed() = nextFloat() * MAX_SPEED - MAX_SPEED / 2
+
+suspend fun AnimationModel.animateShape(shape: AnimatedShape) {
+ shape.x = rnd.nextPos()
+ shape.y = rnd.nextPos()
+ shape.color = rnd.nextColor()
+ var sx = rnd.nextSpeed()
+ var sy = rnd.nextSpeed()
+ var time = System.nanoTime() // nanos
+ var checkTime = time
+ while (true) {
+ val dt = time.let { old -> awaitFrame().also { time = it } - old }
+ if (dt > 0.5e9) continue // don't animate through over a half second lapses
+ val dx = shape.x - 0.5f
+ val dy = shape.y - 0.5f
+ val dn = norm(dx, dy)
+ sx -= dx / dn * ACC * dt
+ sy -= dy / dn * ACC * dt
+ val sn = norm(sx, sy)
+ val trim = sn.coerceAtMost(MAX_SPEED)
+ sx = sx / sn * trim
+ sy = sy / sn * trim
+ shape.x += sx * dt
+ shape.y += sy * dt
+ update(shape)
+ // check once a second
+ if (time > checkTime + 1e9) {
+ checkTime = time
+ when (rnd.nextInt(20)) { // roll d20
+ 0 -> {
+ animateColor(shape) // wait a second & animate color
+ time = awaitFrame() // and sync with next frame
+ }
+ 1 -> { // random speed change
+ sx = rnd.nextSpeed()
+ sy = rnd.nextSpeed()
+ }
+ }
+ }
+ }
+}
+
+suspend fun AnimationModel.animateColor(shape: AnimatedShape) {
+ val duration = 1e9f
+ val startTime = System.nanoTime()
+ val aColor = shape.color
+ val bColor = rnd.nextColor()
+ while (true) {
+ val time = awaitFrame()
+ val b = (time - startTime) / duration
+ if (b >= 1.0f) break
+ val a = 1 - b
+ shape.color = Color.rgb(
+ (Color.red(bColor) * b + Color.red(aColor) * a).toInt(),
+ (Color.green(bColor) * b + Color.green(aColor) * a).toInt(),
+ (Color.blue(bColor) * b + Color.blue(aColor) * a).toInt()
+ )
+ update(shape)
+ }
+ shape.color = bColor
+ update(shape)
+}
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/MainActivity.kt b/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/MainActivity.kt
new file mode 100644
index 00000000..756db9bb
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/MainActivity.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.kotlinx.animation
+
+import androidx.lifecycle.ViewModelProviders
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import kotlinx.android.synthetic.main.activity_main.*
+import kotlinx.android.synthetic.main.content_main.*
+
+class MainActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ setSupportActionBar(toolbar)
+
+ val animationModel = ViewModelProviders.of(this).get(AnimationModel::class.java)
+ animationModel.observe(this, animationView)
+
+ addButton.setOnClickListener {
+ animationModel.addAnimation()
+ }
+
+ removeButton.setOnClickListener {
+ animationModel.clearAnimations()
+ }
+ }
+}
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 00000000..c7bd21db
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportHeight="108"
+ android:viewportWidth="108">
+ <path
+ android:fillType="evenOdd"
+ android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
+ android:strokeColor="#00000000"
+ android:strokeWidth="1">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="78.5885"
+ android:endY="90.9159"
+ android:startX="48.7653"
+ android:startY="61.0927"
+ android:type="linear">
+ <item
+ android:color="#44000000"
+ android:offset="0.0" />
+ <item
+ android:color="#00000000"
+ android:offset="1.0" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path
+ android:fillColor="#FFFFFF"
+ android:fillType="nonZero"
+ android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
+ android:strokeColor="#00000000"
+ android:strokeWidth="1" />
+</vector>
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/drawable/ic_launcher_background.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..d5fccc53
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportHeight="108"
+ android:viewportWidth="108">
+ <path
+ android:fillColor="#26A69A"
+ android:pathData="M0,0h108v108h-108z" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M9,0L9,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,0L19,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,0L29,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,0L39,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,0L49,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,0L59,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,0L69,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,0L79,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M89,0L89,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M99,0L99,108"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,9L108,9"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,19L108,19"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,29L108,29"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,39L108,39"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,49L108,49"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,59L108,59"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,69L108,69"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,79L108,79"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,89L108,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,99L108,99"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,29L89,29"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,39L89,39"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,49L89,49"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,59L89,59"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,69L89,69"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,79L89,79"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,19L29,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,19L39,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,19L49,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,19L59,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,19L69,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,19L79,89"
+ android:strokeColor="#33FFFFFF"
+ android:strokeWidth="0.8" />
+</vector>
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/activity_main.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..8e06e901
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ -->
+
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="org.jetbrains.kotlinx.animation.MainActivity">
+
+ <com.google.android.material.appbar.AppBarLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:theme="@style/AppTheme.AppBarOverlay">
+
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimary"
+ app:popupTheme="@style/AppTheme.PopupOverlay" />
+
+ </com.google.android.material.appbar.AppBarLayout>
+
+ <include layout="@layout/content_main" />
+
+ <com.google.android.material.floatingactionbutton.FloatingActionButton
+ android:id="@+id/addButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|end"
+ android:layout_margin="@dimen/fab_margin"
+ app:backgroundTint="@color/colorPrimary"
+ app:srcCompat="@android:drawable/ic_input_add" />
+
+ <com.google.android.material.floatingactionbutton.FloatingActionButton
+ android:id="@+id/removeButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:layout_margin="@dimen/fab_margin"
+ app:backgroundTint="@color/colorPrimary"
+ app:srcCompat="@android:drawable/ic_delete" />
+
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/content_main.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/content_main.xml
new file mode 100644
index 00000000..2019bb5d
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/content_main.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior"
+ tools:context="org.jetbrains.kotlinx.animation.MainActivity"
+ tools:showIn="@layout/activity_main">
+
+ <org.jetbrains.kotlinx.animation.AnimationView
+ android:id="@+id/animationView"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..8bc717e4
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ -->
+
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 00000000..8bc717e4
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ -->
+
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-hdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..a2f59082
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 00000000..1b523998
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-mdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..ff10afd6
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 00000000..115a4c76
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..dcd3cd80
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..459ca609
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..8ca12fe0
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..8e19b410
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..b824ebdd
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..4c19a13c
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/colors.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..9ad7e369
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="colorPrimary">#3f51b5</color>
+ <color name="colorPrimaryDark">#303F9F</color>
+ <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/dimens.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..59a0b0c4
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/dimens.xml
@@ -0,0 +1,3 @@
+<resources>
+ <dimen name="fab_margin">16dp</dimen>
+</resources>
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/strings.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..cd3f467b
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+<resources>
+ <string name="app_name">Animation</string>
+ <string name="action_settings">Settings</string>
+</resources>
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/styles.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..545b9c6d
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+ <style name="AppTheme.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+
+ <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
+
+ <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
+
+</resources>
diff --git a/ui/kotlinx-coroutines-android/animation-app/build.gradle.kts b/ui/kotlinx-coroutines-android/animation-app/build.gradle.kts
new file mode 100644
index 00000000..9cd0c592
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/build.gradle.kts
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath("com.android.tools.build:gradle:3.5.0")
+ classpath(kotlin("gradle-plugin", property("kotlin_version") as String))
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+task<Delete>("clean") {
+ delete(rootProject.buildDir)
+}
diff --git a/ui/kotlinx-coroutines-android/animation-app/gradle.properties b/ui/kotlinx-coroutines-android/animation-app/gradle.properties
new file mode 100644
index 00000000..c4aa6758
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/gradle.properties
@@ -0,0 +1,28 @@
+#
+# Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+kotlin_version=1.4.0
+coroutines_version=1.4.1
+
+android.useAndroidX=true
+android.enableJetifier=true
+
diff --git a/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.jar b/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..490fda85
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.properties b/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..dbe85eef
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.1-all.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/ui/kotlinx-coroutines-android/animation-app/gradlew b/ui/kotlinx-coroutines-android/animation-app/gradlew
new file mode 100755
index 00000000..2fe81a7d
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/ui/kotlinx-coroutines-android/animation-app/gradlew.bat b/ui/kotlinx-coroutines-android/animation-app/gradlew.bat
new file mode 100644
index 00000000..62bd9b9c
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/gradlew.bat
@@ -0,0 +1,103 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ui/kotlinx-coroutines-android/animation-app/settings.gradle.kts b/ui/kotlinx-coroutines-android/animation-app/settings.gradle.kts
new file mode 100644
index 00000000..b05d810b
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/animation-app/settings.gradle.kts
@@ -0,0 +1,5 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+include(":app")
diff --git a/ui/kotlinx-coroutines-android/build.gradle.kts b/ui/kotlinx-coroutines-android/build.gradle.kts
index 08d45ffe..4f247883 100644
--- a/ui/kotlinx-coroutines-android/build.gradle.kts
+++ b/ui/kotlinx-coroutines-android/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink
@@ -10,10 +10,6 @@ configurations {
create("r8")
}
-repositories {
- mavenCentral()
- jcenter() // https://youtrack.jetbrains.com/issue/IDEA-261387
-}
dependencies {
compileOnly("com.google.android:android:${version("android")}")
compileOnly("androidx.annotation:annotation:${version("androidx_annotation")}")
diff --git a/ui/kotlinx-coroutines-android/example-app/.gitignore b/ui/kotlinx-coroutines-android/example-app/.gitignore
new file mode 100644
index 00000000..03d649e1
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/.gitignore
@@ -0,0 +1,7 @@
+local.properties
+.gradle
+.idea
+build
+example-app.iml
+app/build
+app/app.iml
diff --git a/ui/kotlinx-coroutines-android/example-app/app/build.gradle.kts b/ui/kotlinx-coroutines-android/example-app/app/build.gradle.kts
new file mode 100644
index 00000000..39bba5bf
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/build.gradle.kts
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ id("com.android.application")
+ kotlin("android")
+ kotlin("android.extensions")
+}
+
+android {
+ compileSdkVersion = "29"
+ defaultConfig {
+ applicationId = "com.example.app"
+ minSdkVersion(14)
+ targetSdkVersion(29)
+ versionCode = 1
+ versionName = "1.0"
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+}
+
+dependencies {
+ implementation("androidx.appcompat:appcompat:1.0.2")
+ implementation("androidx.constraintlayout:constraintlayout:1.1.3")
+ implementation("com.google.android.material:material:1.0.0")
+
+ implementation(kotlin("stdlib-jdk7"))
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:${property("coroutines_version")}")
+
+ testImplementation("junit:junit:4.12")
+ androidTestImplementation("androidx.test:runner:1.2.0")
+ androidTestImplementation("androidx.test.espresso:espresso-core:3.2.0")
+}
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/AndroidManifest.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..b8b2a76c
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.app">
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme.NoActionBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/java/com/example/app/MainActivity.kt b/ui/kotlinx-coroutines-android/example-app/app/src/main/java/com/example/app/MainActivity.kt
new file mode 100644
index 00000000..47bd16cc
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/java/com/example/app/MainActivity.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package com.example.app
+
+import android.os.Bundle
+import com.google.android.material.floatingactionbutton.FloatingActionButton
+import androidx.appcompat.app.AppCompatActivity
+import android.view.Menu
+import android.view.MenuItem
+import android.widget.TextView
+import kotlinx.android.synthetic.main.activity_main.*
+import kotlinx.android.synthetic.main.content_main.*
+
+class MainActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ setSupportActionBar(toolbar)
+ setup(hello, fab)
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ menuInflater.inflate(R.menu.menu_main, menu)
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ val id = item.itemId
+ if (id == R.id.action_settings) return true
+ return super.onOptionsItemSelected(item)
+ }
+}
+
+fun setup(hello: TextView, fab: FloatingActionButton) {
+ // placeholder
+}
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/activity_main.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..0b728022
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ -->
+
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.app.MainActivity">
+
+ <com.google.android.material.appbar.AppBarLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:theme="@style/AppTheme.AppBarOverlay">
+
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimary"
+ app:popupTheme="@style/AppTheme.PopupOverlay" />
+
+ </com.google.android.material.appbar.AppBarLayout>
+
+ <include layout="@layout/content_main" />
+
+ <com.google.android.material.floatingactionbutton.FloatingActionButton
+ android:id="@+id/fab"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|end"
+ android:layout_margin="@dimen/fab_margin"
+ app:srcCompat="@android:drawable/ic_dialog_email" />
+
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/content_main.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/content_main.xml
new file mode 100644
index 00000000..77525183
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/content_main.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior"
+ tools:context="com.example.app.MainActivity"
+ tools:showIn="@layout/activity_main">
+
+ <TextView
+ android:id="@+id/hello"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Hello World!"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/menu/menu_main.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/menu/menu_main.xml
new file mode 100644
index 00000000..c4ad0980
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/menu/menu_main.xml
@@ -0,0 +1,10 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context="com.example.app.MainActivity">
+ <item
+ android:id="@+id/action_settings"
+ android:orderInCategory="100"
+ android:title="@string/action_settings"
+ app:showAsAction="never" />
+</menu>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..cde69bcc
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 00000000..9a078e3e
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..c133a0cb
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 00000000..efc028a6
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..bfa42f0e
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..3af2608a
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..324e72cd
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..9bec2e62
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..aee44e13
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..34947cd6
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/colors.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..3ab3e9cb
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="colorPrimary">#3F51B5</color>
+ <color name="colorPrimaryDark">#303F9F</color>
+ <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/dimens.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..59a0b0c4
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/dimens.xml
@@ -0,0 +1,3 @@
+<resources>
+ <dimen name="fab_margin">16dp</dimen>
+</resources>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/strings.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..a94b2dfb
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+<resources>
+ <string name="app_name">ExampleApp</string>
+ <string name="action_settings">Settings</string>
+</resources>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/styles.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..d4ea9ae7
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat">
+ <!-- Customize your theme here. -->
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+ <style name="AppTheme.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+
+ <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
+
+ <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
+
+</resources>
diff --git a/ui/kotlinx-coroutines-android/example-app/build.gradle.kts b/ui/kotlinx-coroutines-android/example-app/build.gradle.kts
new file mode 100644
index 00000000..9cd0c592
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/build.gradle.kts
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath("com.android.tools.build:gradle:3.5.0")
+ classpath(kotlin("gradle-plugin", property("kotlin_version") as String))
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+task<Delete>("clean") {
+ delete(rootProject.buildDir)
+}
diff --git a/ui/kotlinx-coroutines-android/example-app/gradle.properties b/ui/kotlinx-coroutines-android/example-app/gradle.properties
new file mode 100644
index 00000000..c4aa6758
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/gradle.properties
@@ -0,0 +1,28 @@
+#
+# Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+kotlin_version=1.4.0
+coroutines_version=1.4.1
+
+android.useAndroidX=true
+android.enableJetifier=true
+
diff --git a/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.jar b/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..490fda85
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties b/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..dbe85eef
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.1-all.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/ui/kotlinx-coroutines-android/example-app/gradlew b/ui/kotlinx-coroutines-android/example-app/gradlew
new file mode 100755
index 00000000..2fe81a7d
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/ui/kotlinx-coroutines-android/example-app/gradlew.bat b/ui/kotlinx-coroutines-android/example-app/gradlew.bat
new file mode 100644
index 00000000..62bd9b9c
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/gradlew.bat
@@ -0,0 +1,103 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ui/kotlinx-coroutines-android/example-app/settings.gradle.kts b/ui/kotlinx-coroutines-android/example-app/settings.gradle.kts
new file mode 100644
index 00000000..15a801b1
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/settings.gradle.kts
@@ -0,0 +1 @@
+include(":app")
diff --git a/ui/kotlinx-coroutines-android/src/AndroidExceptionPreHandler.kt b/ui/kotlinx-coroutines-android/src/AndroidExceptionPreHandler.kt
index 7d06752c..b105e5b8 100644
--- a/ui/kotlinx-coroutines-android/src/AndroidExceptionPreHandler.kt
+++ b/ui/kotlinx-coroutines-android/src/AndroidExceptionPreHandler.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.android
diff --git a/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt b/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt
index d693e2bc..af79da7c 100644
--- a/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt
+++ b/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("unused")
diff --git a/ui/kotlinx-coroutines-javafx/build.gradle.kts b/ui/kotlinx-coroutines-javafx/build.gradle.kts
index 9e30590c..112441e0 100644
--- a/ui/kotlinx-coroutines-javafx/build.gradle.kts
+++ b/ui/kotlinx-coroutines-javafx/build.gradle.kts
@@ -1,22 +1,15 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
plugins {
- id("org.openjfx.javafxplugin") version "0.0.9"
+ id("org.openjfx.javafxplugin")
}
javafx {
version = version("javafx")
modules = listOf("javafx.controls")
- configuration = "compileOnly"
-}
-
-sourceSets {
- test.configure {
- compileClasspath += configurations.compileOnly
- runtimeClasspath += configurations.compileOnly
- }
+ configuration = "compile"
}
val JDK_18: String? by lazy {
diff --git a/ui/kotlinx-coroutines-javafx/src/JavaFxConvert.kt b/ui/kotlinx-coroutines-javafx/src/JavaFxConvert.kt
index 1cbf9b6f..c7fcb1c2 100644
--- a/ui/kotlinx-coroutines-javafx/src/JavaFxConvert.kt
+++ b/ui/kotlinx-coroutines-javafx/src/JavaFxConvert.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.javafx
diff --git a/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt b/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt
index 0a35cbf2..c3069d63 100644
--- a/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt
+++ b/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.javafx
diff --git a/ui/kotlinx-coroutines-swing/build.gradle.kts b/ui/kotlinx-coroutines-swing/build.gradle.kts
index b8ca906a..b834f29f 100644
--- a/ui/kotlinx-coroutines-swing/build.gradle.kts
+++ b/ui/kotlinx-coroutines-swing/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
dependencies {
diff --git a/ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt b/ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt
index d2d9b786..054ed1f6 100644
--- a/ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt
+++ b/ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.swing
diff --git a/ui/kotlinx-coroutines-swing/test/examples/swing-example.kt b/ui/kotlinx-coroutines-swing/test/examples/swing-example.kt
new file mode 100644
index 00000000..cadb4681
--- /dev/null
+++ b/ui/kotlinx-coroutines-swing/test/examples/swing-example.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package examples
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.swing.*
+import java.text.*
+import java.util.*
+import java.util.concurrent.*
+import kotlin.coroutines.*
+
+fun log(msg: String) = println("${SimpleDateFormat("yyyyMMdd-HHmmss.sss").format(Date())} [${Thread.currentThread().name}] $msg")
+
+suspend fun makeRequest(): String {
+ log("Making request...")
+ return suspendCoroutine { c ->
+ ForkJoinPool.commonPool().execute {
+ c.resume("Result of the request")
+ }
+ }
+}
+
+fun display(result: String) {
+ log("Displaying result '$result'")
+}
+
+fun main(args: Array<String>) = runBlocking(Dispatchers.Swing) {
+ try {
+ // suspend while asynchronously making request
+ val result = makeRequest()
+ // example.display result in UI, here Swing dispatcher ensures that we always stay in event dispatch thread
+ display(result)
+ } catch (exception: Throwable) {
+ // process exception
+ }
+}
+