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
signature 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) {
88 .linux => @import("c/linux.zig"),
99 .windows => @import("c/windows.zig"),
1010 .macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"),
11 .freebsd => @import("c/freebsd.zig"),
11 .freebsd, .kfreebsd => @import("c/freebsd.zig"),
1212 .netbsd => @import("c/netbsd.zig"),
1313 .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"),
1421 else => struct {},
1522};
1623
......@@ -205,3 +212,16 @@ pub extern "c" fn dn_expand(
205212) c_int;
206213
207214pub 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;
112112/// argument buffer overflow
113113pub const EAI_OVERFLOW = 14;
114114pub 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 @@
11const std = @import("../std.zig");
22usingnamespace std.c;
3
43extern "c" threadlocal var errno: c_int;
54pub fn _errno() *c_int {
65 return &errno;
......@@ -12,3 +11,15 @@ pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize
1211
1312pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int;
1413pub 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
1010
1111pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int;
1212pub 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
7575pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;
7676
7777pub 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;
66
77pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
88pub 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)
3737 return Held{ .mutex = self };
3838 }
3939 }
40else struct {
41 state: u32, // TODO: make this an enum
42 parker: ThreadParker,
43
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 }
40else
41 struct {
42 state: u32, // TODO: make this an enum
43 parker: ThreadParker,
6144
62 pub fn deinit(self: *Mutex) void {
63 self.parker.deinit();
64 }
45 const Unlocked = 0;
46 const Sleeping = 1;
47 const Locked = 2;
6548
66 pub const Held = struct {
67 mutex: *Mutex,
49 /// number of iterations to spin yielding the cpu
50 const SPIN_CPU = 4;
6851
69 pub fn release(self: Held) void {
70 switch (@atomicRmw(u32, &self.mutex.state, .Xchg, Unlocked, .Release)) {
71 Locked => {},
72 Sleeping => self.mutex.parker.unpark(&self.mutex.state),
73 Unlocked => unreachable, // unlocking an unlocked mutex
74 else => unreachable, // should never be anything else
75 }
52 /// number of iterations to perform in the cpu yield loop
53 const SPIN_CPU_COUNT = 30;
54
55 /// number of iterations to spin yielding the thread
56 const SPIN_THREAD = 1;
57
58 pub fn init() Mutex {
59 return Mutex{
60 .state = Unlocked,
61 .parker = ThreadParker.init(),
62 };
7663 }
77 };
7864
79 pub fn acquire(self: *Mutex) Held {
80 // Try and speculatively grab the lock.
81 // If it fails, the state is either Locked or Sleeping
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 };
65 pub fn deinit(self: *Mutex) void {
66 self.parker.deinit();
67 }
8668
87 while (true) {
88 // try and acquire the lock using cpu spinning on failure
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 }
69 pub const Held = struct {
70 mutex: *Mutex,
9671
97 // try and acquire the lock using thread rescheduling on failure
98 spin = 0;
99 while (spin < SPIN_THREAD) : (spin += 1) {
100 var value = @atomicLoad(u32, &self.state, .Monotonic);
101 while (value == Unlocked)
102 value = @cmpxchgWeak(u32, &self.state, Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };
103 std.os.sched_yield();
72 pub fn release(self: Held) void {
73 switch (@atomicRmw(u32, &self.mutex.state, .Xchg, Unlocked, .Release)) {
74 Locked => {},
75 Sleeping => self.mutex.parker.unpark(&self.mutex.state),
76 Unlocked => unreachable, // unlocking an unlocked mutex
77 else => unreachable, // should never be anything else
78 }
10479 }
80 };
10581
106 // failed to acquire the lock, go to sleep until woken up by `Held.release()`
107 if (@atomicRmw(u32, &self.state, .Xchg, Sleeping, .Acquire) == Unlocked)
82 pub fn acquire(self: *Mutex) Held {
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)
10888 return Held{ .mutex = self };
109 state = Sleeping;
110 self.parker.park(&self.state, Sleeping);
89
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 }
111115 }
112 }
113};
116 };
114117
115118const TestContext = struct {
116119 mutex: *Mutex,
lib/std/os.zig+16-4
......@@ -3172,9 +3172,21 @@ pub fn dn_expand(
31723172 return error.InvalidDnsPacket;
31733173}
31743174
3175pub fn sched_yield() void {
3176 switch (builtin.os) {
3177 .windows => _ = windows.kernel32.SwitchToThread(),
3178 else => assert(system.sched_yield() == 0),
3175pub const SchedYieldError = error{
3176 /// The system is not configured to allow yielding
3177 SystemCannotYield,
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,
31793191 }
31803192}
lib/std/os/bits.zig-3
......@@ -14,9 +14,6 @@ pub usingnamespace switch (builtin.os) {
1414 else => struct {},
1515};
1616
17pub const pthread_t = *@OpaqueType();
18pub const FILE = @OpaqueType();
19
2017pub const iovec = extern struct {
2118 iov_base: [*]u8,
2219 iov_len: usize,
lib/std/os/bits/darwin.zig-5
......@@ -133,11 +133,6 @@ pub const dirent = extern struct {
133133 }
134134};
135135
136pub const pthread_attr_t = extern struct {
137 __sig: c_long,
138 __opaque: [56]u8,
139};
140
141136/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
142137pub const Kevent = extern struct {
143138 ident: usize,
lib/std/os/bits/dragonfly.zig+3-8
......@@ -360,11 +360,6 @@ pub const Kevent = extern struct {
360360 udata: usize,
361361};
362362
363pub const pthread_attr_t = extern struct { // copied from freebsd
364 __size: [56]u8,
365 __align: c_long,
366};
367
368363pub const EVFILT_FS = -10;
369364pub const EVFILT_USER = -9;
370365pub const EVFILT_EXCEPT = -8;
......@@ -515,13 +510,13 @@ pub const sigset_t = extern struct {
515510pub const sig_atomic_t = c_int;
516511pub const Sigaction = extern struct {
517512 __sigaction_u: extern union {
518 __sa_handler: ?extern fn(c_int) void,
519 __sa_sigaction: ?extern fn(c_int, [*c]siginfo_t, ?*c_void) void,
513 __sa_handler: ?extern fn (c_int) void,
514 __sa_sigaction: ?extern fn (c_int, [*c]siginfo_t, ?*c_void) void,
520515 },
521516 sa_flags: c_int,
522517 sa_mask: sigset_t,
523518};
524pub const sig_t = [*c]extern fn(c_int) void;
519pub const sig_t = [*c]extern fn (c_int) void;
525520
526521pub const sigvec = extern struct {
527522 sv_handler: [*c]__sighandler_t,
lib/std/os/bits/freebsd.zig-5
......@@ -15,11 +15,6 @@ pub const Kevent = extern struct {
1515 // TODO ext
1616};
1717
18pub const pthread_attr_t = extern struct {
19 __size: [56]u8,
20 __align: c_long,
21};
22
2318pub const dl_phdr_info = extern struct {
2419 dlpi_addr: usize,
2520 dlpi_name: ?[*]const u8,
lib/std/os/bits/linux.zig-5
......@@ -1000,11 +1000,6 @@ pub const dl_phdr_info = extern struct {
10001000 dlpi_phnum: u16,
10011001};
10021002
1003pub const pthread_attr_t = extern struct {
1004 __size: [56]u8,
1005 __align: c_long,
1006};
1007
10081003pub const CPU_SETSIZE = 128;
10091004pub const cpu_set_t = [CPU_SETSIZE / @sizeOf(usize)]usize;
10101005pub 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 {
1414 udata: usize,
1515};
1616
17pub const pthread_attr_t = extern struct {
18 pta_magic: u32,
19 pta_flags: c_int,
20 pta_private: *c_void,
21};
22
2317pub const dl_phdr_info = extern struct {
2418 dlpi_addr: usize,
2519 dlpi_name: ?[*]const u8,
lib/std/parker.zig+32-174
......@@ -8,24 +8,9 @@ const linux = std.os.linux;
88const windows = std.os.windows;
99
1010pub 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,
2611 .linux => if (builtin.link_libc) PosixParker else LinuxParker,
2712 .windows => WindowsParker,
28 else => SpinParker,
13 else => if (builtin.link_libc) PosixParker else SpinParker,
2914};
3015
3116const SpinParker = struct {
......@@ -62,7 +47,7 @@ const LinuxParker = struct {
6247 0, linux.EAGAIN => return,
6348 linux.EINTR => continue,
6449 linux.EINVAL => unreachable,
65 else => unreachable,
50 else => continue,
6651 }
6752 }
6853 }
......@@ -94,7 +79,7 @@ const WindowsParker = struct {
9479 var spin = SpinLock.Backoff.init();
9580 const ev_handle = getEventHandle();
9681 const key = @ptrCast(*const c_void, ptr);
97
82
9883 while (@atomicLoad(u32, ptr, .Monotonic) == expected) {
9984 if (ev_handle) |handle| {
10085 _ = @atomicRmw(u32, &self.waiters, .Add, 1, .Release);
......@@ -121,191 +106,64 @@ const WindowsParker = struct {
121106};
122107
123108const PosixParker = struct {
124 cond: pthread_cond_t,
125 mutex: pthread_mutex_t,
109 cond: c.pthread_cond_t,
110 mutex: c.pthread_mutex_t,
111
112 const c = std.c;
126113
127114 pub fn init() PosixParker {
128115 return PosixParker{
129 .cond = PTHREAD_COND_INITIALIZER,
130 .mutex = PTHREAD_MUTEX_INITIALIZER,
116 .cond = c.PTHREAD_COND_INITIALIZER,
117 .mutex = c.PTHREAD_MUTEX_INITIALIZER,
131118 };
132119 }
133120
134121 pub fn deinit(self: *PosixParker) void {
135122 // 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);
137124 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);
139126 assert(retc == 0 or retc == (if (builtin.os == .dragonfly) os.EINVAL else 0));
140127 }
141128
142129 pub fn unpark(self: *PosixParker, ptr: *const u32) void {
143 assert(pthread_mutex_lock(&self.mutex) == 0);
144 defer assert(pthread_mutex_unlock(&self.mutex) == 0);
145 assert(pthread_cond_signal(&self.cond) == 0);
130 assert(c.pthread_mutex_lock(&self.mutex) == 0);
131 defer assert(c.pthread_mutex_unlock(&self.mutex) == 0);
132 assert(c.pthread_cond_signal(&self.cond) == 0);
146133 }
147134
148135 pub fn park(self: *PosixParker, ptr: *const u32, expected: u32) void {
149 assert(pthread_mutex_lock(&self.mutex) == 0);
150 defer assert(pthread_mutex_unlock(&self.mutex) == 0);
136 assert(c.pthread_mutex_lock(&self.mutex) == 0);
137 defer assert(c.pthread_mutex_unlock(&self.mutex) == 0);
151138 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);
153140 }
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 };
283141};
284142
285143test "std.ThreadParker" {
286144 if (builtin.single_threaded)
287145 return error.SkipZigTest;
288
146
289147 const Context = struct {
290148 parker: ThreadParker,
291149 data: u32,
292150
293151 fn receiver(self: *@This()) void {
294 self.parker.park(&self.data, 0); // receives 1
295 assert(@atomicRmw(u32, &self.data, .Xchg, 2, .SeqCst) == 1); // sends 2
296 self.parker.unpark(&self.data); // wakes up waiters on 2
297 self.parker.park(&self.data, 2); // receives 3
298 assert(@atomicRmw(u32, &self.data, .Xchg, 4, .SeqCst) == 3); // sends 4
299 self.parker.unpark(&self.data); // wakes up waiters on 4
152 self.parker.park(&self.data, 0); // receives 1
153 assert(@atomicRmw(u32, &self.data, .Xchg, 2, .SeqCst) == 1); // sends 2
154 self.parker.unpark(&self.data); // wakes up waiters on 2
155 self.parker.park(&self.data, 2); // receives 3
156 assert(@atomicRmw(u32, &self.data, .Xchg, 4, .SeqCst) == 3); // sends 4
157 self.parker.unpark(&self.data); // wakes up waiters on 4
300158 }
301159
302160 fn sender(self: *@This()) void {
303 assert(@atomicRmw(u32, &self.data, .Xchg, 1, .SeqCst) == 0); // sends 1
304 self.parker.unpark(&self.data); // wakes up waiters on 1
305 self.parker.park(&self.data, 1); // receives 2
306 assert(@atomicRmw(u32, &self.data, .Xchg, 3, .SeqCst) == 2); // sends 3
307 self.parker.unpark(&self.data); // wakes up waiters on 3
308 self.parker.park(&self.data, 3); // receives 4
161 assert(@atomicRmw(u32, &self.data, .Xchg, 1, .SeqCst) == 0); // sends 1
162 self.parker.unpark(&self.data); // wakes up waiters on 1
163 self.parker.park(&self.data, 1); // receives 2
164 assert(@atomicRmw(u32, &self.data, .Xchg, 3, .SeqCst) == 2); // sends 3
165 self.parker.unpark(&self.data); // wakes up waiters on 3
166 self.parker.park(&self.data, 3); // receives 4
309167 }
310168 };
311169
......@@ -314,9 +172,9 @@ test "std.ThreadParker" {
314172 .data = 0,
315173 };
316174 defer context.parker.deinit();
317
175
318176 var receiver = try std.Thread.spawn(&context, Context.receiver);
319177 defer receiver.wait();
320178
321179 context.sender();
322}
\ No newline at end of file
180}
lib/std/spinlock.zig+3-3
......@@ -31,8 +31,8 @@ pub const SpinLock = struct {
3131 var i = iterations;
3232 while (i != 0) : (i -= 1) {
3333 switch (builtin.arch) {
34 .i386, .x86_64 => asm volatile("pause"),
35 .arm, .aarch64 => asm volatile("yield"),
34 .i386, .x86_64 => asm volatile ("pause"),
35 .arm, .aarch64 => asm volatile ("yield"),
3636 else => time.sleep(0),
3737 }
3838 }
......@@ -53,7 +53,7 @@ pub const SpinLock = struct {
5353 if (self.iteration < 20) {
5454 SpinLock.yield(self.iteration);
5555 } else if (self.iteration < 24) {
56 os.sched_yield();
56 os.sched_yield() catch time.sleep(1);
5757 } else if (self.iteration < 26) {
5858 time.sleep(1 * time.millisecond);
5959 } else {