Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
package python.multiplatform.reflection

import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.alloc
import kotlinx.cinterop.nativeHeap
import kotlinx.cinterop.ptr
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 kotlin.concurrent.atomics.AtomicInt
import kotlin.concurrent.atomics.ExperimentalAtomicApi

/**
* A default (non-recursive) POSIX mutex, the one primitive iOS and androidNative both provide.
* A non-recursive spin lock on one atomic word, for iOS and androidNative alike (#329).
*
* The `pthread_mutex_t` lives in [nativeHeap] and is never freed: the only user is the
* [HandleTable] singleton, which lives for the life of the process, so there is nothing to
* release it for.
* Not a `pthread_mutex_t`: `pthread_mutex_init` is not part of the POSIX surface Kotlin/Native
* commonizes across Apple and Linux, so `nativeMain`'s shared metadata compile (the one publishing
* runs) could not resolve it even though every per-target compile did. A spin lock needs only the
* common atomics. That is enough here because [PlatformMutex]'s contract keeps every critical section
* to a few array and counter operations, never a call into Python, user code or a cleaner, so a
* waiter spins for a bounded, short time and a free-threaded stop-the-world pause cannot wait on it.
*/
@OptIn(ExperimentalForeignApi::class)
@OptIn(ExperimentalAtomicApi::class)
internal actual class PlatformMutex actual constructor() {
private val mutex = nativeHeap.alloc<pthread_mutex_t>()

init {
pthread_mutex_init(mutex.ptr, null)
}
private val held = AtomicInt(0)

actual fun lock() {
pthread_mutex_lock(mutex.ptr)
while (!held.compareAndSet(0, 1)) {
// Spin: the holder is inside a section of a few array operations.
}
}

actual fun unlock() {
pthread_mutex_unlock(mutex.ptr)
held.store(0)
}
}