From 5d17c5f7cf9a39f2a0d7d97abdd23ee04119f454 Mon Sep 17 00:00:00 2001 From: Andrew Golovashevich Date: Mon, 17 Mar 2025 16:08:06 +0300 Subject: [PATCH] Mutex implementation for linux --- .gitignore | 9 ++++ build.gradle.kts | 21 ++++++++ .../c-interop-utilities/build.gradle.kts | 21 ++++++++ .../c_interop_utilities/CUtilities.kt | 16 ++++++ .../c_interop_utilities/LinuxUtilities.kt | 45 +++++++++++++++++ .../low-level/multithreading/build.gradle.kts | 22 ++++++++ .../low_level/multithreading/TMutex.kt | 8 +++ .../low_level/multithreading/TMutex.kt | 50 +++++++++++++++++++ settings.gradle.kts | 3 ++ 9 files changed, 195 insertions(+) create mode 100644 .gitignore create mode 100644 build.gradle.kts create mode 100644 modules/low-level/c-interop-utilities/build.gradle.kts create mode 100644 modules/low-level/c-interop-utilities/src/commonMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/c_interop_utilities/CUtilities.kt create mode 100644 modules/low-level/c-interop-utilities/src/linuxMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/c_interop_utilities/LinuxUtilities.kt create mode 100644 modules/low-level/multithreading/build.gradle.kts create mode 100644 modules/low-level/multithreading/src/commonMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/multithreading/TMutex.kt create mode 100644 modules/low-level/multithreading/src/linuxMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/multithreading/TMutex.kt create mode 100644 settings.gradle.kts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f2e4e0d --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +/.idea/ +gradle/ +.gradle/ +build/ +*.class +*.jar +/out/ +/gradlew* +.kotlin/ \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..f8d017c --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + kotlin("multiplatform") version "2.1.0" +} + +repositories { + mavenCentral() +} + + +kotlin { + jvm() + mingwX64() + sourceSets { + commonMain { + dependencies { + implementation("io.ktor:ktor-client-core:3.1.1") + implementation("io.ktor:ktor-network:3.1.1") + } + } + } +} \ No newline at end of file diff --git a/modules/low-level/c-interop-utilities/build.gradle.kts b/modules/low-level/c-interop-utilities/build.gradle.kts new file mode 100644 index 0000000..99edca3 --- /dev/null +++ b/modules/low-level/c-interop-utilities/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + kotlin("multiplatform") version "2.1.0" +} + +repositories { + mavenCentral() +} + + +kotlin { + mingwX64() + linuxX64() + macosX64() + macosArm64() + sourceSets { + commonMain { + dependencies { + } + } + } +} \ No newline at end of file diff --git a/modules/low-level/c-interop-utilities/src/commonMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/c_interop_utilities/CUtilities.kt b/modules/low-level/c-interop-utilities/src/commonMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/c_interop_utilities/CUtilities.kt new file mode 100644 index 0000000..fab14d2 --- /dev/null +++ b/modules/low-level/c-interop-utilities/src/commonMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/c_interop_utilities/CUtilities.kt @@ -0,0 +1,16 @@ +package ru.landgrafhomyak.bgtu.networks0.low_level.c_interop_utilities + + +import kotlinx.cinterop.CPointer +import kotlinx.cinterop.CVariable +import kotlinx.cinterop.ExperimentalForeignApi +import platform.posix.malloc +import kotlinx.cinterop.sizeOf as sizeOf_signed + +@OptIn(ExperimentalForeignApi::class) +object CUtilities { + inline fun sizeOf(): ULong = sizeOf_signed().toULong() + + @Suppress("UNCHECKED_CAST") + inline fun newOrOom() = (malloc(sizeOf()) ?: throw OutOfMemoryError()) as CPointer +} \ No newline at end of file diff --git a/modules/low-level/c-interop-utilities/src/linuxMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/c_interop_utilities/LinuxUtilities.kt b/modules/low-level/c-interop-utilities/src/linuxMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/c_interop_utilities/LinuxUtilities.kt new file mode 100644 index 0000000..83c2eab --- /dev/null +++ b/modules/low-level/c-interop-utilities/src/linuxMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/c_interop_utilities/LinuxUtilities.kt @@ -0,0 +1,45 @@ +package ru.landgrafhomyak.bgtu.networks0.low_level.c_interop_utilities + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.toKStringFromUtf8 +import platform.posix.errno +import platform.posix.strerror + + +object LinuxUtilities { + @OptIn(ExperimentalForeignApi::class, ExperimentalContracts::class) + inline fun throwErrno( + createError: (errnoDescription: String) -> Throwable, + ): Nothing { + contract { + callsInPlace(createError, InvocationKind.AT_MOST_ONCE) + } + val origErrno = errno + throwErrno(origErrno, createError) + } + + @OptIn(ExperimentalForeignApi::class, ExperimentalContracts::class) + inline fun throwErrno( + origErrno: Int, + createError: (errnoDescription: String) -> Throwable, + ): Nothing { + contract { + callsInPlace(createError, InvocationKind.AT_MOST_ONCE) + } + val raw = strerror(origErrno) + if (raw != null) { + throw createError(raw.toKStringFromUtf8()) + } else { + val strerrErrno = errno + try { + throw createError("Unknown error (errno=${origErrno})") + } catch (t: Throwable) { + t.addSuppressed(RuntimeException("Failed to get errno description (failed with errno=${strerrErrno})")) + throw t + } + } + } +} \ No newline at end of file diff --git a/modules/low-level/multithreading/build.gradle.kts b/modules/low-level/multithreading/build.gradle.kts new file mode 100644 index 0000000..160bc7a --- /dev/null +++ b/modules/low-level/multithreading/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + kotlin("multiplatform") version "2.1.0" +} + +repositories { + mavenCentral() +} + + +kotlin { + mingwX64() + linuxX64() + macosX64() + macosArm64() + sourceSets { + nativeMain { + dependencies { + implementation(project(":modules:low-level:c-interop-utilities")) + } + } + } +} \ No newline at end of file diff --git a/modules/low-level/multithreading/src/commonMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/multithreading/TMutex.kt b/modules/low-level/multithreading/src/commonMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/multithreading/TMutex.kt new file mode 100644 index 0000000..d1a06b1 --- /dev/null +++ b/modules/low-level/multithreading/src/commonMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/multithreading/TMutex.kt @@ -0,0 +1,8 @@ +package ru.landgrafhomyak.bgtu.networks0.low_level.multithreading + +expect class TMutex : AutoCloseable { + constructor() + + fun lock() + fun unlock() +} \ No newline at end of file diff --git a/modules/low-level/multithreading/src/linuxMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/multithreading/TMutex.kt b/modules/low-level/multithreading/src/linuxMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/multithreading/TMutex.kt new file mode 100644 index 0000000..32954c0 --- /dev/null +++ b/modules/low-level/multithreading/src/linuxMain/kotlin/ru/landgrafhomyak/bgtu/networks0/low_level/multithreading/TMutex.kt @@ -0,0 +1,50 @@ +package ru.landgrafhomyak.bgtu.networks0.low_level.multithreading + +import kotlinx.cinterop.CPointer +import kotlinx.cinterop.ExperimentalForeignApi +import platform.posix.free +import platform.posix.pthread_mutex_destroy +import platform.posix.pthread_mutex_init +import platform.posix.pthread_mutex_lock +import platform.posix.pthread_mutex_t +import platform.posix.pthread_mutex_unlock +import ru.landgrafhomyak.bgtu.networks0.low_level.c_interop_utilities.CUtilities +import ru.landgrafhomyak.bgtu.networks0.low_level.c_interop_utilities.LinuxUtilities + +@Suppress("JoinDeclarationAndAssignment", "CanBeVal", "ConvertSecondaryConstructorToPrimary") +@OptIn(ExperimentalForeignApi::class) +actual class TMutex : AutoCloseable { + private var isClosed: Boolean + private val descriptor: CPointer + + actual constructor() { + this.descriptor = CUtilities.newOrOom() + var err = pthread_mutex_init(this.descriptor, null) + if (err != 0) + LinuxUtilities.throwErrno(err) { d -> RuntimeException("Failed to create pthreads mutex: $d") } + this.isClosed = false + } + + actual fun lock() { + if (this.isClosed) throw IllegalStateException("Mutex was destroyed") + var err = pthread_mutex_lock(this.descriptor) + if (err != 0) + LinuxUtilities.throwErrno(err) { d -> RuntimeException("Failed to lock pthreads mutex: $d") } + } + + actual fun unlock() { + if (this.isClosed) throw IllegalStateException("Mutex was destroyed") + var err = pthread_mutex_unlock(this.descriptor) + if (err != 0) + LinuxUtilities.throwErrno(err) { d -> RuntimeException("Failed to unlock pthreads mutex: $d") } + } + + override fun close() { + if (this.isClosed) return + this.isClosed = true + var err = pthread_mutex_destroy(this.descriptor) + if (err != 0) + LinuxUtilities.throwErrno(err) { d -> RuntimeException("Failed to destroy pthreads mutex: $d") } + free(this.descriptor) + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..c0352d4 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,3 @@ +include(":modules:low-level:c-interop-utilities") +include(":modules:low-level:multithreading") +include(":modules:low-level:sockets") \ No newline at end of file