diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/multitasking_0/threads/_CommonThreadLocalMethods.kt b/src/commonMain/kotlin/ru/landgrafhomyak/multitasking_0/threads/_CommonThreadLocalMethods.kt new file mode 100644 index 0000000..43fd09b --- /dev/null +++ b/src/commonMain/kotlin/ru/landgrafhomyak/multitasking_0/threads/_CommonThreadLocalMethods.kt @@ -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() + } +} \ No newline at end of file diff --git a/src/jvmMain/kotlin/ru/landgrafhomyak/multitasking_0/threads/Thread.kt b/src/jvmMain/kotlin/ru/landgrafhomyak/multitasking_0/threads/Thread.kt index f3a26f1..5a2f73e 100644 --- a/src/jvmMain/kotlin/ru/landgrafhomyak/multitasking_0/threads/Thread.kt +++ b/src/jvmMain/kotlin/ru/landgrafhomyak/multitasking_0/threads/Thread.kt @@ -3,17 +3,15 @@ package ru.landgrafhomyak.multitasking_0.threads import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.locks.LockSupport 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.threads.sync.ResumeThreadCallback @Suppress("AMBIGUOUS_EXPECTS", "ACTUAL_WITHOUT_EXPECT") public actual class Thread( @JvmField - internal val _nativeThread: jThread + internal val _nativeThread: jThread, ) { - private val _threadLocalMethods = this.ThreadLocalMethodsImpl() + private val _threadLocalMethods = ThreadLocalMethodsImpl(this) actual override fun toString(): String = "" @@ -41,90 +39,14 @@ public actual class Thread( } - private inner class ThreadLocalMethodsImpl : ThreadLocalMethods { - private fun _assertThread() { - if (Thread._tl_currentThread.get() != this@Thread) + private class ThreadLocalMethodsImpl(thread: Thread) : _CommonThreadLocalMethods(thread), ThreadLocalMethods { + override fun _assertCurrentThread() { + if (Thread._tl_currentThread.get() !== this.thread) 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() { - this._assertThread() + this._assertCurrentThread() jThread.yield() } @@ -140,9 +62,9 @@ public actual class Thread( this.sync.set(false) 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 -> { - LockSupport.unpark(this@Thread._nativeThread) + LockSupport.unpark(this@ThreadLocalMethodsImpl.thread._nativeThread) } else -> { @@ -155,7 +77,7 @@ public actual class Thread( } override fun suspendThread(store: (ResumeThreadCallback) -> Unit) { - this._assertThread() + this._assertCurrentThread() val resumer = this.ResumeThreadCallbackImpl() store(resumer) run { @@ -180,7 +102,7 @@ public actual class Thread( } override fun suspendThread(timeoutMillis: UInt, timeoutHandler: ResumeThreadCallback.TimeoutHandler, store: (ResumeThreadCallback) -> Unit) { - this._assertThread() + this._assertCurrentThread() val resumer = this.ResumeThreadCallbackImpl() store(resumer) run {