authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-11-08 01:52:23-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-11-08 01:52:23-05:00
log2723ffc2b2d837aec8185f86814a6e6aba45c34d
tree0226ba98b0c3a1cd5c5a441819902a1ca8df16e9
parentfbbcf2f30d3fe0a9b0c41de9b737c13737497a3b
signaturelock-open Commit is signed but in an unrecognized format.

fixups and zig fmt


23 files changed, 308 insertions(+), 278 deletions(-)

lib/std/c.zig+21-1
...@@ -8,9 +8,16 @@ pub usingnamespace switch (builtin.os) {...@@ -8,9 +8,16 @@ pub usingnamespace switch (builtin.os) {
8 .linux => @import("c/linux.zig"),8 .linux => @import("c/linux.zig"),
9 .windows => @import("c/windows.zig"),9 .windows => @import("c/windows.zig"),
10 .macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"),10 .macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"),
11 .freebsd => @import("c/freebsd.zig"),11 .freebsd, .kfreebsd => @import("c/freebsd.zig"),
12 .netbsd => @import("c/netbsd.zig"),12 .netbsd => @import("c/netbsd.zig"),
13 .dragonfly => @import("c/dragonfly.zig"),13 .dragonfly => @import("c/dragonfly.zig"),
14 .openbsd => @import("c/openbsd.zig"),
15 .haiku => @import("c/haiku.zig"),
16 .hermit => @import("c/hermit.zig"),
17 .solaris => @import("c/solaris.zig"),
18 .fuchsia => @import("c/fuchsia.zig"),
19 .minix => @import("c/minix.zig"),
20 .emscripten => @import("c/emscripten.zig"),
14 else => struct {},21 else => struct {},
15};22};
1623
...@@ -205,3 +212,16 @@ pub extern "c" fn dn_expand(...@@ -205,3 +212,16 @@ pub extern "c" fn dn_expand(
205) c_int;212) c_int;
206213
207pub extern "c" fn sched_yield() c_int;214pub extern "c" fn sched_yield() c_int;
215
216pub const PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{};
217pub extern "c" fn pthread_mutex_lock(mutex: *pthread_mutex_t) c_int;
218pub extern "c" fn pthread_mutex_unlock(mutex: *pthread_mutex_t) c_int;
219pub extern "c" fn pthread_mutex_destroy(mutex: *pthread_mutex_t) c_int;
220
221pub const PTHREAD_COND_INITIALIZER = pthread_cond_t{};
222pub extern "c" fn pthread_cond_wait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t) c_int;
223pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int;
224pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c_int;
225
226pub const pthread_t = *@OpaqueType();
227pub const FILE = @OpaqueType();
lib/std/c/darwin.zig+16
...@@ -112,3 +112,19 @@ pub const EAI_PROTOCOL = 13;...@@ -112,3 +112,19 @@ pub const EAI_PROTOCOL = 13;
112/// argument buffer overflow112/// argument buffer overflow
113pub const EAI_OVERFLOW = 14;113pub const EAI_OVERFLOW = 14;
114pub const EAI_MAX = 15;114pub const EAI_MAX = 15;
115
116pub const pthread_mutex_t = extern struct {
117 __sig: c_long = 0x32AAABA7,
118 __opaque: [__PTHREAD_MUTEX_SIZE__]u8 = [_]u8{0} ** __PTHREAD_MUTEX_SIZE__,
119};
120pub const pthread_cond_t = extern struct {
121 __sig: c_long = 0x3CB0B1BB,
122 __opaque: [__PTHREAD_COND_SIZE__]u8 = [_]u8{0} ** __PTHREAD_COND_SIZE__,
123};
124const __PTHREAD_MUTEX_SIZE__ = if (@sizeOf(usize) == 8) 56 else 40;
125const __PTHREAD_COND_SIZE__ = if (@sizeOf(usize) == 8) 40 else 24;
126
127pub const pthread_attr_t = extern struct {
128 __sig: c_long,
129 __opaque: [56]u8,
130};
lib/std/c/dragonfly.zig+12-1
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2usingnamespace std.c;2usingnamespace std.c;
3
4extern "c" threadlocal var errno: c_int;3extern "c" threadlocal var errno: c_int;
5pub fn _errno() *c_int {4pub fn _errno() *c_int {
6 return &errno;5 return &errno;
...@@ -12,3 +11,15 @@ pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize...@@ -12,3 +11,15 @@ pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize
1211
13pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int;12pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int;
14pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;13pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;
14
15pub const pthread_mutex_t = extern struct {
16 inner: ?*c_void = null,
17};
18pub const pthread_cond_t = extern struct {
19 inner: ?*c_void = null,
20};
21
22pub const pthread_attr_t = extern struct { // copied from freebsd
23 __size: [56]u8,
24 __align: c_long,
25};
lib/std/c/emscripten.zig created+8
...@@ -0,0 +1,8 @@
1pub const pthread_mutex_t = extern struct {
2 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(4) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
3};
4pub const pthread_cond_t = extern struct {
5 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
6};
7const __SIZEOF_PTHREAD_COND_T = 48;
8const __SIZEOF_PTHREAD_MUTEX_T = 28;
lib/std/c/freebsd.zig+12
...@@ -10,3 +10,15 @@ pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize...@@ -10,3 +10,15 @@ pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize
1010
11pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int;11pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int;
12pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;12pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;
13
14pub const pthread_mutex_t = extern struct {
15 inner: ?*c_void = null,
16};
17pub const pthread_cond_t = extern struct {
18 inner: ?*c_void = null,
19};
20
21pub const pthread_attr_t = extern struct {
22 __size: [56]u8,
23 __align: c_long,
24};
lib/std/c/fuchsia.zig created+8
...@@ -0,0 +1,8 @@
1pub const pthread_mutex_t = extern struct {
2 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
3};
4pub const pthread_cond_t = extern struct {
5 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
6};
7const __SIZEOF_PTHREAD_COND_T = 48;
8const __SIZEOF_PTHREAD_MUTEX_T = 40;
lib/std/c/haiku.zig created+14
...@@ -0,0 +1,14 @@
1pub const pthread_mutex_t = extern struct {
2 flags: u32 = 0,
3 lock: i32 = 0,
4 unused: i32 = -42,
5 owner: i32 = -1,
6 owner_count: i32 = 0,
7};
8pub const pthread_cond_t = extern struct {
9 flags: u32 = 0,
10 unused: i32 = -42,
11 mutex: ?*c_void = null,
12 waiter_count: i32 = 0,
13 lock: i32 = 0,
14};
lib/std/c/hermit.zig created+6
...@@ -0,0 +1,6 @@
1pub const pthread_mutex_t = extern struct {
2 inner: usize = ~usize(0),
3};
4pub const pthread_cond_t = extern struct {
5 inner: usize = ~usize(0),
6};
lib/std/c/linux.zig+23
...@@ -75,3 +75,26 @@ pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize...@@ -75,3 +75,26 @@ pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize
75pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;75pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;
7676
77pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;77pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
78
79pub const pthread_attr_t = extern struct {
80 __size: [56]u8,
81 __align: c_long,
82};
83
84pub const pthread_mutex_t = extern struct {
85 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
86};
87pub const pthread_cond_t = extern struct {
88 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
89};
90const __SIZEOF_PTHREAD_COND_T = 48;
91const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os == .fuchsia) 40 else switch (builtin.abi) {
92 .musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
93 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (builtin.arch) {
94 .aarch64 => 48,
95 .x86_64 => if (builtin.abi == .gnux32) 40 else 32,
96 .mips64, .powerpc64, .powerpc64le, .sparcv9 => 40,
97 else => if (@sizeOf(usize) == 8) 40 else 24,
98 },
99 else => unreachable,
100};
lib/std/c/minix.zig created+18
...@@ -0,0 +1,18 @@
1const builtin = @import("builtin");
2pub const pthread_mutex_t = extern struct {
3 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
4};
5pub const pthread_cond_t = extern struct {
6 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
7};
8const __SIZEOF_PTHREAD_COND_T = 48;
9const __SIZEOF_PTHREAD_MUTEX_T = switch (builtin.abi) {
10 .musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
11 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (builtin.arch) {
12 .aarch64 => 48,
13 .x86_64 => if (builtin.abi == .gnux32) 40 else 32,
14 .mips64, .powerpc64, .powerpc64le, .sparcv9 => 40,
15 else => if (@sizeOf(usize) == 8) 40 else 24,
16 },
17 else => unreachable,
18};
lib/std/c/netbsd.zig+29
...@@ -6,3 +6,32 @@ pub const _errno = __errno;...@@ -6,3 +6,32 @@ pub const _errno = __errno;
66
7pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;7pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
8pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;8pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
9
10pub const pthread_mutex_t = extern struct {
11 ptm_magic: c_uint = 0x33330003,
12 ptm_errorcheck: padded_spin_t = 0,
13 ptm_unused: padded_spin_t = 0,
14 ptm_owner: usize = 0,
15 ptm_waiters: ?*u8 = null,
16 ptm_recursed: c_uint = 0,
17 ptm_spare2: ?*c_void = null,
18};
19pub const pthread_cond_t = extern struct {
20 ptc_magic: c_uint = 0x55550005,
21 ptc_lock: pthread_spin_t = 0,
22 ptc_waiters_first: ?*u8 = null,
23 ptc_waiters_last: ?*u8 = null,
24 ptc_mutex: ?*pthread_mutex_t = null,
25 ptc_private: ?*c_void = null,
26};
27const pthread_spin_t = if (builtin.arch == .arm or .arch == .powerpc) c_int else u8;
28const padded_spin_t = switch (builtin.arch) {
29 .sparc, .sparcel, .sparcv9, .i386, .x86_64, .le64 => u32,
30 else => spin_t,
31};
32
33pub const pthread_attr_t = extern struct {
34 pta_magic: u32,
35 pta_flags: c_int,
36 pta_private: *c_void,
37};
lib/std/c/openbsd.zig created+6
...@@ -0,0 +1,6 @@
1pub const pthread_mutex_t = extern struct {
2 inner: ?*c_void = null,
3};
4pub const pthread_cond_t = extern struct {
5 inner: ?*c_void = null,
6};
lib/std/c/solaris.zig created+15
...@@ -0,0 +1,15 @@
1pub const pthread_mutex_t = extern struct {
2 __pthread_mutex_flag1: u16 = 0,
3 __pthread_mutex_flag2: u8 = 0,
4 __pthread_mutex_ceiling: u8 = 0,
5 __pthread_mutex_type: u16 = 0,
6 __pthread_mutex_magic: u16 = 0x4d58,
7 __pthread_mutex_lock: u64 = 0,
8 __pthread_mutex_data: u64 = 0,
9};
10pub const pthread_cond_t = extern struct {
11 __pthread_cond_flag: u32 = 0,
12 __pthread_cond_type: u16 = 0,
13 __pthread_cond_magic: u16 = 0x4356,
14 __pthread_cond_data: u64 = 0,
15};
lib/std/mutex.zig+66-63
...@@ -37,80 +37,83 @@ pub const Mutex = if (builtin.single_threaded)...@@ -37,80 +37,83 @@ pub const Mutex = if (builtin.single_threaded)
37 return Held{ .mutex = self };37 return Held{ .mutex = self };
38 }38 }
39 }39 }
40else struct {40else
41 state: u32, // TODO: make this an enum41 struct {
42 parker: ThreadParker,42 state: u32, // TODO: make this an enum
4343 parker: ThreadParker,
44 const Unlocked = 0;
45 const Sleeping = 1;
46 const Locked = 2;
47
48 /// number of iterations to spin yielding the cpu
49 const SPIN_CPU = 4;
50 /// number of iterations to perform in the cpu yield loop
51 const SPIN_CPU_COUNT = 30;
52 /// number of iterations to spin yielding the thread
53 const SPIN_THREAD = 1;
54
55 pub fn init() Mutex {
56 return Mutex{
57 .state = Unlocked,
58 .parker = ThreadParker.init(),
59 };
60 }
6144
62 pub fn deinit(self: *Mutex) void {45 const Unlocked = 0;
63 self.parker.deinit();46 const Sleeping = 1;
64 }47 const Locked = 2;
6548
66 pub const Held = struct {49 /// number of iterations to spin yielding the cpu
67 mutex: *Mutex,50 const SPIN_CPU = 4;
6851
69 pub fn release(self: Held) void {52 /// number of iterations to perform in the cpu yield loop
70 switch (@atomicRmw(u32, &self.mutex.state, .Xchg, Unlocked, .Release)) {53 const SPIN_CPU_COUNT = 30;
71 Locked => {},54
72 Sleeping => self.mutex.parker.unpark(&self.mutex.state),55 /// number of iterations to spin yielding the thread
73 Unlocked => unreachable, // unlocking an unlocked mutex56 const SPIN_THREAD = 1;
74 else => unreachable, // should never be anything else57
75 }58 pub fn init() Mutex {
59 return Mutex{
60 .state = Unlocked,
61 .parker = ThreadParker.init(),
62 };
76 }63 }
77 };
7864
79 pub fn acquire(self: *Mutex) Held {65 pub fn deinit(self: *Mutex) void {
80 // Try and speculatively grab the lock.66 self.parker.deinit();
81 // If it fails, the state is either Locked or Sleeping67 }
82 // depending on if theres a thread stuck sleeping below.
83 var state = @atomicRmw(u32, &self.state, .Xchg, Locked, .Acquire);
84 if (state == Unlocked)
85 return Held{ .mutex = self };
8668
87 while (true) {69 pub const Held = struct {
88 // try and acquire the lock using cpu spinning on failure70 mutex: *Mutex,
89 var spin: usize = 0;
90 while (spin < SPIN_CPU) : (spin += 1) {
91 var value = @atomicLoad(u32, &self.state, .Monotonic);
92 while (value == Unlocked)
93 value = @cmpxchgWeak(u32, &self.state, Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };
94 SpinLock.yield(SPIN_CPU_COUNT);
95 }
9671
97 // try and acquire the lock using thread rescheduling on failure72 pub fn release(self: Held) void {
98 spin = 0;73 switch (@atomicRmw(u32, &self.mutex.state, .Xchg, Unlocked, .Release)) {
99 while (spin < SPIN_THREAD) : (spin += 1) {74 Locked => {},
100 var value = @atomicLoad(u32, &self.state, .Monotonic);75 Sleeping => self.mutex.parker.unpark(&self.mutex.state),
101 while (value == Unlocked)76 Unlocked => unreachable, // unlocking an unlocked mutex
102 value = @cmpxchgWeak(u32, &self.state, Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };77 else => unreachable, // should never be anything else
103 std.os.sched_yield();78 }
104 }79 }
80 };
10581
106 // failed to acquire the lock, go to sleep until woken up by `Held.release()`82 pub fn acquire(self: *Mutex) Held {
107 if (@atomicRmw(u32, &self.state, .Xchg, Sleeping, .Acquire) == Unlocked)83 // Try and speculatively grab the lock.
84 // If it fails, the state is either Locked or Sleeping
85 // depending on if theres a thread stuck sleeping below.
86 var state = @atomicRmw(u32, &self.state, .Xchg, Locked, .Acquire);
87 if (state == Unlocked)
108 return Held{ .mutex = self };88 return Held{ .mutex = self };
109 state = Sleeping;89
110 self.parker.park(&self.state, Sleeping);90 while (true) {
91 // try and acquire the lock using cpu spinning on failure
92 var spin: usize = 0;
93 while (spin < SPIN_CPU) : (spin += 1) {
94 var value = @atomicLoad(u32, &self.state, .Monotonic);
95 while (value == Unlocked)
96 value = @cmpxchgWeak(u32, &self.state, Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };
97 SpinLock.yield(SPIN_CPU_COUNT);
98 }
99
100 // try and acquire the lock using thread rescheduling on failure
101 spin = 0;
102 while (spin < SPIN_THREAD) : (spin += 1) {
103 var value = @atomicLoad(u32, &self.state, .Monotonic);
104 while (value == Unlocked)
105 value = @cmpxchgWeak(u32, &self.state, Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };
106 std.os.sched_yield() catch std.time.sleep(1);
107 }
108
109 // failed to acquire the lock, go to sleep until woken up by `Held.release()`
110 if (@atomicRmw(u32, &self.state, .Xchg, Sleeping, .Acquire) == Unlocked)
111 return Held{ .mutex = self };
112 state = Sleeping;
113 self.parker.park(&self.state, Sleeping);
114 }
111 }115 }
112 }116 };
113};
114117
115const TestContext = struct {118const TestContext = struct {
116 mutex: *Mutex,119 mutex: *Mutex,
lib/std/os.zig+16-4
...@@ -3172,9 +3172,21 @@ pub fn dn_expand(...@@ -3172,9 +3172,21 @@ pub fn dn_expand(
3172 return error.InvalidDnsPacket;3172 return error.InvalidDnsPacket;
3173}3173}
31743174
3175pub fn sched_yield() void {3175pub const SchedYieldError = error{
3176 switch (builtin.os) {3176 /// The system is not configured to allow yielding
3177 .windows => _ = windows.kernel32.SwitchToThread(),3177 SystemCannotYield,
3178 else => assert(system.sched_yield() == 0),3178};
3179
3180pub fn sched_yield() SchedYieldError!void {
3181 if (builtin.os == .windows) {
3182 // The return value has to do with how many other threads there are; it is not
3183 // an error condition on Windows.
3184 _ = windows.kernel32.SwitchToThread();
3185 return;
3186 }
3187 switch (errno(system.sched_yield())) {
3188 0 => return,
3189 ENOSYS => return error.SystemCannotYield,
3190 else => return error.SystemCannotYield,
3179 }3191 }
3180}3192}
lib/std/os/bits.zig-3
...@@ -14,9 +14,6 @@ pub usingnamespace switch (builtin.os) {...@@ -14,9 +14,6 @@ pub usingnamespace switch (builtin.os) {
14 else => struct {},14 else => struct {},
15};15};
1616
17pub const pthread_t = *@OpaqueType();
18pub const FILE = @OpaqueType();
19
20pub const iovec = extern struct {17pub const iovec = extern struct {
21 iov_base: [*]u8,18 iov_base: [*]u8,
22 iov_len: usize,19 iov_len: usize,
lib/std/os/bits/darwin.zig-5
...@@ -133,11 +133,6 @@ pub const dirent = extern struct {...@@ -133,11 +133,6 @@ pub const dirent = extern struct {
133 }133 }
134};134};
135135
136pub const pthread_attr_t = extern struct {
137 __sig: c_long,
138 __opaque: [56]u8,
139};
140
141/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.136/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
142pub const Kevent = extern struct {137pub const Kevent = extern struct {
143 ident: usize,138 ident: usize,
lib/std/os/bits/dragonfly.zig+3-8
...@@ -360,11 +360,6 @@ pub const Kevent = extern struct {...@@ -360,11 +360,6 @@ pub const Kevent = extern struct {
360 udata: usize,360 udata: usize,
361};361};
362362
363pub const pthread_attr_t = extern struct { // copied from freebsd
364 __size: [56]u8,
365 __align: c_long,
366};
367
368pub const EVFILT_FS = -10;363pub const EVFILT_FS = -10;
369pub const EVFILT_USER = -9;364pub const EVFILT_USER = -9;
370pub const EVFILT_EXCEPT = -8;365pub const EVFILT_EXCEPT = -8;
...@@ -515,13 +510,13 @@ pub const sigset_t = extern struct {...@@ -515,13 +510,13 @@ pub const sigset_t = extern struct {
515pub const sig_atomic_t = c_int;510pub const sig_atomic_t = c_int;
516pub const Sigaction = extern struct {511pub const Sigaction = extern struct {
517 __sigaction_u: extern union {512 __sigaction_u: extern union {
518 __sa_handler: ?extern fn(c_int) void,513 __sa_handler: ?extern fn (c_int) void,
519 __sa_sigaction: ?extern fn(c_int, [*c]siginfo_t, ?*c_void) void,514 __sa_sigaction: ?extern fn (c_int, [*c]siginfo_t, ?*c_void) void,
520 },515 },
521 sa_flags: c_int,516 sa_flags: c_int,
522 sa_mask: sigset_t,517 sa_mask: sigset_t,
523};518};
524pub const sig_t = [*c]extern fn(c_int) void;519pub const sig_t = [*c]extern fn (c_int) void;
525520
526pub const sigvec = extern struct {521pub const sigvec = extern struct {
527 sv_handler: [*c]__sighandler_t,522 sv_handler: [*c]__sighandler_t,
lib/std/os/bits/freebsd.zig-5
...@@ -15,11 +15,6 @@ pub const Kevent = extern struct {...@@ -15,11 +15,6 @@ pub const Kevent = extern struct {
15 // TODO ext15 // TODO ext
16};16};
1717
18pub const pthread_attr_t = extern struct {
19 __size: [56]u8,
20 __align: c_long,
21};
22
23pub const dl_phdr_info = extern struct {18pub const dl_phdr_info = extern struct {
24 dlpi_addr: usize,19 dlpi_addr: usize,
25 dlpi_name: ?[*]const u8,20 dlpi_name: ?[*]const u8,
lib/std/os/bits/linux.zig-5
...@@ -1000,11 +1000,6 @@ pub const dl_phdr_info = extern struct {...@@ -1000,11 +1000,6 @@ pub const dl_phdr_info = extern struct {
1000 dlpi_phnum: u16,1000 dlpi_phnum: u16,
1001};1001};
10021002
1003pub const pthread_attr_t = extern struct {
1004 __size: [56]u8,
1005 __align: c_long,
1006};
1007
1008pub const CPU_SETSIZE = 128;1003pub const CPU_SETSIZE = 128;
1009pub const cpu_set_t = [CPU_SETSIZE / @sizeOf(usize)]usize;1004pub const cpu_set_t = [CPU_SETSIZE / @sizeOf(usize)]usize;
1010pub const cpu_count_t = @IntType(false, std.math.log2(CPU_SETSIZE * 8));1005pub const cpu_count_t = @IntType(false, std.math.log2(CPU_SETSIZE * 8));
lib/std/os/bits/netbsd.zig-6
...@@ -14,12 +14,6 @@ pub const Kevent = extern struct {...@@ -14,12 +14,6 @@ pub const Kevent = extern struct {
14 udata: usize,14 udata: usize,
15};15};
1616
17pub const pthread_attr_t = extern struct {
18 pta_magic: u32,
19 pta_flags: c_int,
20 pta_private: *c_void,
21};
22
23pub const dl_phdr_info = extern struct {17pub const dl_phdr_info = extern struct {
24 dlpi_addr: usize,18 dlpi_addr: usize,
25 dlpi_name: ?[*]const u8,19 dlpi_name: ?[*]const u8,
lib/std/parker.zig+32-174
...@@ -8,24 +8,9 @@ const linux = std.os.linux;...@@ -8,24 +8,9 @@ const linux = std.os.linux;
8const windows = std.os.windows;8const windows = std.os.windows;
99
10pub const ThreadParker = switch (builtin.os) {10pub const ThreadParker = switch (builtin.os) {
11 .macosx,
12 .tvos,
13 .ios,
14 .watchos,
15 .netbsd,
16 .openbsd,
17 .freebsd,
18 .kfreebsd,
19 .dragonfly,
20 .haiku,
21 .hermit,
22 .solaris,
23 .minix,
24 .fuchsia,
25 .emscripten => if (builtin.link_libc) PosixParker else SpinParker,
26 .linux => if (builtin.link_libc) PosixParker else LinuxParker,11 .linux => if (builtin.link_libc) PosixParker else LinuxParker,
27 .windows => WindowsParker,12 .windows => WindowsParker,
28 else => SpinParker,13 else => if (builtin.link_libc) PosixParker else SpinParker,
29};14};
3015
31const SpinParker = struct {16const SpinParker = struct {
...@@ -62,7 +47,7 @@ const LinuxParker = struct {...@@ -62,7 +47,7 @@ const LinuxParker = struct {
62 0, linux.EAGAIN => return,47 0, linux.EAGAIN => return,
63 linux.EINTR => continue,48 linux.EINTR => continue,
64 linux.EINVAL => unreachable,49 linux.EINVAL => unreachable,
65 else => unreachable,50 else => continue,
66 }51 }
67 }52 }
68 }53 }
...@@ -94,7 +79,7 @@ const WindowsParker = struct {...@@ -94,7 +79,7 @@ const WindowsParker = struct {
94 var spin = SpinLock.Backoff.init();79 var spin = SpinLock.Backoff.init();
95 const ev_handle = getEventHandle();80 const ev_handle = getEventHandle();
96 const key = @ptrCast(*const c_void, ptr);81 const key = @ptrCast(*const c_void, ptr);
97 82
98 while (@atomicLoad(u32, ptr, .Monotonic) == expected) {83 while (@atomicLoad(u32, ptr, .Monotonic) == expected) {
99 if (ev_handle) |handle| {84 if (ev_handle) |handle| {
100 _ = @atomicRmw(u32, &self.waiters, .Add, 1, .Release);85 _ = @atomicRmw(u32, &self.waiters, .Add, 1, .Release);
...@@ -121,191 +106,64 @@ const WindowsParker = struct {...@@ -121,191 +106,64 @@ const WindowsParker = struct {
121};106};
122107
123const PosixParker = struct {108const PosixParker = struct {
124 cond: pthread_cond_t,109 cond: c.pthread_cond_t,
125 mutex: pthread_mutex_t,110 mutex: c.pthread_mutex_t,
111
112 const c = std.c;
126113
127 pub fn init() PosixParker {114 pub fn init() PosixParker {
128 return PosixParker{115 return PosixParker{
129 .cond = PTHREAD_COND_INITIALIZER,116 .cond = c.PTHREAD_COND_INITIALIZER,
130 .mutex = PTHREAD_MUTEX_INITIALIZER,117 .mutex = c.PTHREAD_MUTEX_INITIALIZER,
131 };118 };
132 }119 }
133120
134 pub fn deinit(self: *PosixParker) void {121 pub fn deinit(self: *PosixParker) void {
135 // On dragonfly, the destroy functions return EINVAL if they were initialized statically.122 // On dragonfly, the destroy functions return EINVAL if they were initialized statically.
136 const retm = pthread_mutex_destroy(&self.mutex);123 const retm = c.pthread_mutex_destroy(&self.mutex);
137 assert(retm == 0 or retm == (if (builtin.os == .dragonfly) os.EINVAL else 0));124 assert(retm == 0 or retm == (if (builtin.os == .dragonfly) os.EINVAL else 0));
138 const retc = pthread_cond_destroy(&self.cond);125 const retc = c.pthread_cond_destroy(&self.cond);
139 assert(retc == 0 or retc == (if (builtin.os == .dragonfly) os.EINVAL else 0));126 assert(retc == 0 or retc == (if (builtin.os == .dragonfly) os.EINVAL else 0));
140 }127 }
141128
142 pub fn unpark(self: *PosixParker, ptr: *const u32) void {129 pub fn unpark(self: *PosixParker, ptr: *const u32) void {
143 assert(pthread_mutex_lock(&self.mutex) == 0);130 assert(c.pthread_mutex_lock(&self.mutex) == 0);
144 defer assert(pthread_mutex_unlock(&self.mutex) == 0);131 defer assert(c.pthread_mutex_unlock(&self.mutex) == 0);
145 assert(pthread_cond_signal(&self.cond) == 0);132 assert(c.pthread_cond_signal(&self.cond) == 0);
146 }133 }
147134
148 pub fn park(self: *PosixParker, ptr: *const u32, expected: u32) void {135 pub fn park(self: *PosixParker, ptr: *const u32, expected: u32) void {
149 assert(pthread_mutex_lock(&self.mutex) == 0);136 assert(c.pthread_mutex_lock(&self.mutex) == 0);
150 defer assert(pthread_mutex_unlock(&self.mutex) == 0);137 defer assert(c.pthread_mutex_unlock(&self.mutex) == 0);
151 while (@atomicLoad(u32, ptr, .Acquire) == expected)138 while (@atomicLoad(u32, ptr, .Acquire) == expected)
152 assert(pthread_cond_wait(&self.cond, &self.mutex) == 0);139 assert(c.pthread_cond_wait(&self.cond, &self.mutex) == 0);
153 }140 }
154
155 const PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{};
156 extern "c" fn pthread_mutex_lock(mutex: *pthread_mutex_t) c_int;
157 extern "c" fn pthread_mutex_unlock(mutex: *pthread_mutex_t) c_int;
158 extern "c" fn pthread_mutex_destroy(mutex: *pthread_mutex_t) c_int;
159
160 const PTHREAD_COND_INITIALIZER = pthread_cond_t{};
161 extern "c" fn pthread_cond_wait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t) c_int;
162 extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int;
163 extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c_int;
164
165 // https://github.com/rust-lang/libc
166 usingnamespace switch (builtin.os) {
167 .macosx, .tvos, .ios, .watchos => struct {
168 pub const pthread_mutex_t = extern struct {
169 __sig: c_long = 0x32AAABA7,
170 __opaque: [__PTHREAD_MUTEX_SIZE__]u8 = [_]u8{0} ** __PTHREAD_MUTEX_SIZE__,
171 };
172 pub const pthread_cond_t = extern struct {
173 __sig: c_long = 0x3CB0B1BB,
174 __opaque: [__PTHREAD_COND_SIZE__]u8 = [_]u8{0} ** __PTHREAD_COND_SIZE__,
175 };
176 const __PTHREAD_MUTEX_SIZE__ = if (@sizeOf(usize) == 8) 56 else 40;
177 const __PTHREAD_COND_SIZE__ = if (@sizeOf(usize) == 8) 40 else 24;
178 },
179 .netbsd => struct {
180 pub const pthread_mutex_t = extern struct {
181 ptm_magic: c_uint = 0x33330003,
182 ptm_errorcheck: padded_spin_t = 0,
183 ptm_unused: padded_spin_t = 0,
184 ptm_owner: usize = 0,
185 ptm_waiters: ?*u8 = null,
186 ptm_recursed: c_uint = 0,
187 ptm_spare2: ?*c_void = null,
188 };
189 pub const pthread_cond_t = extern struct {
190 ptc_magic: c_uint = 0x55550005,
191 ptc_lock: pthread_spin_t = 0,
192 ptc_waiters_first: ?*u8 = null,
193 ptc_waiters_last: ?*u8 = null,
194 ptc_mutex: ?*pthread_mutex_t = null,
195 ptc_private: ?*c_void = null,
196 };
197 const pthread_spin_t = if (builtin.arch == .arm or .arch == .powerpc) c_int else u8;
198 const padded_spin_t = switch (builtin.arch) {
199 .sparc, .sparcel, .sparcv9, .i386, .x86_64, .le64 => u32,
200 else => spin_t,
201 };
202 },
203 .openbsd, .freebsd, .kfreebsd, .dragonfly => struct {
204 pub const pthread_mutex_t = extern struct {
205 inner: ?*c_void = null,
206 };
207 pub const pthread_cond_t = extern struct {
208 inner: ?*c_void = null,
209 };
210 },
211 .haiku => struct {
212 pub const pthread_mutex_t = extern struct {
213 flags: u32 = 0,
214 lock: i32 = 0,
215 unused: i32 = -42,
216 owner: i32 = -1,
217 owner_count: i32 = 0,
218 };
219 pub const pthread_cond_t = extern struct {
220 flags: u32 = 0,
221 unused: i32 = -42,
222 mutex: ?*c_void = null,
223 waiter_count: i32 = 0,
224 lock: i32 = 0,
225 };
226 },
227 .hermit => struct {
228 pub const pthread_mutex_t = extern struct {
229 inner: usize = ~usize(0),
230 };
231 pub const pthread_cond_t = extern struct {
232 inner: usize = ~usize(0),
233 };
234 },
235 .solaris => struct {
236 pub const pthread_mutex_t = extern struct {
237 __pthread_mutex_flag1: u16 = 0,
238 __pthread_mutex_flag2: u8 = 0,
239 __pthread_mutex_ceiling: u8 = 0,
240 __pthread_mutex_type: u16 = 0,
241 __pthread_mutex_magic: u16 = 0x4d58,
242 __pthread_mutex_lock: u64 = 0,
243 __pthread_mutex_data: u64 = 0,
244 };
245 pub const pthread_cond_t = extern struct {
246 __pthread_cond_flag: u32 = 0,
247 __pthread_cond_type: u16 = 0,
248 __pthread_cond_magic: u16 = 0x4356,
249 __pthread_cond_data: u64 = 0,
250 };
251 },
252 .fuchsia, .minix, .linux => struct {
253 pub const pthread_mutex_t = extern struct {
254 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
255 };
256 pub const pthread_cond_t = extern struct {
257 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
258 };
259 const __SIZEOF_PTHREAD_COND_T = 48;
260 const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os == .fuchsia) 40 else switch (builtin.abi) {
261 .musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
262 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (builtin.arch) {
263 .aarch64 => 48,
264 .x86_64 => if (builtin.abi == .gnux32) 40 else 32,
265 .mips64, .powerpc64, .powerpc64le, .sparcv9 => 40,
266 else => if (@sizeOf(usize) == 8) 40 else 24,
267 },
268 else => unreachable,
269 };
270 },
271 .emscripten => struct {
272 pub const pthread_mutex_t = extern struct {
273 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(4) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
274 };
275 pub const pthread_cond_t = extern struct {
276 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
277 };
278 const __SIZEOF_PTHREAD_COND_T = 48;
279 const __SIZEOF_PTHREAD_MUTEX_T = 28;
280 },
281 else => unreachable,
282 };
283};141};
284142
285test "std.ThreadParker" {143test "std.ThreadParker" {
286 if (builtin.single_threaded)144 if (builtin.single_threaded)
287 return error.SkipZigTest;145 return error.SkipZigTest;
288 146
289 const Context = struct {147 const Context = struct {
290 parker: ThreadParker,148 parker: ThreadParker,
291 data: u32,149 data: u32,
292150
293 fn receiver(self: *@This()) void {151 fn receiver(self: *@This()) void {
294 self.parker.park(&self.data, 0); // receives 1152 self.parker.park(&self.data, 0); // receives 1
295 assert(@atomicRmw(u32, &self.data, .Xchg, 2, .SeqCst) == 1); // sends 2153 assert(@atomicRmw(u32, &self.data, .Xchg, 2, .SeqCst) == 1); // sends 2
296 self.parker.unpark(&self.data); // wakes up waiters on 2154 self.parker.unpark(&self.data); // wakes up waiters on 2
297 self.parker.park(&self.data, 2); // receives 3155 self.parker.park(&self.data, 2); // receives 3
298 assert(@atomicRmw(u32, &self.data, .Xchg, 4, .SeqCst) == 3); // sends 4156 assert(@atomicRmw(u32, &self.data, .Xchg, 4, .SeqCst) == 3); // sends 4
299 self.parker.unpark(&self.data); // wakes up waiters on 4157 self.parker.unpark(&self.data); // wakes up waiters on 4
300 }158 }
301159
302 fn sender(self: *@This()) void {160 fn sender(self: *@This()) void {
303 assert(@atomicRmw(u32, &self.data, .Xchg, 1, .SeqCst) == 0); // sends 1161 assert(@atomicRmw(u32, &self.data, .Xchg, 1, .SeqCst) == 0); // sends 1
304 self.parker.unpark(&self.data); // wakes up waiters on 1162 self.parker.unpark(&self.data); // wakes up waiters on 1
305 self.parker.park(&self.data, 1); // receives 2163 self.parker.park(&self.data, 1); // receives 2
306 assert(@atomicRmw(u32, &self.data, .Xchg, 3, .SeqCst) == 2); // sends 3164 assert(@atomicRmw(u32, &self.data, .Xchg, 3, .SeqCst) == 2); // sends 3
307 self.parker.unpark(&self.data); // wakes up waiters on 3165 self.parker.unpark(&self.data); // wakes up waiters on 3
308 self.parker.park(&self.data, 3); // receives 4166 self.parker.park(&self.data, 3); // receives 4
309 }167 }
310 };168 };
311169
...@@ -314,9 +172,9 @@ test "std.ThreadParker" {...@@ -314,9 +172,9 @@ test "std.ThreadParker" {
314 .data = 0,172 .data = 0,
315 };173 };
316 defer context.parker.deinit();174 defer context.parker.deinit();
317 175
318 var receiver = try std.Thread.spawn(&context, Context.receiver);176 var receiver = try std.Thread.spawn(&context, Context.receiver);
319 defer receiver.wait();177 defer receiver.wait();
320178
321 context.sender();179 context.sender();
322}
\ No newline at end of file
180}
lib/std/spinlock.zig+3-3
...@@ -31,8 +31,8 @@ pub const SpinLock = struct {...@@ -31,8 +31,8 @@ pub const SpinLock = struct {
31 var i = iterations;31 var i = iterations;
32 while (i != 0) : (i -= 1) {32 while (i != 0) : (i -= 1) {
33 switch (builtin.arch) {33 switch (builtin.arch) {
34 .i386, .x86_64 => asm volatile("pause"),34 .i386, .x86_64 => asm volatile ("pause"),
35 .arm, .aarch64 => asm volatile("yield"),35 .arm, .aarch64 => asm volatile ("yield"),
36 else => time.sleep(0),36 else => time.sleep(0),
37 }37 }
38 }38 }
...@@ -53,7 +53,7 @@ pub const SpinLock = struct {...@@ -53,7 +53,7 @@ pub const SpinLock = struct {
53 if (self.iteration < 20) {53 if (self.iteration < 20) {
54 SpinLock.yield(self.iteration);54 SpinLock.yield(self.iteration);
55 } else if (self.iteration < 24) {55 } else if (self.iteration < 24) {
56 os.sched_yield();56 os.sched_yield() catch time.sleep(1);
57 } else if (self.iteration < 26) {57 } else if (self.iteration < 26) {
58 time.sleep(1 * time.millisecond);58 time.sleep(1 * time.millisecond);
59 } else {59 } else {