@@ -17,13 +17,13 @@ internal actual object DefaultExecutor : EventLoopImplBase(), Runnable {
17
17
incrementUseCount() // this event loop is never completed
18
18
}
19
19
20
- private const val DEFAULT_KEEP_ALIVE = 1000L // in milliseconds
20
+ private const val DEFAULT_KEEP_ALIVE_MS = 1000L // in milliseconds
21
21
22
22
private val KEEP_ALIVE_NANOS = TimeUnit .MILLISECONDS .toNanos(
23
23
try {
24
- java.lang.Long .getLong(" kotlinx.coroutines.DefaultExecutor.keepAlive" , DEFAULT_KEEP_ALIVE )
24
+ java.lang.Long .getLong(" kotlinx.coroutines.DefaultExecutor.keepAlive" , DEFAULT_KEEP_ALIVE_MS )
25
25
} catch (e: SecurityException ) {
26
- DEFAULT_KEEP_ALIVE
26
+ DEFAULT_KEEP_ALIVE_MS
27
27
})
28
28
29
29
@Suppress(" ObjectPropertyName" )
@@ -37,15 +37,39 @@ internal actual object DefaultExecutor : EventLoopImplBase(), Runnable {
37
37
private const val ACTIVE = 1
38
38
private const val SHUTDOWN_REQ = 2
39
39
private const val SHUTDOWN_ACK = 3
40
+ private const val SHUTDOWN = 4
40
41
41
42
@Volatile
42
43
private var debugStatus: Int = FRESH
43
44
45
+ val isShutDown: Boolean get() = debugStatus == SHUTDOWN
46
+
44
47
private val isShutdownRequested: Boolean get() {
45
48
val debugStatus = debugStatus
46
49
return debugStatus == SHUTDOWN_REQ || debugStatus == SHUTDOWN_ACK
47
50
}
48
51
52
+ actual override fun enqueue (task : Runnable ) {
53
+ if (isShutDown) shutdownError()
54
+ super .enqueue(task)
55
+ }
56
+
57
+ override fun reschedule (now : Long , delayedTask : DelayedTask ) {
58
+ // Reschedule on default executor can only be invoked after Dispatchers.shutdown
59
+ shutdownError()
60
+ }
61
+
62
+ private fun shutdownError () {
63
+ throw RejectedExecutionException (" DefaultExecutor was shut down. " +
64
+ " This error indicates that Dispatchers.shutdown() was invoked prior to completion of exiting coroutines, leaving coroutines in incomplete state. " +
65
+ " Please refer to Dispatchers.shutdown documentation for more details" )
66
+ }
67
+
68
+ override fun shutdown () {
69
+ debugStatus = SHUTDOWN
70
+ super .shutdown()
71
+ }
72
+
49
73
/* *
50
74
* All event loops are using DefaultExecutor#invokeOnTimeout to avoid livelock on
51
75
* ```
@@ -118,9 +142,8 @@ internal actual object DefaultExecutor : EventLoopImplBase(), Runnable {
118
142
return true
119
143
}
120
144
121
- // used for tests
122
- @Synchronized
123
- fun shutdown (timeout : Long ) {
145
+ @Synchronized // used _only_ for tests
146
+ fun shutdownForTests (timeout : Long ) {
124
147
val deadline = System .currentTimeMillis() + timeout
125
148
if (! isShutdownRequested) debugStatus = SHUTDOWN_REQ
126
149
// loop while there is anything to do immediately or deadline passes
0 commit comments