Thread implementation on java

This commit is contained in:
Andrew Golovashevich 2025-09-08 00:30:00 +03:00
parent 9d847df01c
commit cfcf761745
9 changed files with 220 additions and 21 deletions

View File

@ -1,6 +1,4 @@
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.configureAllCompilationsOnAllTargets
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.configureAllCompilersOptionsOnAllTargets
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.defineAllMultiplatformTargets
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.defineXomrkGiteaMavenRepo
buildscript {
@ -15,7 +13,7 @@ buildscript {
}
plugins {
kotlin("multiplatform") version "2.2.10"
kotlin("multiplatform") version "2.2.20-Beta1"
`maven-publish`
}
@ -42,7 +40,7 @@ kotlin {
configureAllCompilersOptionsOnAllTargets {
freeCompilerArgs.addAll("-Xexpect-actual-classes")
freeCompilerArgs.addAll("-Xexpect-actual-classes", "-Xrender-internal-diagnostic-names", "-XXLanguage:+ExpectRefinement")
}
jvm().compilations.configureEach {

View File

@ -1,11 +1,13 @@
package ru.landgrafhomyak.multitasking_0
import ru.landgrafhomyak.multitasking_0.threads.Thread
/**
* Concurrency primitive with call stack.
*/
public interface Fiber {
/**
* Returns [thread][Thread] to which fiber is bound if there are restrictions to threads where fiber can be [resumed][Fiber.resume].
* Returns [thread][ru.landgrafhomyak.multitasking_0.threads.Thread] to which fiber is bound if there are restrictions to threads where fiber can be [resumed][Fiber.resume].
*/
public val ownerThread: Thread?
@ -59,9 +61,13 @@ public interface Fiber {
*/
public fun resume()
public fun interrupt()
/**
* Returns uncaught exception that terminated this fiber.
* If current [state][Fiber.state] isn't [FINISHED_WITH_ERROR][ExecutionState.FINISHED_WITH_ERROR] will throw [IllegalStateException].
*/
public val uncaughtException: Throwable
public fun releaseResources()
}

View File

@ -1,5 +1,7 @@
package ru.landgrafhomyak.multitasking_0
import ru.landgrafhomyak.multitasking_0.threads.Thread
public interface SingleThreadEventLoop {
/**
* Returns thread on which this event loop runs.

View File

@ -1,4 +1,6 @@
package ru.landgrafhomyak.multitasking_0
package ru.landgrafhomyak.multitasking_0.threads
import ru.landgrafhomyak.multitasking_0.Fiber
public expect class Thread {
public val name: String
@ -7,6 +9,6 @@ public expect class Thread {
public var runningFiber: Fiber?
public companion object {
public fun getCurrentThread(): Thread
public fun currentThread(): Thread
}
}
}

View File

@ -1,13 +0,0 @@
package ru.landgrafhomyak.multitasking_0
public actual class Thread(
public actual val name: String,
) {
actual override fun toString(): String = TODO()
public actual var runningFiber: Fiber? = null
public actual companion object {
public actual fun getCurrentThread(): Thread = TODO()
}
}

View File

@ -0,0 +1,122 @@
package ru.landgrafhomyak.multitasking_0.threads
import java.util.concurrent.CountDownLatch
import java.lang.Thread as jThread
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
@Suppress("JoinDeclarationAndAssignment")
internal class DrivenPlatformThread : Thread {
override fun toString(): String = TODO()
override val _nativeThread: jThread
private val _sync: ReentrantLock
private var _uncaughtException: Throwable?
private var _isExplicitlyDestroyed: Boolean
private val _threadFinishedWaiter: CountDownLatch
internal constructor(name: String, isDaemon: Boolean, routine: ThreadRoutine) : super() {
this._sync = ReentrantLock()
this._uncaughtException = null
this._isExplicitlyDestroyed = false
this._threadFinishedWaiter = CountDownLatch(1)
this._nativeThread = jThread.ofPlatform().name(name).daemon(isDaemon).unstarted(this.Kernel(routine))
}
private inner class Kernel(private val _routine: ThreadRoutine) : Runnable {
override fun run() {
try {
this._routine.runThread(this@DrivenPlatformThread)
} catch (t: Throwable) {
this@DrivenPlatformThread._sync.withLock {
this@DrivenPlatformThread._uncaughtException = t
}
} finally {
this@DrivenPlatformThread._threadFinishedWaiter.countDown()
}
}
}
override val state: State
get() {
this._sync.withLock {
if (this._isExplicitlyDestroyed)
return State.DESTROYED
when (this._nativeThread.state) {
jThread.State.NEW -> return State.NEW
jThread.State.RUNNABLE -> return State.NOT_FINISHED
jThread.State.BLOCKED -> return State.NOT_FINISHED
jThread.State.WAITING -> return State.NOT_FINISHED
jThread.State.TIMED_WAITING -> return State.NOT_FINISHED
jThread.State.TERMINATED -> {
if (this._uncaughtException == null)
return State.FINISHED_SUCCESSFULLY
else
return State.FINISHED_WITH_ERROR
}
}
}
}
override val uncaughtException: Throwable
get() {
this._sync.withLock {
val e = this._uncaughtException
if (e != null)
return e
when (this._nativeThread.state) {
jThread.State.NEW, jThread.State.RUNNABLE, jThread.State.BLOCKED, jThread.State.WAITING, jThread.State.TIMED_WAITING ->
throw IllegalStateException("Thread not finished yet")
jThread.State.TERMINATED -> throw IllegalStateException("Thread finished without uncaught exceptions")
}
}
}
override fun start() {
this._sync.withLock {
if (this._isExplicitlyDestroyed)
throw IllegalStateException("Thread already was started, finished and destroyed")
// stdlib's errors aren't verbose
when (this._nativeThread.state) {
jThread.State.NEW -> {}
jThread.State.TERMINATED -> throw IllegalStateException("Thread already was started and finished")
jThread.State.RUNNABLE, jThread.State.BLOCKED, jThread.State.WAITING, jThread.State.TIMED_WAITING ->
throw IllegalStateException("Thread already was started")
}
this._nativeThread.start()
}
}
override fun join() {
this._sync.withLock {
if (this._isExplicitlyDestroyed)
throw IllegalStateException("Can't join on destroyed thread")
if (this._nativeThread.state == jThread.State.NEW)
throw IllegalStateException("Can't join on thread that isn't started")
}
// stdlib's join uses Object.wait which may block caller virtual thread, so let wait in way virtual threads support
this._threadFinishedWaiter.await()
this._nativeThread.join()
}
override fun releaseResources() {
this._sync.withLock {
if (this._isExplicitlyDestroyed)
throw IllegalStateException("Thread already destroyed")
when (this._nativeThread.state) {
jThread.State.NEW -> {}
jThread.State.TERMINATED -> {}
jThread.State.RUNNABLE, jThread.State.BLOCKED, jThread.State.WAITING, jThread.State.TIMED_WAITING ->
throw IllegalStateException("Thread already was started")
}
this._isExplicitlyDestroyed = true
}
}
}

View File

@ -0,0 +1,42 @@
package ru.landgrafhomyak.multitasking_0.threads
import java.lang.Thread as jThread
import ru.landgrafhomyak.multitasking_0.Fiber
@Suppress("AMBIGUOUS_EXPECTS", "ACTUAL_WITHOUT_EXPECT")
public actual sealed class Thread {
actual abstract override fun toString(): String
public actual var runningFiber: Fiber? = null
protected abstract val _nativeThread: jThread
public actual val name: String get() = this._nativeThread.name
public actual val isDaemon: Boolean get() = this._nativeThread.isDaemon
public actual abstract val state: State
public actual abstract val uncaughtException: Throwable
public actual abstract fun releaseResources()
public actual abstract fun start()
public actual abstract fun join()
public actual enum class State {
NEW,
NOT_FINISHED,
FINISHED_SUCCESSFULLY,
FINISHED_WITH_ERROR,
DESTROYED
}
public actual companion object {
@JvmStatic
public actual fun create(name: String, isDaemon: Boolean, routine: ThreadRoutine): Thread {
TODO()
}
@JvmStatic
public actual fun currentThread(): Thread {
TODO()
}
}
}

View File

@ -0,0 +1,35 @@
package ru.landgrafhomyak.multitasking_0.threads
import kotlin.experimental.ExpectRefinement
import ru.landgrafhomyak.multitasking_0.Fiber
// didn't work because AMBIGUOUS_EXPECTS
@OptIn(ExperimentalMultiplatform::class)
@ExpectRefinement
public expect class Thread {
public val name: String
override fun toString(): String
public var runningFiber: Fiber?
public fun start()
public fun join()
public val state: State
public val uncaughtException: Throwable
public fun releaseResources()
public val isDaemon: Boolean
public enum class State {
NEW,
NOT_FINISHED,
FINISHED_SUCCESSFULLY,
FINISHED_WITH_ERROR,
DESTROYED
}
public companion object {
public fun create(name: String, isDaemon: Boolean, routine: ThreadRoutine): Thread
public fun currentThread(): Thread
}
}

View File

@ -0,0 +1,5 @@
package ru.landgrafhomyak.multitasking_0.threads
public fun interface ThreadRoutine {
public fun runThread(thread: Thread)
}