Skip to content

Commit ab34869

Browse files
authored
Merge pull request #330 from thisisthepy/feat/native-mutex-commonized
Fix: commonizable PlatformMutex on native (#329)
2 parents 471a1b4 + 4e622d3 commit ab34869

1 file changed

Lines changed: 15 additions & 20 deletions

File tree

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,29 @@
11
package python.multiplatform.reflection
22

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
115

126
/**
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).
148
*
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.
1815
*/
19-
@OptIn(ExperimentalForeignApi::class)
16+
@OptIn(ExperimentalAtomicApi::class)
2017
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)
2619

2720
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+
}
2924
}
3025

3126
actual fun unlock() {
32-
pthread_mutex_unlock(mutex.ptr)
27+
held.store(0)
3328
}
3429
}

0 commit comments

Comments
 (0)