Thread local variable impl on WinApi

This commit is contained in:
Andrew Golovashevich 2025-09-12 04:23:52 +03:00
parent f8cb01799d
commit 650213fc4c
3 changed files with 81 additions and 5 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
/.idea/ .idea/
gradle/ gradle/
.gradle/ .gradle/
build/ build/

View File

@ -22,6 +22,7 @@ version = "0.1"
repositories { repositories {
mavenCentral() mavenCentral()
maven("https://maven.landgrafhomyak.ru/")
} }
kotlin { kotlin {
@ -68,7 +69,13 @@ kotlin {
compileOnly("org.jetbrains.kotlin:kotlin-annotations-jvm:${this@kotlin.coreLibrariesVersion}") compileOnly("org.jetbrains.kotlin:kotlin-annotations-jvm:${this@kotlin.coreLibrariesVersion}")
} }
} }
mingwX64().compilations["main"].defaultSourceSet {
dependencies {
implementation("ru.landgrafhomyak.utility:highlevel-try-finally:0.6")
implementation("ru.landgrafhomyak.utility:closeable-state-1:1.2")
implementation("ru.landgrafhomyak.utility:kotlin-native-interop-utilities-0:0.1")
}
}
val notJvmMain by creating { dependsOn(commonMain) } val notJvmMain by creating { dependsOn(commonMain) }
val notJvmTest by creating { dependsOn(commonTest) } val notJvmTest by creating { dependsOn(commonTest) }
@ -96,11 +103,13 @@ kotlin {
this@target.compilations.getByName("main").defaultSourceSet.dependsOn(multithreadPlatformMain) this@target.compilations.getByName("main").defaultSourceSet.dependsOn(multithreadPlatformMain)
this@target.compilations.getByName("test").defaultSourceSet.dependsOn(multithreadPlatformTest) this@target.compilations.getByName("test").defaultSourceSet.dependsOn(multithreadPlatformTest)
} }
}
} }
val windowsMain by creating { dependsOn(multithreadPlatformMain) }
val windowsTest by creating { dependsOn(multithreadPlatformTest) }
mingwX64().compilations["main"].defaultSourceSet.dependsOn(windowsMain)
mingwX64().compilations["test"].defaultSourceSet.dependsOn(windowsTest)
}
} }
publishing { publishing {

View File

@ -0,0 +1,67 @@
package ru.landgrafhomyak.multitasking_0.threads
import kotlin.concurrent.atomics.ExperimentalAtomicApi
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.StableRef
import platform.windows.DWORD
import platform.windows.ERROR_SUCCESS
import platform.windows.GetLastError
import platform.windows.LPVOID
import platform.windows.TLS_OUT_OF_INDEXES
import platform.windows.TlsAlloc
import platform.windows.TlsFree
import platform.windows.TlsGetValue
import platform.windows.TlsSetValue
import ru.landgrafhomyak.utility.closeable_state_1.CloseableState
import ru.landgrafhomyak.utility.closeable_state_1.ManualStateManipulation
import ru.landgrafhomyak.utility.closeable_state_1.OwnedUsagesCounter
import ru.landgrafhomyak.utility.closeable_state_1.withUse
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
import ru.landgrafhomyak.utility.kotlin_native_interop_stdlib_0.windows.WindowsApiException
import ru.landgrafhomyak.utility.kotlin_native_interop_stdlib_0.windows.zeroToWinApiErr
@Suppress("JoinDeclarationAndAssignment")
@OptIn(ExperimentalForeignApi::class, ExperimentalAtomicApi::class)
internal class ThreadLocalVariable {
private val _windows_tls_index: DWORD
private val _garbageCollectionDisabler: StableRef<ThreadLocalVariable>
private val _state: CloseableState.AllowsConcurrency
init {
this._state = OwnedUsagesCounter(this)
this._garbageCollectionDisabler = StableRef.create(this)
safeAutoClose2(
action = {
this._windows_tls_index = TlsAlloc()
if (this._windows_tls_index == TLS_OUT_OF_INDEXES)
WindowsApiException.throwFromLastWindowsErr()
},
onError = { this._garbageCollectionDisabler.dispose() }
)
}
fun dealloc() {
@OptIn(ManualStateManipulation::class)
this._state.close()
zeroToWinApiErr { TlsFree(this._windows_tls_index) }
this._garbageCollectionDisabler.dispose()
}
fun get(): LPVOID? {
this._state.withUse {
val value = TlsGetValue(this._windows_tls_index)
val errCode = GetLastError()
if (errCode != ERROR_SUCCESS.toUInt())
WindowsApiException.throwFromWindowsErrCode(errCode)
return value
}
}
fun set(value: LPVOID?) {
this._state.withUse {
zeroToWinApiErr { TlsSetValue(this._windows_tls_index, value) }
}
}
}