diff --git a/kotlinx-coroutines-debug/src/CoroutinesBlockHoundIntegration.kt b/kotlinx-coroutines-debug/src/CoroutinesBlockHoundIntegration.kt index da3468047a..c3fc130ea7 100644 --- a/kotlinx-coroutines-debug/src/CoroutinesBlockHoundIntegration.kt +++ b/kotlinx-coroutines-debug/src/CoroutinesBlockHoundIntegration.kt @@ -10,8 +10,7 @@ import reactor.blockhound.integration.* public class CoroutinesBlockHoundIntegration : BlockHoundIntegration { override fun applyTo(builder: BlockHound.Builder): Unit = with(builder) { - allowBlockingCallsInside("kotlinx.coroutines.channels.AbstractSendChannel", "sendSuspend") - // these classes use a lock internally + // These classes use a lock internally, but should be safe to use. for (method in listOf( "pollInternal", "isEmpty", "isFull", "isClosedForReceive", "offerInternal", "offerSelectInternal", "enqueueSend", "pollInternal", "pollSelectInternal", "enqueueReceiveInternal", "onCancelIdempotent" )) @@ -29,8 +28,20 @@ public class CoroutinesBlockHoundIntegration : BlockHoundIntegration { { allowBlockingCallsInside("kotlinx.coroutines.channels.ConflatedChannel", method) } - // should be safe; used for sending tasks to a thread pool + allowBlockingCallsInside("kotlinx.coroutines.channels.AbstractSendChannel", "sendSuspend") + /* This method may block as part of its implementation, but is probably safe. We need to whitelist it so that + it is possible to enqueue coroutines in contexts that use thread pools from other coroutines in a way that's not + considered blocking. */ allowBlockingCallsInside("java.util.concurrent.ScheduledThreadPoolExecutor", "execute") + /* These files have fields that invoke service loaders. They are manually whitelisted; another approach could be + to whitelist the operations performed by service loaders, as they can generally be considered safe. This was not + done here because ServiceLoader has a large API surface, with some methods being hidden as implementation + details (in particular, the implementation of its iterator is completely opaque). Relying on particular names + being used in ServiceLoader's implementation would be brittle. */ + allowBlockingCallsInside("kotlinx.coroutines.reactive.ReactiveFlowKt", "") + allowBlockingCallsInside("kotlinx.coroutines.CoroutineExceptionHandlerImplKt", "") + /* The predicates that define that BlockHound should only report blocking calls from threads that are part of + the coroutine thread pool and currently execute a CPU-bound coroutine computation. */ addDynamicThreadPredicate { isSchedulerWorker(it) } nonBlockingThreadPredicate { p -> p.or { mayNotBlock(it) } } }