Commit b535e86cc0

kprotty <kbutcher6200@gmail.com>
2019-11-07 22:32:20
move SpinLock definitions around
1 parent 92dac89
Changed files (5)
lib/std/os/linux.zig
@@ -954,6 +954,10 @@ pub fn fremovexattr(fd: usize, name: [*]const u8) usize {
     return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
 }
 
+pub fn sched_yield() usize {
+    return syscall0(SYS_sched_yield);
+}
+
 pub fn sched_getaffinity(pid: i32, size: usize, set: *cpu_set_t) usize {
     const rc = syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), size, @ptrToInt(set));
     if (@bitCast(isize, rc) < 0) return rc;
lib/std/c.zig
@@ -158,6 +158,7 @@ pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
 pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
 pub extern "c" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
 pub extern "c" fn pthread_self() pthread_t;
+pub extern "c" fn pthread_yield() c_int;
 pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
 
 pub extern "c" fn kqueue() c_int;
lib/std/mutex.zig
@@ -46,11 +46,11 @@ else struct {
     const Locked = 2;
 
     /// number of iterations to spin yielding the cpu
-    const SpinCpu = 4;
+    const SPIN_CPU = 4;
     /// number of iterations to perform in the cpu yield loop
-    const SpinCpuCount = 30;
+    const SPIN_CPU_COUNT = 30;
     /// number of iterations to spin yielding the thread
-    const SpinThread = 1;
+    const SPIN_THREAD = 1;
 
     pub fn init() Mutex {
         return Mutex{
@@ -86,20 +86,21 @@ else struct {
 
         while (true) {
             // try and acquire the lock using cpu spinning on failure
-            for (([SpinCpu]void)(undefined)) |_| {
+            var spin: usize = 0;
+            while (spin < SPIN_CPU) : (spin += 1) {
                 var value = @atomicLoad(u32, &self.state, .Monotonic);
                 while (value == Unlocked)
                     value = @cmpxchgWeak(u32, &self.state, Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };
-                for (([SpinCpuCount]void)(undefined)) |_|
-                    SpinLock.yieldCpu();
+                SpinLock.yield(SPIN_CPU_COUNT);
             }
 
             // try and acquire the lock using thread rescheduling on failure
-            for (([SpinThread]void)(undefined)) |_| {
+            spin = 0;
+            while (spin < SPIN_THREAD) : (spin += 1) {
                 var value = @atomicLoad(u32, &self.state, .Monotonic);
                 while (value == Unlocked)
                     value = @cmpxchgWeak(u32, &self.state, Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };
-                SpinLock.yieldThread();
+                std.os.yield();
             }
 
             // failed to acquire the lock, go to sleep until woken up by `Held.release()`
lib/std/os.zig
@@ -3169,3 +3169,13 @@ pub fn dn_expand(
     }
     return error.InvalidDnsPacket;
 }
+
+pub fn yield() void {
+    switch (builtin.os) {
+        .windows => _ = windows.kernel32.SwitchToThread(),
+        .linux => _ = assert(linux.sched_yield() == 0),
+        else => if (builtin.link_libc) {
+            assert(std.c.pthread_yield() == 0);
+        },
+    }
+}
lib/std/spinlock.zig
@@ -28,22 +28,17 @@ pub const SpinLock = struct {
         return Held{ .spinlock = self };
     }
 
-    pub fn yieldCpu() void {
-        switch (builtin.arch) {
-            .i386, .x86_64 => asm volatile("pause" ::: "memory"),
-            // .arm, .aarch64 => asm volatile("yield"),
-            //
-            // Causes CI to fail
-            // See: https://github.com/ziglang/zig/pull/3585#issuecomment-549962765
-            else => time.sleep(0),
-        }
-    }
-
-    pub fn yieldThread() void {
-        switch (builtin.os) {
-            .linux => assert(linux.syscall0(linux.SYS_sched_yield) == 0),
-            .windows => _ = windows.kernel32.SwitchToThread(),
-            else => time.sleep(1 * time.microsecond),
+    pub fn yield(iterations: usize) void {
+        var i = iterations;
+        while (i != 0) : (i -= 1) {
+            switch (builtin.arch) {
+                .i386, .x86_64 => asm volatile("pause" ::: "memory"),
+                // .arm, .aarch64 => asm volatile("yield"),
+                //
+                // Causes CI to fail
+                // See: https://github.com/ziglang/zig/pull/3585#issuecomment-549962765
+                else => time.sleep(0),
+            }
         }
     }
 
@@ -55,16 +50,14 @@ pub const SpinLock = struct {
             return @This(){ .iteration = 0 };
         }
 
-        /// Hybrid yielding from
+        /// Modified hybrid yielding from
         /// http://www.1024cores.net/home/lock-free-algorithms/tricks/spinning
         pub fn yield(self: *@This()) void {
             defer self.iteration +%= 1;
-            if (self.iteration < 10) {
-                yieldCpu();
-            } else if (self.iteration < 20) {
-                for (([30]void)(undefined)) |_| yieldCpu();
+            if (self.iteration < 20) {
+                SpinLock.yield(self.iteration);
             } else if (self.iteration < 24) {
-                yieldThread();
+                os.yield();
             } else if (self.iteration < 26) {
                 time.sleep(1 * time.millisecond);
             } else {