Skip to content

Commit 192acf4

Browse files
committed
Restore an Android compatibility trick (removed in #4196)
1 parent cca8c9a commit 192acf4

File tree

2 files changed

+26
-5
lines changed

2 files changed

+26
-5
lines changed

kotlinx-coroutines-core/jvm/src/Executors.kt

+6-5
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,13 @@ private class DispatcherExecutor(@JvmField val dispatcher: CoroutineDispatcher)
117117

118118
internal class ExecutorCoroutineDispatcherImpl(override val executor: Executor) : ExecutorCoroutineDispatcher(), Delay {
119119

120+
/*
121+
* Attempts to reflectively (to be Java 6 compatible) invoke
122+
* ScheduledThreadPoolExecutor.setRemoveOnCancelPolicy in order to cleanup
123+
* internal scheduler queue on cancellation.
124+
*/
120125
init {
121-
/* Attempt to invoke ScheduledThreadPoolExecutor.setRemoveOnCancelPolicy in order to clean up
122-
* the internal scheduler queue on cancellation. */
123-
if (executor is ScheduledThreadPoolExecutor) {
124-
executor.removeOnCancelPolicy = true
125-
}
126+
removeFutureOnCancel(executor)
126127
}
127128

128129
override fun dispatch(context: CoroutineContext, block: Runnable) {

kotlinx-coroutines-core/jvm/src/internal/Concurrent.kt

+20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package kotlinx.coroutines.internal
22

3+
import java.lang.reflect.Method
34
import java.util.*
5+
import java.util.concurrent.Executor
6+
import java.util.concurrent.ScheduledThreadPoolExecutor
47
import kotlin.concurrent.withLock as withLockJvm
58

69
internal actual typealias ReentrantLock = java.util.concurrent.locks.ReentrantLock
@@ -18,3 +21,20 @@ internal actual annotation class BenignDataRace()
1821
@Suppress("NOTHING_TO_INLINE") // So that R8 can completely remove ConcurrentKt class
1922
internal actual inline fun <E> identitySet(expectedSize: Int): MutableSet<E> =
2023
Collections.newSetFromMap(IdentityHashMap(expectedSize))
24+
25+
private val REMOVE_FUTURE_ON_CANCEL: Method? = try {
26+
ScheduledThreadPoolExecutor::class.java.getMethod("setRemoveOnCancelPolicy", Boolean::class.java)
27+
} catch (_: Throwable) {
28+
null
29+
}
30+
31+
@Suppress("NAME_SHADOWING")
32+
internal fun removeFutureOnCancel(executor: Executor): Boolean {
33+
try {
34+
val executor = executor as? ScheduledThreadPoolExecutor ?: return false
35+
(REMOVE_FUTURE_ON_CANCEL ?: return false).invoke(executor, true)
36+
return true
37+
} catch (_: Throwable) {
38+
return false // failed to setRemoveOnCancelPolicy, assume it does not remove the future on cancel
39+
}
40+
}

0 commit comments

Comments
 (0)