zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 61cd38e8ace66de64b2d3e53b2ebc327a979c4ef (tree)
parent 9b177a7d21250b82cd18677c5c71ab04e431120d
Author: GasInfinity <me@gasinfinity.dev>
Date:   Tue, 21 Apr 2026 08:54:54 +0200

feat(libzigc): add common implementations of `pthread_spin_*`

* and remove their mingw, musl and wasi implementations

Diffstat:
Mlib/c.zig | 1+
Alib/c/pthread.zig | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dlib/libc/mingw/winpthreads/spinlock.c | 82-------------------------------------------------------------------------------
Dlib/libc/musl/src/thread/pthread_spin_destroy.c | 6------
Dlib/libc/musl/src/thread/pthread_spin_init.c | 6------
Dlib/libc/musl/src/thread/pthread_spin_lock.c | 8--------
Dlib/libc/musl/src/thread/pthread_spin_trylock.c | 7-------
Dlib/libc/musl/src/thread/pthread_spin_unlock.c | 7-------
Dlib/libc/wasi/thread-stub/pthread_spin_lock.c | 8--------
Dlib/libc/wasi/thread-stub/pthread_spin_trylock.c | 8--------
Dlib/libc/wasi/thread-stub/pthread_spin_unlock.c | 7-------
Mlib/std/c.zig | 20+++++++++++++++++++-
Msrc/libs/mingw.zig | 1-
Msrc/libs/musl.zig | 5-----
Msrc/libs/wasi_libc.zig | 5-----
Mtest/c.zig | 1+
Atest/c/pthread.zig | 20++++++++++++++++++++
17 files changed, 98 insertions(+), 151 deletions(-)

diff --git 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 @@ -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 @@ -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 <windows.h> - -/* 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 @@ -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 @@ -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 @@ -1,8 +0,0 @@ -#include "pthread_impl.h" -#include <errno.h> - -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 @@ -1,7 +0,0 @@ -#include "pthread_impl.h" -#include <errno.h> - -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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)); +}