|
1 | 1 | package python.multiplatform.reflection |
2 | 2 |
|
3 | | -import kotlinx.cinterop.ExperimentalForeignApi |
4 | | -import kotlinx.cinterop.alloc |
5 | | -import kotlinx.cinterop.nativeHeap |
6 | | -import kotlinx.cinterop.ptr |
7 | | -import platform.posix.pthread_mutex_init |
8 | | -import platform.posix.pthread_mutex_lock |
9 | | -import platform.posix.pthread_mutex_t |
10 | | -import platform.posix.pthread_mutex_unlock |
| 3 | +import kotlin.concurrent.atomics.AtomicInt |
| 4 | +import kotlin.concurrent.atomics.ExperimentalAtomicApi |
11 | 5 |
|
12 | 6 | /** |
13 | | - * A default (non-recursive) POSIX mutex, the one primitive iOS and androidNative both provide. |
| 7 | + * A non-recursive spin lock on one atomic word, for iOS and androidNative alike (#329). |
14 | 8 | * |
15 | | - * The `pthread_mutex_t` lives in [nativeHeap] and is never freed: the only user is the |
16 | | - * [HandleTable] singleton, which lives for the life of the process, so there is nothing to |
17 | | - * release it for. |
| 9 | + * Not a `pthread_mutex_t`: `pthread_mutex_init` is not part of the POSIX surface Kotlin/Native |
| 10 | + * commonizes across Apple and Linux, so `nativeMain`'s shared metadata compile (the one publishing |
| 11 | + * runs) could not resolve it even though every per-target compile did. A spin lock needs only the |
| 12 | + * common atomics. That is enough here because [PlatformMutex]'s contract keeps every critical section |
| 13 | + * to a few array and counter operations, never a call into Python, user code or a cleaner, so a |
| 14 | + * waiter spins for a bounded, short time and a free-threaded stop-the-world pause cannot wait on it. |
18 | 15 | */ |
19 | | -@OptIn(ExperimentalForeignApi::class) |
| 16 | +@OptIn(ExperimentalAtomicApi::class) |
20 | 17 | internal actual class PlatformMutex actual constructor() { |
21 | | - private val mutex = nativeHeap.alloc<pthread_mutex_t>() |
22 | | - |
23 | | - init { |
24 | | - pthread_mutex_init(mutex.ptr, null) |
25 | | - } |
| 18 | + private val held = AtomicInt(0) |
26 | 19 |
|
27 | 20 | actual fun lock() { |
28 | | - pthread_mutex_lock(mutex.ptr) |
| 21 | + while (!held.compareAndSet(0, 1)) { |
| 22 | + // Spin: the holder is inside a section of a few array operations. |
| 23 | + } |
29 | 24 | } |
30 | 25 |
|
31 | 26 | actual fun unlock() { |
32 | | - pthread_mutex_unlock(mutex.ptr) |
| 27 | + held.store(0) |
33 | 28 | } |
34 | 29 | } |
0 commit comments