| author | |
| committer | |
| log | b535e86cc0e86e76471aebd731566ae140098a07 |
| tree | 36e49cab7ff4c229228980f7c541abd4ad2997b2 |
| parent | 92dac89d019fcd91aa043a116d6a6e166da8c4b2 |
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; |
| 158 | pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int; | 158 | pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int; |
| 159 | pub extern "c" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int; | 159 | pub extern "c" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int; |
| 160 | pub extern "c" fn pthread_self() pthread_t; | 160 | pub extern "c" fn pthread_self() pthread_t; |
| 161 | pub extern "c" fn pthread_yield() c_int; | ||
| 161 | pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int; | 162 | pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int; |
| 162 | 163 | ||
| 163 | pub extern "c" fn kqueue() c_int; | 164 | pub 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; |
| 47 | 47 | ||
| 48 | /// number of iterations to spin yielding the cpu | 48 | /// 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 loop | 50 | /// 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 thread | 52 | /// number of iterations to spin yielding the thread |
| 53 | const SpinThread = 1; | 53 | const SPIN_THREAD = 1; |
| 54 | 54 | ||
| 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 { |
| 86 | 86 | ||
| 87 | while (true) { | 87 | while (true) { |
| 88 | // try and acquire the lock using cpu spinning on failure | 88 | // 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 | } |
| 96 | 96 | ||
| 97 | // try and acquire the lock using thread rescheduling on failure | 97 | // 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 | } |
| 104 | 105 | ||
| 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 | |||
| 3173 | pub 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 | } |
| 956 | 956 | ||
| 957 | pub fn sched_yield() usize { | ||
| 958 | return syscall0(SYS_sched_yield); | ||
| 959 | } | ||
| 960 | |||
| 957 | pub fn sched_getaffinity(pid: i32, size: usize, set: *cpu_set_t) usize { | 961 | pub 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 | } |
| 30 | 30 | ||
| 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 fail | 36 | // .arm, .aarch64 => asm volatile("yield"), |
| 37 | // See: https://github.com/ziglang/zig/pull/3585#issuecomment-549962765 | 37 | // |
| 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), |
| 41 | 41 | } | |
| 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 | } |
| 49 | 44 | ||
| ... | @@ -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 | } |
| 57 | 52 | ||
| 58 | /// Hybrid yielding from | 53 | /// Modified hybrid yielding from |
| 59 | /// http://www.1024cores.net/home/lock-free-algorithms/tricks/spinning | 54 | /// 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 { |