Minor optimizations of UndispatchedEventLoop
diff --git a/common/kotlinx-coroutines-core-common/src/Dispatched.kt b/common/kotlinx-coroutines-core-common/src/Dispatched.kt
index 6fc1870..34aacae 100644
--- a/common/kotlinx-coroutines-core-common/src/Dispatched.kt
+++ b/common/kotlinx-coroutines-core-common/src/Dispatched.kt
@@ -13,53 +13,53 @@
@NativeThreadLocal
internal object UndispatchedEventLoop {
- data class State(
+ data class EventLoop(
@JvmField var isActive: Boolean = false,
- @JvmField val threadLocalQueue: ArrayQueue<Runnable> = ArrayQueue()
+ @JvmField val queue: ArrayQueue<Runnable> = ArrayQueue()
)
@JvmField
- internal val state = CommonThreadLocal { State() }
+ internal val threadLocalEventLoop = CommonThreadLocal { EventLoop() }
inline fun execute(continuation: DispatchedContinuation<*>, contState: Any?, mode: Int, block: () -> Unit) {
- val state = state.get()
- if (state.isActive) {
+ val eventLoop = threadLocalEventLoop.get()
+ if (eventLoop.isActive) {
continuation._state = contState
continuation.resumeMode = mode
- state.threadLocalQueue.addLast(continuation)
+ eventLoop.queue.addLast(continuation)
return
}
- runLoop(state, block)
+ runEventLoop(eventLoop, block)
}
fun resumeUndispatched(task: DispatchedTask<*>) {
- val state = state.get()
- if (state.isActive) {
- state.threadLocalQueue.addLast(task)
+ val eventLoop = threadLocalEventLoop.get()
+ if (eventLoop.isActive) {
+ eventLoop.queue.addLast(task)
return
}
- runLoop(state, { task.resume(task.delegate, MODE_UNDISPATCHED) })
+ runEventLoop(eventLoop, { task.resume(task.delegate, MODE_UNDISPATCHED) })
}
- inline fun runLoop(state: State, block: () -> Unit) {
+ inline fun runEventLoop(eventLoop: EventLoop, block: () -> Unit) {
try {
- state.isActive = true
+ eventLoop.isActive = true
block()
- while (!state.threadLocalQueue.isEmpty) {
- val element = state.threadLocalQueue.removeFirst()
- element.run()
+ while (true) {
+ val nextEvent = eventLoop.queue.removeFirstOrNull() ?: return
+ nextEvent.run()
}
} catch (e: Throwable) {
/*
* This exception doesn't happen normally, only if user either submitted throwing runnable
* or if we have a bug in implementation. Anyway, reset state of the dispatcher to the initial.
*/
- state.threadLocalQueue.clear()
+ eventLoop.queue.clear()
throw DispatchException("Unexpected exception in undispatched event loop, clearing pending tasks", e)
} finally {
- state.isActive = false
+ eventLoop.isActive = false
}
}
}
diff --git a/common/kotlinx-coroutines-core-common/src/internal/ArrayQueue.kt b/common/kotlinx-coroutines-core-common/src/internal/ArrayQueue.kt
index be38183..a6bf8f6 100644
--- a/common/kotlinx-coroutines-core-common/src/internal/ArrayQueue.kt
+++ b/common/kotlinx-coroutines-core-common/src/internal/ArrayQueue.kt
@@ -5,8 +5,6 @@
package kotlinx.coroutines.internal
internal class ArrayQueue<T : Any> {
- public val isEmpty: Boolean get() = head == tail
-
private var elements = arrayOfNulls<Any>(16)
private var head = 0
private var tail = 0
@@ -18,12 +16,12 @@
}
@Suppress("UNCHECKED_CAST")
- public fun removeFirst(): T {
- require(head != tail) { "Queue is empty" }
+ public fun removeFirstOrNull(): T? {
+ if (head == tail) return null
val element = elements[head]
elements[head] = null
head = (head + 1) and elements.size - 1
- return element!! as T
+ return element as T
}
public fun clear() {