SelectClause1.invoke(block: suspend (Q) -> R) = - ClauseData(clauseObject, regFunc, processResFunc, null, block, onCancellationConstructor).register() + ClauseData(clauseObject, regFunc, processResFunc, null, block, onCancellationConstructor).register() override fun SelectClause2
.invoke(param: P, block: suspend (Q) -> R) = - ClauseData
(clauseObject, regFunc, processResFunc, param, block, onCancellationConstructor).register() + ClauseData(clauseObject, regFunc, processResFunc, param, block, onCancellationConstructor).register() /** * Attempts to register this `select` clause. If another clause is already selected, @@ -461,10 +461,10 @@ internal open class SelectImplementation constructor( * updates the state to this clause reference. */ @JvmName("register") - internal fun ClauseData .register(reregister: Boolean = false) { + internal fun ClauseData.register(reregister: Boolean = false) { assert { state.value !== STATE_CANCELLED } // Is there already selected clause? - if (state.value.let { it is ClauseData<*> }) return + if (state.value.let { it is SelectImplementation<*>.ClauseData }) return // For new clauses, check that there does not exist // another clause with the same object. if (!reregister) checkClauseObject(clauseObject) @@ -569,7 +569,7 @@ internal open class SelectImplementation constructor( curState.forEach { reregisterClause(it) } } // This `select` operation became completed during clauses re-registration. - curState is ClauseData<*> -> { + curState is SelectImplementation<*>.ClauseData -> { cont.resume(Unit, curState.createOnCancellationAction(this, internalResult)) return@sc } @@ -628,7 +628,7 @@ internal open class SelectImplementation constructor( } } // Already selected. - STATE_COMPLETED, is ClauseData<*> -> return TRY_SELECT_ALREADY_SELECTED + STATE_COMPLETED, is SelectImplementation<*>.ClauseData -> return TRY_SELECT_ALREADY_SELECTED // Already cancelled. STATE_CANCELLED -> return TRY_SELECT_CANCELLED // This select is still in REGISTRATION phase, re-register the clause @@ -650,7 +650,7 @@ internal open class SelectImplementation constructor( * If the reference to the list of clauses is already cleared due to completion/cancellation, * this function returns `null` */ - private fun findClause(clauseObject: Any): ClauseData ? { + private fun findClause(clauseObject: Any): ClauseData? { // Read the list of clauses. If the `clauses` field is already `null`, // the clean-up phase has already completed, and this function returns `null`. val clauses = this.clauses ?: return null @@ -678,7 +678,7 @@ internal open class SelectImplementation constructor( assert { isSelected } // Get the selected clause. @Suppress("UNCHECKED_CAST") - val selectedClause = state.value as ClauseData + val selectedClause = state.value as SelectImplementation .ClauseData // Perform the clean-up before the internal result processing and // the user-specified block invocation to guarantee the absence // of memory leaks. Collect the internal result before that. @@ -700,7 +700,7 @@ internal open class SelectImplementation constructor( } } - private suspend fun processResultAndInvokeBlockRecoveringException(clause: ClauseData , internalResult: Any?): R = + private suspend fun processResultAndInvokeBlockRecoveringException(clause: ClauseData, internalResult: Any?): R = try { val blockArgument = clause.processResult(internalResult) clause.invokeBlock(blockArgument) @@ -716,7 +716,7 @@ internal open class SelectImplementation constructor( * [SelectInstance.disposeOnCompletion] during * clause registrations. */ - private fun cleanup(selectedClause: ClauseData ) { + private fun cleanup(selectedClause: ClauseData) { assert { state.value == selectedClause } // Read the list of clauses. If the `clauses` field is already `null`, // a concurrent clean-up procedure has already completed, and it is safe to finish. @@ -757,7 +757,7 @@ internal open class SelectImplementation constructor( /** * Each `select` clause is internally represented with a [ClauseData] instance. */ - internal class ClauseData ( + internal inner class ClauseData( @JvmField val clauseObject: Any, // the object of this `select` clause: Channel, Mutex, Job, ... private val regFunc: RegistrationFunction, private val processResFunc: ProcessResultFunction, @@ -825,7 +825,7 @@ internal open class SelectImplementation constructor( fun dispose() { with(disposableHandleOrSegment) { if (this is Segment<*>) { - this.onCancellation(indexInSegment, null) + this.onCancellation(indexInSegment, null, context) } else { (this as? DisposableHandle)?.dispose() } diff --git a/kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt b/kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt index 5329a15a0f..a4b1e04341 100644 --- a/kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt +++ b/kotlinx-coroutines-core/common/src/selects/SelectUnbiased.kt @@ -38,7 +38,7 @@ public suspend inline fun selectUnbiased(crossinline builder: SelectBuilder< */ @PublishedApi internal open class UnbiasedSelectImplementation (context: CoroutineContext) : SelectImplementation (context) { - private val clausesToRegister: MutableList > = arrayListOf() + private val clausesToRegister: MutableList = arrayListOf() override fun SelectClause0.invoke(block: suspend () -> R) { clausesToRegister += ClauseData(clauseObject, regFunc, processResFunc, PARAM_CLAUSE_0, block, onCancellationConstructor) diff --git a/kotlinx-coroutines-core/common/src/sync/Semaphore.kt b/kotlinx-coroutines-core/common/src/sync/Semaphore.kt index 8ef888d801..9f30721df5 100644 --- a/kotlinx-coroutines-core/common/src/sync/Semaphore.kt +++ b/kotlinx-coroutines-core/common/src/sync/Semaphore.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.* import kotlinx.coroutines.internal.* import kotlinx.coroutines.selects.* import kotlin.contracts.* +import kotlin.coroutines.* import kotlin.js.* import kotlin.math.* @@ -378,7 +379,7 @@ private class SemaphoreSegment(id: Long, prev: SemaphoreSegment?, pointers: Int) // Cleans the acquirer slot located by the specified index // and removes this segment physically if all slots are cleaned. - override fun onCancellation(index: Int, cause: Throwable?) { + override fun onCancellation(index: Int, cause: Throwable?, context: CoroutineContext) { // Clean the slot set(index, CANCELLED) // Remove this segment if needed diff --git a/kotlinx-coroutines-core/common/test/CancellableContinuationHandlersTest.kt b/kotlinx-coroutines-core/common/test/CancellableContinuationHandlersTest.kt index bd6a44fff8..54bc18c17b 100644 --- a/kotlinx-coroutines-core/common/test/CancellableContinuationHandlersTest.kt +++ b/kotlinx-coroutines-core/common/test/CancellableContinuationHandlersTest.kt @@ -167,7 +167,7 @@ class CancellableContinuationHandlersTest : TestBase() { override val numberOfSlots: Int get() = 0 var invokeOnCancellationCalled = false - override fun onCancellation(index: Int, cause: Throwable?) { + override fun onCancellation(index: Int, cause: Throwable?, context: CoroutineContext) { invokeOnCancellationCalled = true } } diff --git a/kotlinx-coroutines-core/jvm/src/debug/internal/DebugProbesImpl.kt b/kotlinx-coroutines-core/jvm/src/debug/internal/DebugProbesImpl.kt index ade48bbb5e..a7432ef658 100644 --- a/kotlinx-coroutines-core/jvm/src/debug/internal/DebugProbesImpl.kt +++ b/kotlinx-coroutines-core/jvm/src/debug/internal/DebugProbesImpl.kt @@ -182,8 +182,8 @@ internal object DebugProbesImpl { val coroutinesInfoAsJson = ArrayList (size) for (info in coroutinesInfo) { val context = info.context - val name = context[CoroutineName.Key]?.name?.toStringWithQuotes() - val dispatcher = context[CoroutineDispatcher.Key]?.toStringWithQuotes() + val name = context[CoroutineName.Key]?.name?.toStringRepr() + val dispatcher = context[CoroutineDispatcher.Key]?.toStringRepr() coroutinesInfoAsJson.add( """ { @@ -219,7 +219,7 @@ internal object DebugProbesImpl { { "declaringClass": "${element.className}", "methodName": "${element.methodName}", - "fileName": ${element.fileName?.toStringWithQuotes()}, + "fileName": ${element.fileName?.toStringRepr()}, "lineNumber": ${element.lineNumber} } """.trimIndent() @@ -229,7 +229,7 @@ internal object DebugProbesImpl { return "[${stackTraceElementsInfoAsJson.joinToString()}]" } - private fun Any.toStringWithQuotes() = "\"$this\"" + private fun Any.toStringRepr() = toString().repr() /* * Internal (JVM-public) method used by IDEA debugger as of 1.4-M3. @@ -590,3 +590,19 @@ internal object DebugProbesImpl { private val StackTraceElement.isInternalMethod: Boolean get() = className.startsWith("kotlinx.coroutines") } + +private fun String.repr(): String = buildString { + append('"') + for (c in this@repr) { + when (c) { + '"' -> append("\\\"") + '\\' -> append("\\\\") + '\b' -> append("\\b") + '\n' -> append("\\n") + '\r' -> append("\\r") + '\t' -> append("\\t") + else -> append(c) + } + } + append('"') +} diff --git a/kotlinx-coroutines-debug/README.md b/kotlinx-coroutines-debug/README.md index 117c663afc..a5dcc76253 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.7.0.jar`. +You can run your application with an additional argument: `-javaagent:kotlinx-coroutines-debug-1.7.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. diff --git a/kotlinx-coroutines-debug/build.gradle b/kotlinx-coroutines-debug/build.gradle index ded13b7b5a..340c1d21dc 100644 --- a/kotlinx-coroutines-debug/build.gradle +++ b/kotlinx-coroutines-debug/build.gradle @@ -4,6 +4,9 @@ apply plugin: "com.github.johnrengelman.shadow" +// apply plugin to use autocomplete for Kover DSL +apply plugin: 'org.jetbrains.kotlinx.kover' + configurations { shadowDeps // shaded dependencies, not included into the resulting .pom file compileOnly.extendsFrom(shadowDeps) @@ -53,14 +56,11 @@ configurations { } } -def commonKoverExcludes = - // Never used, safety mechanism - ["kotlinx.coroutines.debug.internal.NoOpProbesKt"] - -tasks.koverHtmlReport { - excludes = commonKoverExcludes -} - -tasks.koverVerify { - excludes = commonKoverExcludes +koverReport { + filters { + excludes { + // Never used, safety mechanism + classes("kotlinx.coroutines.debug.internal.NoOpProbesKt") + } + } } diff --git a/kotlinx-coroutines-debug/test/DumpCoroutineInfoAsJsonAndReferencesTest.kt b/kotlinx-coroutines-debug/test/DumpCoroutineInfoAsJsonAndReferencesTest.kt index 4808470eb6..7d2521960f 100644 --- a/kotlinx-coroutines-debug/test/DumpCoroutineInfoAsJsonAndReferencesTest.kt +++ b/kotlinx-coroutines-debug/test/DumpCoroutineInfoAsJsonAndReferencesTest.kt @@ -29,6 +29,10 @@ class DumpCoroutineInfoAsJsonAndReferencesTest : DebugTestBase() { fun testDumpOfNamedCoroutine() = runTestWithNamedDeferred("Name") + @Test + fun testDumpOfNamedCoroutineWithSpecialCharacters() = + runTestWithNamedDeferred("Name with\n \"special\" characters\\/\t\b") + @Test fun testDumpWithNoCoroutines() { val dumpResult = DebugProbesImpl.dumpCoroutinesInfoAsJsonAndReferences() diff --git a/kotlinx-coroutines-test/README.md b/kotlinx-coroutines-test/README.md index fae47fa777..c3f36cf2dc 100644 --- a/kotlinx-coroutines-test/README.md +++ b/kotlinx-coroutines-test/README.md @@ -26,7 +26,7 @@ Provided [TestDispatcher] implementations: Add `kotlinx-coroutines-test` to your project test dependencies: ``` dependencies { - testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.0' + testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1' } ``` diff --git a/kotlinx-coroutines-test/api/kotlinx-coroutines-test.api b/kotlinx-coroutines-test/api/kotlinx-coroutines-test.api index a41502b2e1..64639f24a1 100644 --- a/kotlinx-coroutines-test/api/kotlinx-coroutines-test.api +++ b/kotlinx-coroutines-test/api/kotlinx-coroutines-test.api @@ -22,7 +22,7 @@ public final class kotlinx/coroutines/test/TestBuildersKt { public static final fun runTest (Lkotlinx/coroutines/test/TestScope;JLkotlin/jvm/functions/Function2;)V public static synthetic fun runTest$default (Lkotlin/coroutines/CoroutineContext;JLkotlin/jvm/functions/Function2;ILjava/lang/Object;)V public static synthetic fun runTest$default (Lkotlinx/coroutines/test/TestCoroutineScope;JLkotlin/jvm/functions/Function2;ILjava/lang/Object;)V - public static final synthetic fun runTest$default (Lkotlinx/coroutines/test/TestScope;Ljava/lang/Long;Lkotlin/jvm/functions/Function2;Ljava/lang/Integer;Ljava/lang/Object;)V + public static final synthetic fun runTest$default (Lkotlinx/coroutines/test/TestScope;JLkotlin/jvm/functions/Function2;ILjava/lang/Object;)V public static final fun runTest-8Mi8wO0 (Lkotlin/coroutines/CoroutineContext;JLkotlin/jvm/functions/Function2;)V public static final fun runTest-8Mi8wO0 (Lkotlinx/coroutines/test/TestScope;JLkotlin/jvm/functions/Function2;)V public static synthetic fun runTest-8Mi8wO0$default (Lkotlin/coroutines/CoroutineContext;JLkotlin/jvm/functions/Function2;ILjava/lang/Object;)V diff --git a/kotlinx-coroutines-test/common/src/TestBuilders.kt b/kotlinx-coroutines-test/common/src/TestBuilders.kt index 8ae075a706..f95dabc3d7 100644 --- a/kotlinx-coroutines-test/common/src/TestBuilders.kt +++ b/kotlinx-coroutines-test/common/src/TestBuilders.kt @@ -578,8 +578,8 @@ internal expect fun dumpCoroutines() @JvmName("runTest\$default") @Suppress("DEPRECATION", "UNUSED_PARAMETER") public fun TestScope.runTestLegacy( - dispatchTimeoutMs: Long?, + dispatchTimeoutMs: Long, testBody: suspend TestScope.() -> Unit, - unused1: Int?, + marker: Int, unused2: Any?, -): TestResult = runTest(dispatchTimeoutMs ?: 60_000, testBody) +): TestResult = runTest(dispatchTimeoutMs = if (marker and 1 != 0) dispatchTimeoutMs else 60_000L, testBody) diff --git a/reactive/kotlinx-coroutines-reactive/build.gradle.kts b/reactive/kotlinx-coroutines-reactive/build.gradle.kts index 3f2ba6b829..fbcde96527 100644 --- a/reactive/kotlinx-coroutines-reactive/build.gradle.kts +++ b/reactive/kotlinx-coroutines-reactive/build.gradle.kts @@ -1,7 +1,14 @@ +import kotlinx.kover.gradle.plugin.dsl.* + /* * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ +plugins { + // apply plugin to use autocomplete for Kover DSL + id("org.jetbrains.kotlinx.kover") +} + val reactiveStreamsVersion = property("reactive_streams_version") dependencies { @@ -35,16 +42,14 @@ externalDocumentationLink( url = "https://www.reactive-streams.org/reactive-streams-$reactiveStreamsVersion-javadoc/" ) -val commonKoverExcludes = listOf( - "kotlinx.coroutines.reactive.FlowKt", // Deprecated - "kotlinx.coroutines.reactive.FlowKt__MigrationKt", // Deprecated - "kotlinx.coroutines.reactive.ConvertKt" // Deprecated -) - -kover { +koverReport { filters { - classes { - excludes += commonKoverExcludes + excludes { + classes( + "kotlinx.coroutines.reactive.FlowKt", // Deprecated + "kotlinx.coroutines.reactive.FlowKt__MigrationKt", // Deprecated + "kotlinx.coroutines.reactive.ConvertKt" // Deprecated + ) } } } diff --git a/reactive/kotlinx-coroutines-reactor/build.gradle.kts b/reactive/kotlinx-coroutines-reactor/build.gradle.kts index a90b3cbd3c..7d3441ca00 100644 --- a/reactive/kotlinx-coroutines-reactor/build.gradle.kts +++ b/reactive/kotlinx-coroutines-reactor/build.gradle.kts @@ -2,6 +2,11 @@ * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ +plugins { + // apply plugin to use autocomplete for Kover DSL + id("org.jetbrains.kotlinx.kover") +} + val reactorVersion = version("reactor") dependencies { @@ -28,15 +33,14 @@ externalDocumentationLink( url = "https://projectreactor.io/docs/core/$reactorVersion/api/" ) -val commonKoverExcludes = listOf( - "kotlinx.coroutines.reactor.FlowKt", // Deprecated - "kotlinx.coroutines.reactor.ConvertKt\$asFlux$1" // Deprecated -) -kover { +koverReport { filters { - classes { - excludes += commonKoverExcludes + excludes { + classes( + "kotlinx.coroutines.reactor.FlowKt", // Deprecated + "kotlinx.coroutines.reactor.ConvertKt\$asFlux$1" // Deprecated + ) } } } diff --git a/ui/coroutines-guide-ui.md b/ui/coroutines-guide-ui.md index f45c382a2f..b8a7de33b1 100644 --- a/ui/coroutines-guide-ui.md +++ b/ui/coroutines-guide-ui.md @@ -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.7.0" +implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1" ``` You can clone [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) project from GitHub onto your diff --git a/ui/kotlinx-coroutines-android/build.gradle.kts b/ui/kotlinx-coroutines-android/build.gradle.kts index b5c9c0cf5d..70bc61582b 100644 --- a/ui/kotlinx-coroutines-android/build.gradle.kts +++ b/ui/kotlinx-coroutines-android/build.gradle.kts @@ -112,9 +112,3 @@ open class RunR8 : JavaExec() { super.exec() } } - -tasks.withType { - extensions.configure { - excludes.addAll(listOf("com.android.*", "android.*")) // Exclude robolectric-generated classes - } -}