Extracted independent ThreadLocalMethods implementation to common sources

This commit is contained in:
Andrew Golovashevich 2025-09-12 07:56:25 +03:00
parent 34debfcb7b
commit 67079c1565
2 changed files with 100 additions and 88 deletions

View File

@ -0,0 +1,90 @@
package ru.landgrafhomyak.multitasking_0.threads
import kotlin.concurrent.atomics.ExperimentalAtomicApi
import kotlin.jvm.JvmField
import ru.landgrafhomyak.multitasking_0.SingleThreadEventLoop
import ru.landgrafhomyak.multitasking_0.fibers.Fiber
internal abstract class _CommonThreadLocalMethods(
@JvmField
protected val thread: Thread,
) : ThreadLocalMethods {
protected abstract fun _assertCurrentThread()
override fun get(): Thread {
this._assertCurrentThread()
return this.thread
}
private inner class FibersStackNode(
@JvmField
val caller: FibersStackNode?,
@JvmField
val fiber: Fiber,
) : ExitFiberCallback {
private var _isUsed = false
override val callerFiber: Fiber?
get() {
if (this._isUsed) throw IllegalStateException("Fiber already exited and value in this property isn't actual")
return this.caller?.fiber
}
override fun exitFiber() {
this@_CommonThreadLocalMethods._assertCurrentThread()
if (this._isUsed)
throw IllegalStateException("Fiber already exited")
if (this@_CommonThreadLocalMethods._fibersStack !== this)
throw IllegalStateException("Fiber being exited isn't on top of fibers stack")
this._isUsed = true
this@_CommonThreadLocalMethods._fibersStack = this.caller
}
}
private var _fibersStack: FibersStackNode? = null
override val runningFiber: Fiber?
get() {
this._assertCurrentThread()
return this._fibersStack?.fiber
}
override fun enterFiber(fiberToEnter: Fiber): ExitFiberCallback {
this._assertCurrentThread()
val node = this.FibersStackNode(this._fibersStack, fiberToEnter)
this._fibersStack = node
return node
}
private var _runningEventLoop: SingleThreadEventLoop? = null
override val runningEventLoop: SingleThreadEventLoop?
get() {
this._assertCurrentThread()
return this._runningEventLoop
}
@OptIn(ExperimentalAtomicApi::class)
private inner class ClearEventLoopCallbackImpl: ClearEventLoopCallback {
private var _isUsed = false
override fun clearEventLoop() {
this@_CommonThreadLocalMethods._assertCurrentThread()
if (this._isUsed)
throw IllegalStateException("Event loop already cleared")
this._isUsed = true
this@_CommonThreadLocalMethods._runningEventLoop = null
}
}
override fun setEventLoop(eventLoop: SingleThreadEventLoop): ClearEventLoopCallback {
this._assertCurrentThread()
if (this._runningEventLoop != null)
throw IllegalStateException("There is already a running event loop here")
this._runningEventLoop = eventLoop
return this.ClearEventLoopCallbackImpl()
}
}

View File

@ -3,17 +3,15 @@ package ru.landgrafhomyak.multitasking_0.threads
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.locks.LockSupport import java.util.concurrent.locks.LockSupport
import java.lang.Thread as jThread import java.lang.Thread as jThread
import ru.landgrafhomyak.multitasking_0.fibers.Fiber
import ru.landgrafhomyak.multitasking_0.SingleThreadEventLoop
import ru.landgrafhomyak.multitasking_0.WrongCallerThreadException import ru.landgrafhomyak.multitasking_0.WrongCallerThreadException
import ru.landgrafhomyak.multitasking_0.threads.sync.ResumeThreadCallback import ru.landgrafhomyak.multitasking_0.threads.sync.ResumeThreadCallback
@Suppress("AMBIGUOUS_EXPECTS", "ACTUAL_WITHOUT_EXPECT") @Suppress("AMBIGUOUS_EXPECTS", "ACTUAL_WITHOUT_EXPECT")
public actual class Thread( public actual class Thread(
@JvmField @JvmField
internal val _nativeThread: jThread internal val _nativeThread: jThread,
) { ) {
private val _threadLocalMethods = this.ThreadLocalMethodsImpl() private val _threadLocalMethods = ThreadLocalMethodsImpl(this)
actual override fun toString(): String = "<platform native thread name='${this._nativeThread.name}'>" actual override fun toString(): String = "<platform native thread name='${this._nativeThread.name}'>"
@ -41,90 +39,14 @@ public actual class Thread(
} }
private inner class ThreadLocalMethodsImpl : ThreadLocalMethods { private class ThreadLocalMethodsImpl(thread: Thread) : _CommonThreadLocalMethods(thread), ThreadLocalMethods {
private fun _assertThread() { override fun _assertCurrentThread() {
if (Thread._tl_currentThread.get() != this@Thread) if (Thread._tl_currentThread.get() !== this.thread)
throw WrongCallerThreadException("Reference returned by 'Thread.current' must be used only in thread where it was produced") throw WrongCallerThreadException("Reference returned by 'Thread.current' must be used only in thread where it was produced")
} }
override fun get(): Thread {
this._assertThread()
return this@Thread
}
private inner class FibersStackNode(
@JvmField
val caller: FibersStackNode?,
@JvmField
val fiber: Fiber,
) : ExitFiberCallback {
private val _isClosed = AtomicBoolean(false)
override val callerFiber: Fiber?
get() {
if (this._isClosed.get()) throw IllegalStateException("Fiber already exited and value in this property isn't actual")
return this.caller?.fiber
}
override fun exitFiber() {
if (this._isClosed.compareAndExchange(false, true))
throw IllegalStateException("Fiber already exited")
if (this@ThreadLocalMethodsImpl._fibersStack !== this) {
this._isClosed.set(false)
throw IllegalStateException("Fiber being exited isn't on top of fibers stack")
}
this@ThreadLocalMethodsImpl._fibersStack = this.caller
}
}
private var _fibersStack: FibersStackNode? = null
override val runningFiber: Fiber?
get() {
this._assertThread()
return this._fibersStack?.fiber
}
override fun enterFiber(fiberToEnter: Fiber): ExitFiberCallback {
this._assertThread()
val node = this.FibersStackNode(this._fibersStack, fiberToEnter)
this._fibersStack = node
return node
}
private var _runningEventLoop: SingleThreadEventLoop? = null
override val runningEventLoop: SingleThreadEventLoop?
get() {
this._assertThread()
return this._runningEventLoop
}
private inner class ClearEventLoopCallbackImpl(
) : ClearEventLoopCallback {
private val _isClosed = AtomicBoolean(false)
override fun clearEventLoop() {
if (this._isClosed.compareAndExchange(false, true))
throw IllegalStateException("Event loop already cleared")
this@ThreadLocalMethodsImpl._runningEventLoop = null
}
}
override fun setEventLoop(eventLoop: SingleThreadEventLoop): ClearEventLoopCallback {
this._assertThread()
if (this._runningEventLoop != null)
throw IllegalStateException("There is already a running event loop here")
this._runningEventLoop = eventLoop
return this.ClearEventLoopCallbackImpl()
}
override fun yield() { override fun yield() {
this._assertThread() this._assertCurrentThread()
jThread.yield() jThread.yield()
} }
@ -140,9 +62,9 @@ public actual class Thread(
this.sync.set(false) this.sync.set(false)
throw IllegalStateException("Thread already resumed by this callback instance") throw IllegalStateException("Thread already resumed by this callback instance")
} }
when (this@Thread._nativeThread.state) { when (this@ThreadLocalMethodsImpl.thread._nativeThread.state) {
jThread.State.WAITING, jThread.State.TIMED_WAITING -> { jThread.State.WAITING, jThread.State.TIMED_WAITING -> {
LockSupport.unpark(this@Thread._nativeThread) LockSupport.unpark(this@ThreadLocalMethodsImpl.thread._nativeThread)
} }
else -> { else -> {
@ -155,7 +77,7 @@ public actual class Thread(
} }
override fun suspendThread(store: (ResumeThreadCallback) -> Unit) { override fun suspendThread(store: (ResumeThreadCallback) -> Unit) {
this._assertThread() this._assertCurrentThread()
val resumer = this.ResumeThreadCallbackImpl() val resumer = this.ResumeThreadCallbackImpl()
store(resumer) store(resumer)
run { run {
@ -180,7 +102,7 @@ public actual class Thread(
} }
override fun suspendThread(timeoutMillis: UInt, timeoutHandler: ResumeThreadCallback.TimeoutHandler, store: (ResumeThreadCallback) -> Unit) { override fun suspendThread(timeoutMillis: UInt, timeoutHandler: ResumeThreadCallback.TimeoutHandler, store: (ResumeThreadCallback) -> Unit) {
this._assertThread() this._assertCurrentThread()
val resumer = this.ResumeThreadCallbackImpl() val resumer = this.ResumeThreadCallbackImpl()
store(resumer) store(resumer)
run { run {