| author | |
| committer | |
| log | d4cac43d308ffa930cd7174567be7c1fe18e29fb |
| tree | 816130dae7af5c407f17e384eb3f7bd96b9a123b |
| parent | cfde9303ff75322525746aa325026f0e12fb402c |
| parent | f8e9593851d4305a24836bdd3636255fb8c4243a |
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31990
Reviewed-by: Andrew Kelley <andrew@ziglang.org>17 files changed, 106 insertions(+), 151 deletions(-)
lib/c.zig+1| ... | ... | @@ -68,6 +68,7 @@ comptime { |
| 68 | 68 | _ = @import("c/malloc.zig"); |
| 69 | 69 | } |
| 70 | 70 | _ = @import("c/math.zig"); |
| 71 | _ = @import("c/pthread.zig"); | |
| 71 | 72 | _ = @import("c/search.zig"); |
| 72 | 73 | _ = @import("c/stdlib.zig"); |
| 73 | 74 | _ = @import("c/string.zig"); |
lib/c/pthread.zig created+57| ... | ... | @@ -0,0 +1,57 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | ||
| 3 | const std = @import("std"); | |
| 4 | const c = std.c; | |
| 5 | ||
| 6 | const symbol = @import("../c.zig").symbol; | |
| 7 | ||
| 8 | comptime { | |
| 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 | ||
| 18 | const 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 | ||
| 23 | fn 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 | ||
| 30 | fn 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 | ||
| 36 | fn 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 | ||
| 41 | fn 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 | ||
| 51 | fn 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.) */ | |
| 40 | typedef intptr_t spinlock_word_t; | |
| 41 | ||
| 42 | int | |
| 43 | pthread_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 | ||
| 51 | int | |
| 52 | pthread_spin_destroy (pthread_spinlock_t *lock) | |
| 53 | { | |
| 54 | return 0; | |
| 55 | } | |
| 56 | ||
| 57 | int | |
| 58 | pthread_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 | ||
| 68 | int | |
| 69 | pthread_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 | ||
| 76 | int | |
| 77 | pthread_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 | ||
| 3 | int 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 | ||
| 3 | int 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 | ||
| 4 | int 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 | ||
| 4 | int 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 | ||
| 3 | int 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 | ||
| 3 | int 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 | ||
| 3 | int 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 | ||
| 3 | int pthread_spin_unlock(pthread_spinlock_t *s) | |
| 4 | { | |
| 5 | 	*s = 0; | |
| 6 | 	return 0; | |
| 7 | } |
lib/std/c.zig+27-1| ... | ... | @@ -7898,6 +7898,20 @@ pub const Stat = switch (native_os) { |
| 7898 | 7898 | else => void, |
| 7899 | 7899 | }; |
| 7900 | 7900 | |
| 7901 | pub const pthread_spinlock_t = switch (native_os) { | |
| 7902 | .openbsd => openbsd.pthread_spinlock_t, | |
| 7903 | .freebsd => extern struct { | |
| 7904 | inner: ?*anyopaque = null, | |
| 7905 | }, | |
| 7906 | .netbsd => extern struct { | |
| 7907 | pts_magic: c_uint, | |
| 7908 | spin: pthread_spin_t, | |
| 7909 | pts_flags: c_int, | |
| 7910 | }, | |
| 7911 | .windows => isize, | |
| 7912 | else => c_int, | |
| 7913 | }; | |
| 7914 | ||
| 7901 | 7915 | pub const pthread_mutex_t = switch (native_os) { |
| 7902 | 7916 | .linux => extern struct { |
| 7903 | 7917 | data: [data_len]u8 align(@alignOf(usize)) = [_]u8{0} ** data_len, |
| ... | ... | @@ -10956,6 +10970,19 @@ pub extern "c" fn dn_expand( |
| 10956 | 10970 | length: c_int, |
| 10957 | 10971 | ) c_int; |
| 10958 | 10972 | |
| 10973 | pub const PTHREAD_PROCESS_PRIVATE: c_int = if (native_os.isDarwin()) | |
| 10974 | 2 | |
| 10975 | else | |
| 10976 | 0; | |
| 10977 | ||
| 10978 | pub const PTHREAD_PROCESS_SHARED: c_int = 1; | |
| 10979 | ||
| 10980 | pub extern "c" fn pthread_spin_init(spin: *pthread_spinlock_t, pshared: c_int) c_int; | |
| 10981 | pub extern "c" fn pthread_spin_lock(spin: *pthread_spinlock_t) c_int; | |
| 10982 | pub extern "c" fn pthread_spin_unlock(spin: *pthread_spinlock_t) c_int; | |
| 10983 | pub extern "c" fn pthread_spin_trylock(spin: *pthread_spinlock_t) c_int; | |
| 10984 | pub extern "c" fn pthread_spin_destroy(spin: *pthread_spinlock_t) c_int; | |
| 10985 | ||
| 10959 | 10986 | pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = .{}; |
| 10960 | 10987 | pub extern "c" fn pthread_mutex_lock(mutex: *pthread_mutex_t) E; |
| 10961 | 10988 | pub extern "c" fn pthread_mutex_unlock(mutex: *pthread_mutex_t) E; |
| ... | ... | @@ -11268,7 +11295,6 @@ pub const login_getcaptime = openbsd.login_getcaptime; |
| 11268 | 11295 | pub const login_getclass = openbsd.login_getclass; |
| 11269 | 11296 | pub const login_getstyle = openbsd.login_getstyle; |
| 11270 | 11297 | pub const pledge = openbsd.pledge; |
| 11271 | pub const pthread_spinlock_t = openbsd.pthread_spinlock_t; | |
| 11272 | 11298 | pub const pw_dup = openbsd.pw_dup; |
| 11273 | 11299 | pub const setclasscontext = openbsd.setclasscontext; |
| 11274 | 11300 | pub const setpassent = openbsd.setpassent; |
src/libs/mingw.zig-1| ... | ... | @@ -913,7 +913,6 @@ const mingw32_winpthreads_src = [_][]const u8{ |
| 913 | 913 | "winpthreads" ++ path.sep_str ++ "rwlock.c", |
| 914 | 914 | "winpthreads" ++ path.sep_str ++ "sched.c", |
| 915 | 915 | "winpthreads" ++ path.sep_str ++ "sem.c", |
| 916 | "winpthreads" ++ path.sep_str ++ "spinlock.c", | |
| 917 | 916 | "winpthreads" ++ path.sep_str ++ "thread.c", |
| 918 | 917 | }; |
| 919 | 918 |
src/libs/musl.zig-5| ... | ... | @@ -1663,11 +1663,6 @@ const src_files = [_][]const u8{ |
| 1663 | 1663 | "musl/src/thread/pthread_setschedprio.c", |
| 1664 | 1664 | "musl/src/thread/pthread_setspecific.c", |
| 1665 | 1665 | "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", | |
| 1671 | 1666 | "musl/src/thread/pthread_testcancel.c", |
| 1672 | 1667 | "musl/src/thread/riscv32/clone.s", |
| 1673 | 1668 | "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{ |
| 939 | 939 | "musl/src/thread/pthread_setcancelstate.c", |
| 940 | 940 | "musl/src/thread/pthread_setcanceltype.c", |
| 941 | 941 | "musl/src/thread/pthread_setspecific.c", |
| 942 | "musl/src/thread/pthread_spin_destroy.c", | |
| 943 | "musl/src/thread/pthread_spin_init.c", | |
| 944 | 942 | "musl/src/thread/pthread_testcancel.c", |
| 945 | 943 | "musl/src/thread/thrd_sleep.c", |
| 946 | 944 | "musl/src/time/asctime.c", |
| ... | ... | @@ -1086,9 +1084,6 @@ const libc_top_half_src_files = [_][]const u8{ |
| 1086 | 1084 | "wasi/thread-stub/pthread_rwlock_trywrlock.c", |
| 1087 | 1085 | "wasi/thread-stub/pthread_rwlock_unlock.c", |
| 1088 | 1086 | "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", | |
| 1092 | 1087 | }; |
| 1093 | 1088 | |
| 1094 | 1089 | const crt1_command_src_file = "wasi/libc-bottom-half/crt/crt1-command.c"; |
test/c.zig+1| ... | ... | @@ -4,6 +4,7 @@ const std = @import("std"); |
| 4 | 4 | test { |
| 5 | 5 | _ = @import("c/inttypes.zig"); |
| 6 | 6 | _ = @import("c/math.zig"); |
| 7 | _ = @import("c/pthread.zig"); | |
| 7 | 8 | _ = @import("c/search.zig"); |
| 8 | 9 | _ = @import("c/stdlib.zig"); |
| 9 | 10 | _ = @import("c/string.zig"); |
test/c/pthread.zig created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("std"); | |
| 3 | ||
| 4 | const c = std.c; | |
| 5 | const math = std.math; | |
| 6 | const testing = std.testing; | |
| 7 | ||
| 8 | test "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(@intFromEnum(c.E.SUCCESS), c.pthread_spin_trylock(&spin)); | |
| 16 | try std.testing.expectEqual(@intFromEnum(c.E.SUCCESS), c.pthread_spin_unlock(&spin)); | |
| 17 | ||
| 18 | try std.testing.expectEqual(@intFromEnum(c.E.SUCCESS), c.pthread_spin_lock(&spin)); | |
| 19 | try std.testing.expectEqual(@intFromEnum(c.E.SUCCESS), c.pthread_spin_unlock(&spin)); | |
| 20 | } |