authorgravatar for me@gasinfinity.devGasInfinity <me@gasinfinity.dev> 2026-04-21 08:54:54+02:00
committergravatar for me@gasinfinity.devGasInfinity <me@gasinfinity.dev> 2026-04-21 09:03:06+02:00
log61cd38e8ace66de64b2d3e53b2ebc327a979c4ef
treecc271bb44627f163be2778fb16bf43ed744c6c98
parent9b177a7d21250b82cd18677c5c71ab04e431120d
signaturebadge-check Signed by SSH key SHA256:p3IHbr0lyK2ekfDC1Zi7dOEV/9T6lGghNawhl5sBnM4

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

* and remove their mingw, musl and wasi implementations

17 files changed, 98 insertions(+), 151 deletions(-)

lib/c.zig+1
......@@ -68,6 +68,7 @@ comptime {
6868 _ = @import("c/malloc.zig");
6969 }
7070 _ = @import("c/math.zig");
71 _ = @import("c/pthread.zig");
7172 _ = @import("c/search.zig");
7273 _ = @import("c/stdlib.zig");
7374 _ = @import("c/string.zig");
lib/c/pthread.zig created+57
......@@ -0,0 +1,57 @@
1const builtin = @import("builtin");
2
3const std = @import("std");
4const c = std.c;
5
6const symbol = @import("../c.zig").symbol;
7
8comptime {
9 if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC() or builtin.target.isMinGW()) {
10 symbol(&pthread_spin_init, "pthread_spin_init");
11 symbol(&pthread_spin_destroy, "pthread_spin_destroy");
12 symbol(&pthread_spin_trylock, "pthread_spin_trylock");
13 symbol(&pthread_spin_lock, "pthread_spin_lock");
14 symbol(&pthread_spin_unlock, "pthread_spin_unlock");
15 }
16}
17
18const SpinLock = enum(c.pthread_spinlock_t) {
19 unlocked = if (builtin.target.isMinGW()) -1 else 0,
20 locked = if (builtin.target.isMinGW()) 0 else @intFromEnum(c.E.BUSY),
21};
22
23fn pthread_spin_init(s: *c.pthread_spinlock_t, pshared: c_int) callconv(.c) c_int {
24 _ = pshared;
25 const spin: *SpinLock = @ptrCast(s);
26 spin.* = .unlocked;
27 return 0;
28}
29
30fn pthread_spin_destroy(s: *c.pthread_spinlock_t) callconv(.c) c_int {
31 const spin: *SpinLock = @ptrCast(s);
32 spin.* = undefined;
33 return 0;
34}
35
36fn pthread_spin_trylock(s: *c.pthread_spinlock_t) callconv(.c) c_int {
37 const spin: *SpinLock = @ptrCast(s);
38 return if (@cmpxchgStrong(SpinLock, spin, .unlocked, .locked, .acquire, .monotonic)) |_| @intFromEnum(c.E.BUSY) else 0;
39}
40
41fn pthread_spin_lock(s: *c.pthread_spinlock_t) callconv(.c) c_int {
42 const spin: *SpinLock = @ptrCast(s);
43 if (builtin.single_threaded and @atomicLoad(SpinLock, spin, .monotonic) == .locked) return @intFromEnum(c.E.DEADLK);
44
45 while (@cmpxchgWeak(SpinLock, spin, .unlocked, .locked, .acquire, .monotonic)) |_| {
46 std.atomic.spinLoopHint();
47 }
48 return 0;
49}
50
51fn pthread_spin_unlock(s: *c.pthread_spinlock_t) callconv(.c) c_int {
52 const spin: *SpinLock = @ptrCast(s);
53
54 // "The results are undefined if the lock is not held by the calling thread"
55 std.debug.assert(@atomicRmw(SpinLock, spin, .Xchg, .unlocked, .release) == .locked);
56 return 0;
57}
lib/libc/mingw/winpthreads/spinlock.c deleted-82
......@@ -1,82 +0,0 @@
1/*
2 Copyright (c) 2013 mingw-w64 project
3 Copyright (c) 2015 Intel Corporation
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 DEALINGS IN THE SOFTWARE.
22*/
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#define WIN32_LEAN_AND_MEAN
29#include <windows.h>
30
31/* public header files */
32#include "pthread.h"
33/* internal header files */
34#include "misc.h"
35
36/* We use the pthread_spinlock_t itself as a lock:
37 -1 is free, 0 is locked.
38 (This is dictated by PTHREAD_SPINLOCK_INITIALIZER, which we can't change
39 without breaking binary compatibility.) */
40typedef intptr_t spinlock_word_t;
41
42int
43pthread_spin_init (pthread_spinlock_t *lock, int pshared)
44{
45 spinlock_word_t *lk = (spinlock_word_t *)lock;
46 *lk = -1;
47 return 0;
48}
49
50
51int
52pthread_spin_destroy (pthread_spinlock_t *lock)
53{
54 return 0;
55}
56
57int
58pthread_spin_lock (pthread_spinlock_t *lock)
59{
60 volatile spinlock_word_t *lk = (volatile spinlock_word_t *)lock;
61 while (unlikely(InterlockedExchangePointer((PVOID volatile *)lk, 0) == 0))
62 do {
63 YieldProcessor();
64 } while (*lk == 0);
65 return 0;
66}
67
68int
69pthread_spin_trylock (pthread_spinlock_t *lock)
70{
71 spinlock_word_t *lk = (spinlock_word_t *)lock;
72 return InterlockedExchangePointer((PVOID volatile *)lk, 0) == 0 ? EBUSY : 0;
73}
74
75
76int
77pthread_spin_unlock (pthread_spinlock_t *lock)
78{
79 volatile spinlock_word_t *lk = (volatile spinlock_word_t *)lock;
80 *lk = -1;
81 return 0;
82}
lib/libc/musl/src/thread/pthread_spin_destroy.c deleted-6
......@@ -1,6 +0,0 @@
1#include "pthread_impl.h"
2
3int pthread_spin_destroy(pthread_spinlock_t *s)
4{
5 return 0;
6}
lib/libc/musl/src/thread/pthread_spin_init.c deleted-6
......@@ -1,6 +0,0 @@
1#include "pthread_impl.h"
2
3int pthread_spin_init(pthread_spinlock_t *s, int shared)
4{
5 return *s = 0;
6}
lib/libc/musl/src/thread/pthread_spin_lock.c deleted-8
......@@ -1,8 +0,0 @@
1#include "pthread_impl.h"
2#include <errno.h>
3
4int pthread_spin_lock(pthread_spinlock_t *s)
5{
6 while (*(volatile int *)s || a_cas(s, 0, EBUSY)) a_spin();
7 return 0;
8}
lib/libc/musl/src/thread/pthread_spin_trylock.c deleted-7
......@@ -1,7 +0,0 @@
1#include "pthread_impl.h"
2#include <errno.h>
3
4int pthread_spin_trylock(pthread_spinlock_t *s)
5{
6 return a_cas(s, 0, EBUSY);
7}
lib/libc/musl/src/thread/pthread_spin_unlock.c deleted-7
......@@ -1,7 +0,0 @@
1#include "pthread_impl.h"
2
3int pthread_spin_unlock(pthread_spinlock_t *s)
4{
5 a_store(s, 0);
6 return 0;
7}
lib/libc/wasi/thread-stub/pthread_spin_lock.c deleted-8
......@@ -1,8 +0,0 @@
1#include "pthread_impl.h"
2
3int pthread_spin_lock(pthread_spinlock_t *s)
4{
5 if (*s) return EDEADLK;
6 *s = 1;
7 return 0;
8}
lib/libc/wasi/thread-stub/pthread_spin_trylock.c deleted-8
......@@ -1,8 +0,0 @@
1#include "pthread_impl.h"
2
3int pthread_spin_trylock(pthread_spinlock_t *s)
4{
5 if (*s) return EBUSY;
6 *s = 1;
7 return 0;
8}
lib/libc/wasi/thread-stub/pthread_spin_unlock.c deleted-7
......@@ -1,7 +0,0 @@
1#include "pthread_impl.h"
2
3int pthread_spin_unlock(pthread_spinlock_t *s)
4{
5 *s = 0;
6 return 0;
7}
lib/std/c.zig+19-1
......@@ -7898,6 +7898,12 @@ pub const Stat = switch (native_os) {
78987898 else => void,
78997899};
79007900
7901pub const pthread_spinlock_t = switch (native_os) {
7902 .openbsd => openbsd.pthread_spinlock_t,
7903 .windows => isize,
7904 else => c_int,
7905};
7906
79017907pub const pthread_mutex_t = switch (native_os) {
79027908 .linux => extern struct {
79037909 data: [data_len]u8 align(@alignOf(usize)) = [_]u8{0} ** data_len,
......@@ -10956,6 +10962,19 @@ pub extern "c" fn dn_expand(
1095610962 length: c_int,
1095710963) c_int;
1095810964
10965pub const PTHREAD_PROCESS_PRIVATE: c_int = if (native_os.isDarwin())
10966 2
10967else
10968 0;
10969
10970pub const PTHREAD_PROCESS_SHARED: c_int = 1;
10971
10972pub extern "c" fn pthread_spin_init(spin: *pthread_spinlock_t, pshared: c_int) E;
10973pub extern "c" fn pthread_spin_lock(spin: *pthread_spinlock_t) E;
10974pub extern "c" fn pthread_spin_unlock(spin: *pthread_spinlock_t) E;
10975pub extern "c" fn pthread_spin_trylock(spin: *pthread_spinlock_t) E;
10976pub extern "c" fn pthread_spin_destroy(spin: *pthread_spinlock_t) E;
10977
1095910978pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = .{};
1096010979pub extern "c" fn pthread_mutex_lock(mutex: *pthread_mutex_t) E;
1096110980pub extern "c" fn pthread_mutex_unlock(mutex: *pthread_mutex_t) E;
......@@ -11268,7 +11287,6 @@ pub const login_getcaptime = openbsd.login_getcaptime;
1126811287pub const login_getclass = openbsd.login_getclass;
1126911288pub const login_getstyle = openbsd.login_getstyle;
1127011289pub const pledge = openbsd.pledge;
11271pub const pthread_spinlock_t = openbsd.pthread_spinlock_t;
1127211290pub const pw_dup = openbsd.pw_dup;
1127311291pub const setclasscontext = openbsd.setclasscontext;
1127411292pub const setpassent = openbsd.setpassent;
src/libs/mingw.zig-1
......@@ -913,7 +913,6 @@ const mingw32_winpthreads_src = [_][]const u8{
913913 "winpthreads" ++ path.sep_str ++ "rwlock.c",
914914 "winpthreads" ++ path.sep_str ++ "sched.c",
915915 "winpthreads" ++ path.sep_str ++ "sem.c",
916 "winpthreads" ++ path.sep_str ++ "spinlock.c",
917916 "winpthreads" ++ path.sep_str ++ "thread.c",
918917};
919918
src/libs/musl.zig-5
......@@ -1663,11 +1663,6 @@ const src_files = [_][]const u8{
16631663 "musl/src/thread/pthread_setschedprio.c",
16641664 "musl/src/thread/pthread_setspecific.c",
16651665 "musl/src/thread/pthread_sigmask.c",
1666 "musl/src/thread/pthread_spin_destroy.c",
1667 "musl/src/thread/pthread_spin_init.c",
1668 "musl/src/thread/pthread_spin_lock.c",
1669 "musl/src/thread/pthread_spin_trylock.c",
1670 "musl/src/thread/pthread_spin_unlock.c",
16711666 "musl/src/thread/pthread_testcancel.c",
16721667 "musl/src/thread/riscv32/clone.s",
16731668 "musl/src/thread/riscv32/__set_thread_area.s",
src/libs/wasi_libc.zig-5
......@@ -939,8 +939,6 @@ const libc_top_half_src_files = [_][]const u8{
939939 "musl/src/thread/pthread_setcancelstate.c",
940940 "musl/src/thread/pthread_setcanceltype.c",
941941 "musl/src/thread/pthread_setspecific.c",
942 "musl/src/thread/pthread_spin_destroy.c",
943 "musl/src/thread/pthread_spin_init.c",
944942 "musl/src/thread/pthread_testcancel.c",
945943 "musl/src/thread/thrd_sleep.c",
946944 "musl/src/time/asctime.c",
......@@ -1086,9 +1084,6 @@ const libc_top_half_src_files = [_][]const u8{
10861084 "wasi/thread-stub/pthread_rwlock_trywrlock.c",
10871085 "wasi/thread-stub/pthread_rwlock_unlock.c",
10881086 "wasi/thread-stub/pthread_rwlock_wrlock.c",
1089 "wasi/thread-stub/pthread_spin_lock.c",
1090 "wasi/thread-stub/pthread_spin_trylock.c",
1091 "wasi/thread-stub/pthread_spin_unlock.c",
10921087};
10931088
10941089const crt1_command_src_file = "wasi/libc-bottom-half/crt/crt1-command.c";
test/c.zig+1
......@@ -4,6 +4,7 @@ const std = @import("std");
44test {
55 _ = @import("c/inttypes.zig");
66 _ = @import("c/math.zig");
7 _ = @import("c/pthread.zig");
78 _ = @import("c/search.zig");
89 _ = @import("c/stdlib.zig");
910 _ = @import("c/string.zig");
test/c/pthread.zig created+20
......@@ -0,0 +1,20 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const c = std.c;
5const math = std.math;
6const testing = std.testing;
7
8test "pthread_spinlock_t" {
9 if (builtin.target.os.tag.isDarwin()) return; // Darwin doesn't have `pthread_spin_*`
10
11 var spin: c.pthread_spinlock_t = undefined;
12 _ = c.pthread_spin_init(&spin, c.PTHREAD_PROCESS_PRIVATE);
13 defer _ = c.pthread_spin_destroy(&spin);
14
15 try std.testing.expectEqual(.SUCCESS, c.pthread_spin_trylock(&spin));
16 try std.testing.expectEqual(.SUCCESS, c.pthread_spin_unlock(&spin));
17
18 try std.testing.expectEqual(.SUCCESS, c.pthread_spin_lock(&spin));
19 try std.testing.expectEqual(.SUCCESS, c.pthread_spin_unlock(&spin));
20}