Skip to content

Commit 46a598e

Browse files
committed
System property to control BlockingChecker extension point for runBlocking
1 parent 82a918a commit 46a598e

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public abstract interface class kotlinx/coroutines/experimental/BlockingChecker
2525
}
2626

2727
public final class kotlinx/coroutines/experimental/BuildersKt {
28+
public static final field BLOCKING_CHECKER_PROPERTY_NAME Ljava/lang/String;
29+
public static final field BLOCKING_CHECKER_VALUE_DISABLE Ljava/lang/String;
2830
public static final synthetic fun launch (Lkotlin/coroutines/experimental/CoroutineContext;Lkotlinx/coroutines/experimental/CoroutineStart;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/experimental/Job;
2931
public static final fun launch (Lkotlin/coroutines/experimental/CoroutineContext;Lkotlinx/coroutines/experimental/CoroutineStart;Lkotlinx/coroutines/experimental/Job;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/experimental/Job;
3032
public static final synthetic fun launch (Lkotlin/coroutines/experimental/CoroutineContext;Lkotlinx/coroutines/experimental/CoroutineStart;Lkotlinx/coroutines/experimental/Job;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/experimental/Job;

core/kotlinx-coroutines-core/src/Builders.kt

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
package kotlinx.coroutines.experimental
99

10+
import internal.*
1011
import java.util.*
1112
import java.util.concurrent.locks.*
1213
import kotlin.coroutines.experimental.*
@@ -31,7 +32,8 @@ import kotlin.coroutines.experimental.*
3132
* See [newCoroutineContext] for a description of debugging facilities that are available for newly created coroutine.
3233
*
3334
* @throws IllegalStateException if blocking is not allowed in current thread.
34-
* Blocking is checked by [BlockingChecker] registered in [ServiceLoader]
35+
* Blocking is checked by [BlockingChecker] that is registered via [ServiceLoader],
36+
* unless [BLOCKING_CHECKER_PROPERTY_NAME] system property is set to [BLOCKING_CHECKER_VALUE_DISABLE].
3537
* @param context context of the coroutine. The default value is an implementation of [EventLoop].
3638
* @param block the coroutine code.
3739
*/
@@ -50,6 +52,18 @@ public fun <T> runBlocking(context: CoroutineContext = EmptyCoroutineContext, bl
5052
return coroutine.joinBlocking()
5153
}
5254

55+
/**
56+
* Name of the property to control whether [runBlocking] builder
57+
* is restricted via [BlockingChecker] extension points.
58+
*/
59+
public const val BLOCKING_CHECKER_PROPERTY_NAME = "kotlinx.coroutines.blocking.checker"
60+
61+
/**
62+
* Value of the [BLOCKING_CHECKER_PROPERTY_NAME] to disable installed
63+
* [BlockingChecker] and thus allow [runBlocking] in any thread.
64+
*/
65+
public const val BLOCKING_CHECKER_VALUE_DISABLE = "disable"
66+
5367
/**
5468
* Extension point which determines whether invoking [runBlocking] in the current thread is allowed.
5569
* [runBlocking] discovers all checkers via [ServiceLoader] and invokes [checkRunBlocking] on
@@ -63,6 +77,9 @@ public fun <T> runBlocking(context: CoroutineContext = EmptyCoroutineContext, bl
6377
* check(!UiFramework.isInUiThread()) { "runBlocking is not allowed in UI thread" }
6478
* }
6579
* ```
80+
*
81+
* Installed checkers are ignored if "`kotlinx.coroutines.blocking.checker`" ([BLOCKING_CHECKER_PROPERTY_NAME])
82+
* system property is set to the value "`disable`" ([BLOCKING_CHECKER_VALUE_DISABLE]).
6683
*/
6784
public interface BlockingChecker {
6885
/**
@@ -71,11 +88,24 @@ public interface BlockingChecker {
7188
fun checkRunBlocking()
7289
}
7390

91+
private class BlockingCheckerList(private val checkers: Array<BlockingChecker>) : BlockingChecker {
92+
override fun checkRunBlocking() = checkers.forEach { it.checkRunBlocking() }
93+
}
94+
7495
// Nullable to enable DCE when no filters are present in classpath
7596
private val blockingChecker: BlockingChecker? = run {
76-
val filters = ServiceLoader.load(BlockingChecker::class.java).toList().toTypedArray()
77-
if (filters.isEmpty()) null else object : BlockingChecker {
78-
override fun checkRunBlocking() = filters.forEach { it.checkRunBlocking() }
97+
val value = systemProp(BLOCKING_CHECKER_PROPERTY_NAME)
98+
when (value) {
99+
BLOCKING_CHECKER_VALUE_DISABLE -> null
100+
null -> {
101+
val checkers = ServiceLoader.load(BlockingChecker::class.java).toList()
102+
when (checkers.size) {
103+
0 -> null
104+
1 -> checkers[0]
105+
else -> BlockingCheckerList(checkers.toTypedArray())
106+
}
107+
}
108+
else -> error("System property '$BLOCKING_CHECKER_PROPERTY_NAME' has unrecognized value '$value'")
79109
}
80110
}
81111

0 commit comments

Comments
 (0)