authorgravatar for kbutcher6200@gmail.comkprotty <kbutcher6200@gmail.com> 2019-11-07 15:32:20-06:00
committergravatar for kbutcher6200@gmail.comkprotty <kbutcher6200@gmail.com> 2019-11-07 15:32:20-06:00
logb535e86cc0e86e76471aebd731566ae140098a07
tree36e49cab7ff4c229228980f7c541abd4ad2997b2
parent92dac89d019fcd91aa043a116d6a6e166da8c4b2

move SpinLock definitions around


5 files changed, 39 insertions(+), 30 deletions(-)

lib/std/c.zig+1
...@@ -158,6 +158,7 @@ pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) c_int;...@@ -158,6 +158,7 @@ pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
158pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;158pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
159pub extern "c" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;159pub extern "c" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
160pub extern "c" fn pthread_self() pthread_t;160pub extern "c" fn pthread_self() pthread_t;
161pub extern "c" fn pthread_yield() c_int;
161pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;162pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
162163
163pub extern "c" fn kqueue() c_int;164pub extern "c" fn kqueue() c_int;
lib/std/mutex.zig+9-8
...@@ -46,11 +46,11 @@ else struct {...@@ -46,11 +46,11 @@ else struct {
46 const Locked = 2;46 const Locked = 2;
4747
48 /// number of iterations to spin yielding the cpu48 /// number of iterations to spin yielding the cpu
49 const SpinCpu = 4;49 const SPIN_CPU = 4;
50 /// number of iterations to perform in the cpu yield loop50 /// number of iterations to perform in the cpu yield loop
51 const SpinCpuCount = 30;51 const SPIN_CPU_COUNT = 30;
52 /// number of iterations to spin yielding the thread52 /// number of iterations to spin yielding the thread
53 const SpinThread = 1;53 const SPIN_THREAD = 1;
5454
55 pub fn init() Mutex {55 pub fn init() Mutex {
56 return Mutex{56 return Mutex{
...@@ -86,20 +86,21 @@ else struct {...@@ -86,20 +86,21 @@ else struct {
8686
87 while (true) {87 while (true) {
88 // try and acquire the lock using cpu spinning on failure88 // try and acquire the lock using cpu spinning on failure
89 for (([SpinCpu]void)(undefined)) |_| {89 var spin: usize = 0;
90 while (spin < SPIN_CPU) : (spin += 1) {
90 var value = @atomicLoad(u32, &self.state, .Monotonic);91 var value = @atomicLoad(u32, &self.state, .Monotonic);
91 while (value == Unlocked)92 while (value == Unlocked)
92 value = @cmpxchgWeak(u32, &self.state, Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };93 value = @cmpxchgWeak(u32, &self.state, Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };
93 for (([SpinCpuCount]void)(undefined)) |_|94 SpinLock.yield(SPIN_CPU_COUNT);
94 SpinLock.yieldCpu();
95 }95 }
9696
97 // try and acquire the lock using thread rescheduling on failure97 // try and acquire the lock using thread rescheduling on failure
98 for (([SpinThread]void)(undefined)) |_| {98 spin = 0;
99 while (spin < SPIN_THREAD) : (spin += 1) {
99 var value = @atomicLoad(u32, &self.state, .Monotonic);100 var value = @atomicLoad(u32, &self.state, .Monotonic);
100 while (value == Unlocked)101 while (value == Unlocked)
101 value = @cmpxchgWeak(u32, &self.state, Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };102 value = @cmpxchgWeak(u32, &self.state, Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };
102 SpinLock.yieldThread();103 std.os.yield();
103 }104 }
104105
105 // failed to acquire the lock, go to sleep until woken up by `Held.release()`106 // failed to acquire the lock, go to sleep until woken up by `Held.release()`
lib/std/os.zig+10
...@@ -3169,3 +3169,13 @@ pub fn dn_expand(...@@ -3169,3 +3169,13 @@ pub fn dn_expand(
3169 }3169 }
3170 return error.InvalidDnsPacket;3170 return error.InvalidDnsPacket;
3171}3171}
3172
3173pub fn yield() void {
3174 switch (builtin.os) {
3175 .windows => _ = windows.kernel32.SwitchToThread(),
3176 .linux => _ = assert(linux.sched_yield() == 0),
3177 else => if (builtin.link_libc) {
3178 assert(std.c.pthread_yield() == 0);
3179 },
3180 }
3181}
lib/std/os/linux.zig+4
...@@ -954,6 +954,10 @@ pub fn fremovexattr(fd: usize, name: [*]const u8) usize {...@@ -954,6 +954,10 @@ pub fn fremovexattr(fd: usize, name: [*]const u8) usize {
954 return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));954 return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
955}955}
956956
957pub fn sched_yield() usize {
958 return syscall0(SYS_sched_yield);
959}
960
957pub fn sched_getaffinity(pid: i32, size: usize, set: *cpu_set_t) usize {961pub fn sched_getaffinity(pid: i32, size: usize, set: *cpu_set_t) usize {
958 const rc = syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), size, @ptrToInt(set));962 const rc = syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), size, @ptrToInt(set));
959 if (@bitCast(isize, rc) < 0) return rc;963 if (@bitCast(isize, rc) < 0) return rc;
lib/std/spinlock.zig+15-22
...@@ -28,22 +28,17 @@ pub const SpinLock = struct {...@@ -28,22 +28,17 @@ pub const SpinLock = struct {
28 return Held{ .spinlock = self };28 return Held{ .spinlock = self };
29 }29 }
3030
31 pub fn yieldCpu() void {31 pub fn yield(iterations: usize) void {
32 switch (builtin.arch) {32 var i = iterations;
33 .i386, .x86_64 => asm volatile("pause" ::: "memory"),33 while (i != 0) : (i -= 1) {
34 // .arm, .aarch64 => asm volatile("yield"),34 switch (builtin.arch) {
35 //35 .i386, .x86_64 => asm volatile("pause" ::: "memory"),
36 // Causes CI to fail36 // .arm, .aarch64 => asm volatile("yield"),
37 // See: https://github.com/ziglang/zig/pull/3585#issuecomment-54996276537 //
38 else => time.sleep(0),38 // Causes CI to fail
39 }39 // See: https://github.com/ziglang/zig/pull/3585#issuecomment-549962765
40 }40 else => time.sleep(0),
4141 }
42 pub fn yieldThread() void {
43 switch (builtin.os) {
44 .linux => assert(linux.syscall0(linux.SYS_sched_yield) == 0),
45 .windows => _ = windows.kernel32.SwitchToThread(),
46 else => time.sleep(1 * time.microsecond),
47 }42 }
48 }43 }
4944
...@@ -55,16 +50,14 @@ pub const SpinLock = struct {...@@ -55,16 +50,14 @@ pub const SpinLock = struct {
55 return @This(){ .iteration = 0 };50 return @This(){ .iteration = 0 };
56 }51 }
5752
58 /// Hybrid yielding from53 /// Modified hybrid yielding from
59 /// http://www.1024cores.net/home/lock-free-algorithms/tricks/spinning54 /// http://www.1024cores.net/home/lock-free-algorithms/tricks/spinning
60 pub fn yield(self: *@This()) void {55 pub fn yield(self: *@This()) void {
61 defer self.iteration +%= 1;56 defer self.iteration +%= 1;
62 if (self.iteration < 10) {57 if (self.iteration < 20) {
63 yieldCpu();58 SpinLock.yield(self.iteration);
64 } else if (self.iteration < 20) {
65 for (([30]void)(undefined)) |_| yieldCpu();
66 } else if (self.iteration < 24) {59 } else if (self.iteration < 24) {
67 yieldThread();60 os.yield();
68 } else if (self.iteration < 26) {61 } else if (self.iteration < 26) {
69 time.sleep(1 * time.millisecond);62 time.sleep(1 * time.millisecond);
70 } else {63 } else {