From 61cd38e8ace66de64b2d3e53b2ebc327a979c4ef Mon Sep 17 00:00:00 2001 From: GasInfinity Date: Tue, 21 Apr 2026 08:54:54 +0200 Subject: [PATCH] feat(libzigc): add common implementations of `pthread_spin_*` * and remove their mingw, musl and wasi implementations --- lib/c.zig | 1 + lib/c/pthread.zig | 57 +++++++++++++ lib/libc/mingw/winpthreads/spinlock.c | 82 ------------------- .../musl/src/thread/pthread_spin_destroy.c | 6 -- lib/libc/musl/src/thread/pthread_spin_init.c | 6 -- lib/libc/musl/src/thread/pthread_spin_lock.c | 8 -- .../musl/src/thread/pthread_spin_trylock.c | 7 -- .../musl/src/thread/pthread_spin_unlock.c | 7 -- lib/libc/wasi/thread-stub/pthread_spin_lock.c | 8 -- .../wasi/thread-stub/pthread_spin_trylock.c | 8 -- .../wasi/thread-stub/pthread_spin_unlock.c | 7 -- lib/std/c.zig | 20 ++++- src/libs/mingw.zig | 1 - src/libs/musl.zig | 5 -- src/libs/wasi_libc.zig | 5 -- test/c.zig | 1 + test/c/pthread.zig | 20 +++++ 17 files changed, 98 insertions(+), 151 deletions(-) create mode 100644 lib/c/pthread.zig delete mode 100644 lib/libc/mingw/winpthreads/spinlock.c delete mode 100644 lib/libc/musl/src/thread/pthread_spin_destroy.c delete mode 100644 lib/libc/musl/src/thread/pthread_spin_init.c delete mode 100644 lib/libc/musl/src/thread/pthread_spin_lock.c delete mode 100644 lib/libc/musl/src/thread/pthread_spin_trylock.c delete mode 100644 lib/libc/musl/src/thread/pthread_spin_unlock.c delete mode 100644 lib/libc/wasi/thread-stub/pthread_spin_lock.c delete mode 100644 lib/libc/wasi/thread-stub/pthread_spin_trylock.c delete mode 100644 lib/libc/wasi/thread-stub/pthread_spin_unlock.c create mode 100644 test/c/pthread.zig diff --git a/lib/c.zig b/lib/c.zig index 4a73995e2d..83ab1111f3 100644 --- a/lib/c.zig +++ b/lib/c.zig @@ -68,6 +68,7 @@ comptime { _ = @import("c/malloc.zig"); } _ = @import("c/math.zig"); + _ = @import("c/pthread.zig"); _ = @import("c/search.zig"); _ = @import("c/stdlib.zig"); _ = @import("c/string.zig"); diff --git a/lib/c/pthread.zig b/lib/c/pthread.zig new file mode 100644 index 0000000000..ca10ec7c32 --- /dev/null +++ b/lib/c/pthread.zig @@ -0,0 +1,57 @@ +const builtin = @import("builtin"); + +const std = @import("std"); +const c = std.c; + +const symbol = @import("../c.zig").symbol; + +comptime { + if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC() or builtin.target.isMinGW()) { + symbol(&pthread_spin_init, "pthread_spin_init"); + symbol(&pthread_spin_destroy, "pthread_spin_destroy"); + symbol(&pthread_spin_trylock, "pthread_spin_trylock"); + symbol(&pthread_spin_lock, "pthread_spin_lock"); + symbol(&pthread_spin_unlock, "pthread_spin_unlock"); + } +} + +const SpinLock = enum(c.pthread_spinlock_t) { + unlocked = if (builtin.target.isMinGW()) -1 else 0, + locked = if (builtin.target.isMinGW()) 0 else @intFromEnum(c.E.BUSY), +}; + +fn pthread_spin_init(s: *c.pthread_spinlock_t, pshared: c_int) callconv(.c) c_int { + _ = pshared; + const spin: *SpinLock = @ptrCast(s); + spin.* = .unlocked; + return 0; +} + +fn pthread_spin_destroy(s: *c.pthread_spinlock_t) callconv(.c) c_int { + const spin: *SpinLock = @ptrCast(s); + spin.* = undefined; + return 0; +} + +fn pthread_spin_trylock(s: *c.pthread_spinlock_t) callconv(.c) c_int { + const spin: *SpinLock = @ptrCast(s); + return if (@cmpxchgStrong(SpinLock, spin, .unlocked, .locked, .acquire, .monotonic)) |_| @intFromEnum(c.E.BUSY) else 0; +} + +fn pthread_spin_lock(s: *c.pthread_spinlock_t) callconv(.c) c_int { + const spin: *SpinLock = @ptrCast(s); + if (builtin.single_threaded and @atomicLoad(SpinLock, spin, .monotonic) == .locked) return @intFromEnum(c.E.DEADLK); + + while (@cmpxchgWeak(SpinLock, spin, .unlocked, .locked, .acquire, .monotonic)) |_| { + std.atomic.spinLoopHint(); + } + return 0; +} + +fn pthread_spin_unlock(s: *c.pthread_spinlock_t) callconv(.c) c_int { + const spin: *SpinLock = @ptrCast(s); + + // "The results are undefined if the lock is not held by the calling thread" + std.debug.assert(@atomicRmw(SpinLock, spin, .Xchg, .unlocked, .release) == .locked); + return 0; +} diff --git a/lib/libc/mingw/winpthreads/spinlock.c b/lib/libc/mingw/winpthreads/spinlock.c deleted file mode 100644 index eb21509d60..0000000000 --- a/lib/libc/mingw/winpthreads/spinlock.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - Copyright (c) 2013 mingw-w64 project - Copyright (c) 2015 Intel Corporation - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define WIN32_LEAN_AND_MEAN -#include - -/* public header files */ -#include "pthread.h" -/* internal header files */ -#include "misc.h" - -/* We use the pthread_spinlock_t itself as a lock: - -1 is free, 0 is locked. - (This is dictated by PTHREAD_SPINLOCK_INITIALIZER, which we can't change - without breaking binary compatibility.) */ -typedef intptr_t spinlock_word_t; - -int -pthread_spin_init (pthread_spinlock_t *lock, int pshared) -{ - spinlock_word_t *lk = (spinlock_word_t *)lock; - *lk = -1; - return 0; -} - - -int -pthread_spin_destroy (pthread_spinlock_t *lock) -{ - return 0; -} - -int -pthread_spin_lock (pthread_spinlock_t *lock) -{ - volatile spinlock_word_t *lk = (volatile spinlock_word_t *)lock; - while (unlikely(InterlockedExchangePointer((PVOID volatile *)lk, 0) == 0)) - do { - YieldProcessor(); - } while (*lk == 0); - return 0; -} - -int -pthread_spin_trylock (pthread_spinlock_t *lock) -{ - spinlock_word_t *lk = (spinlock_word_t *)lock; - return InterlockedExchangePointer((PVOID volatile *)lk, 0) == 0 ? EBUSY : 0; -} - - -int -pthread_spin_unlock (pthread_spinlock_t *lock) -{ - volatile spinlock_word_t *lk = (volatile spinlock_word_t *)lock; - *lk = -1; - return 0; -} diff --git a/lib/libc/musl/src/thread/pthread_spin_destroy.c b/lib/libc/musl/src/thread/pthread_spin_destroy.c deleted file mode 100644 index e65a820c3d..0000000000 --- a/lib/libc/musl/src/thread/pthread_spin_destroy.c +++ /dev/null @@ -1,6 +0,0 @@ -#include "pthread_impl.h" - -int pthread_spin_destroy(pthread_spinlock_t *s) -{ - return 0; -} diff --git a/lib/libc/musl/src/thread/pthread_spin_init.c b/lib/libc/musl/src/thread/pthread_spin_init.c deleted file mode 100644 index 681881cf36..0000000000 --- a/lib/libc/musl/src/thread/pthread_spin_init.c +++ /dev/null @@ -1,6 +0,0 @@ -#include "pthread_impl.h" - -int pthread_spin_init(pthread_spinlock_t *s, int shared) -{ - return *s = 0; -} diff --git a/lib/libc/musl/src/thread/pthread_spin_lock.c b/lib/libc/musl/src/thread/pthread_spin_lock.c deleted file mode 100644 index ded2b653c4..0000000000 --- a/lib/libc/musl/src/thread/pthread_spin_lock.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "pthread_impl.h" -#include - -int pthread_spin_lock(pthread_spinlock_t *s) -{ - while (*(volatile int *)s || a_cas(s, 0, EBUSY)) a_spin(); - return 0; -} diff --git a/lib/libc/musl/src/thread/pthread_spin_trylock.c b/lib/libc/musl/src/thread/pthread_spin_trylock.c deleted file mode 100644 index 5284fdac24..0000000000 --- a/lib/libc/musl/src/thread/pthread_spin_trylock.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "pthread_impl.h" -#include - -int pthread_spin_trylock(pthread_spinlock_t *s) -{ - return a_cas(s, 0, EBUSY); -} diff --git a/lib/libc/musl/src/thread/pthread_spin_unlock.c b/lib/libc/musl/src/thread/pthread_spin_unlock.c deleted file mode 100644 index 724d9e0d65..0000000000 --- a/lib/libc/musl/src/thread/pthread_spin_unlock.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "pthread_impl.h" - -int pthread_spin_unlock(pthread_spinlock_t *s) -{ - a_store(s, 0); - return 0; -} diff --git a/lib/libc/wasi/thread-stub/pthread_spin_lock.c b/lib/libc/wasi/thread-stub/pthread_spin_lock.c deleted file mode 100644 index 4a682a6b6f..0000000000 --- a/lib/libc/wasi/thread-stub/pthread_spin_lock.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "pthread_impl.h" - -int pthread_spin_lock(pthread_spinlock_t *s) -{ - if (*s) return EDEADLK; - *s = 1; - return 0; -} diff --git a/lib/libc/wasi/thread-stub/pthread_spin_trylock.c b/lib/libc/wasi/thread-stub/pthread_spin_trylock.c deleted file mode 100644 index 5ef1b2a02a..0000000000 --- a/lib/libc/wasi/thread-stub/pthread_spin_trylock.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "pthread_impl.h" - -int pthread_spin_trylock(pthread_spinlock_t *s) -{ - if (*s) return EBUSY; - *s = 1; - return 0; -} diff --git a/lib/libc/wasi/thread-stub/pthread_spin_unlock.c b/lib/libc/wasi/thread-stub/pthread_spin_unlock.c deleted file mode 100644 index f9d8a23dc6..0000000000 --- a/lib/libc/wasi/thread-stub/pthread_spin_unlock.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "pthread_impl.h" - -int pthread_spin_unlock(pthread_spinlock_t *s) -{ - *s = 0; - return 0; -} diff --git a/lib/std/c.zig b/lib/std/c.zig index 11b58b2162..294ff0f449 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -7898,6 +7898,12 @@ pub const Stat = switch (native_os) { else => void, }; +pub const pthread_spinlock_t = switch (native_os) { + .openbsd => openbsd.pthread_spinlock_t, + .windows => isize, + else => c_int, +}; + pub const pthread_mutex_t = switch (native_os) { .linux => extern struct { data: [data_len]u8 align(@alignOf(usize)) = [_]u8{0} ** data_len, @@ -10956,6 +10962,19 @@ pub extern "c" fn dn_expand( length: c_int, ) c_int; +pub const PTHREAD_PROCESS_PRIVATE: c_int = if (native_os.isDarwin()) + 2 +else + 0; + +pub const PTHREAD_PROCESS_SHARED: c_int = 1; + +pub extern "c" fn pthread_spin_init(spin: *pthread_spinlock_t, pshared: c_int) E; +pub extern "c" fn pthread_spin_lock(spin: *pthread_spinlock_t) E; +pub extern "c" fn pthread_spin_unlock(spin: *pthread_spinlock_t) E; +pub extern "c" fn pthread_spin_trylock(spin: *pthread_spinlock_t) E; +pub extern "c" fn pthread_spin_destroy(spin: *pthread_spinlock_t) E; + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = .{}; pub extern "c" fn pthread_mutex_lock(mutex: *pthread_mutex_t) E; pub extern "c" fn pthread_mutex_unlock(mutex: *pthread_mutex_t) E; @@ -11268,7 +11287,6 @@ pub const login_getcaptime = openbsd.login_getcaptime; pub const login_getclass = openbsd.login_getclass; pub const login_getstyle = openbsd.login_getstyle; pub const pledge = openbsd.pledge; -pub const pthread_spinlock_t = openbsd.pthread_spinlock_t; pub const pw_dup = openbsd.pw_dup; pub const setclasscontext = openbsd.setclasscontext; pub const setpassent = openbsd.setpassent; diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index 6ad4e65d16..9ea43035bb 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -913,7 +913,6 @@ const mingw32_winpthreads_src = [_][]const u8{ "winpthreads" ++ path.sep_str ++ "rwlock.c", "winpthreads" ++ path.sep_str ++ "sched.c", "winpthreads" ++ path.sep_str ++ "sem.c", - "winpthreads" ++ path.sep_str ++ "spinlock.c", "winpthreads" ++ path.sep_str ++ "thread.c", }; diff --git a/src/libs/musl.zig b/src/libs/musl.zig index beb1c2ceb8..22d9fbe51f 100644 --- a/src/libs/musl.zig +++ b/src/libs/musl.zig @@ -1663,11 +1663,6 @@ const src_files = [_][]const u8{ "musl/src/thread/pthread_setschedprio.c", "musl/src/thread/pthread_setspecific.c", "musl/src/thread/pthread_sigmask.c", - "musl/src/thread/pthread_spin_destroy.c", - "musl/src/thread/pthread_spin_init.c", - "musl/src/thread/pthread_spin_lock.c", - "musl/src/thread/pthread_spin_trylock.c", - "musl/src/thread/pthread_spin_unlock.c", "musl/src/thread/pthread_testcancel.c", "musl/src/thread/riscv32/clone.s", "musl/src/thread/riscv32/__set_thread_area.s", diff --git a/src/libs/wasi_libc.zig b/src/libs/wasi_libc.zig index 1fde2f0ef9..d94f7f6284 100644 --- a/src/libs/wasi_libc.zig +++ b/src/libs/wasi_libc.zig @@ -939,8 +939,6 @@ const libc_top_half_src_files = [_][]const u8{ "musl/src/thread/pthread_setcancelstate.c", "musl/src/thread/pthread_setcanceltype.c", "musl/src/thread/pthread_setspecific.c", - "musl/src/thread/pthread_spin_destroy.c", - "musl/src/thread/pthread_spin_init.c", "musl/src/thread/pthread_testcancel.c", "musl/src/thread/thrd_sleep.c", "musl/src/time/asctime.c", @@ -1086,9 +1084,6 @@ const libc_top_half_src_files = [_][]const u8{ "wasi/thread-stub/pthread_rwlock_trywrlock.c", "wasi/thread-stub/pthread_rwlock_unlock.c", "wasi/thread-stub/pthread_rwlock_wrlock.c", - "wasi/thread-stub/pthread_spin_lock.c", - "wasi/thread-stub/pthread_spin_trylock.c", - "wasi/thread-stub/pthread_spin_unlock.c", }; const crt1_command_src_file = "wasi/libc-bottom-half/crt/crt1-command.c"; diff --git a/test/c.zig b/test/c.zig index 797f16f5cb..d07856d037 100644 --- a/test/c.zig +++ b/test/c.zig @@ -4,6 +4,7 @@ const std = @import("std"); test { _ = @import("c/inttypes.zig"); _ = @import("c/math.zig"); + _ = @import("c/pthread.zig"); _ = @import("c/search.zig"); _ = @import("c/stdlib.zig"); _ = @import("c/string.zig"); diff --git a/test/c/pthread.zig b/test/c/pthread.zig new file mode 100644 index 0000000000..0ef98ab035 --- /dev/null +++ b/test/c/pthread.zig @@ -0,0 +1,20 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const c = std.c; +const math = std.math; +const testing = std.testing; + +test "pthread_spinlock_t" { + if (builtin.target.os.tag.isDarwin()) return; // Darwin doesn't have `pthread_spin_*` + + var spin: c.pthread_spinlock_t = undefined; + _ = c.pthread_spin_init(&spin, c.PTHREAD_PROCESS_PRIVATE); + defer _ = c.pthread_spin_destroy(&spin); + + try std.testing.expectEqual(.SUCCESS, c.pthread_spin_trylock(&spin)); + try std.testing.expectEqual(.SUCCESS, c.pthread_spin_unlock(&spin)); + + try std.testing.expectEqual(.SUCCESS, c.pthread_spin_lock(&spin)); + try std.testing.expectEqual(.SUCCESS, c.pthread_spin_unlock(&spin)); +}