authorgravatar for kbutcher6200@gmail.comkprotty <kbutcher6200@gmail.com> 2019-11-05 08:16:08-06:00
committergravatar for kbutcher6200@gmail.comkprotty <kbutcher6200@gmail.com> 2019-11-05 08:16:08-06:00
log0d4f4aad9e44043b329de0f2e556c3b61cdaafa9
tree0333bce0658e6d10c1bb796b93b1129379dbe727
parentbb6ad1a6c21694b4ea9340c552962b5ea60712e4

adaptive SpinLock


2 files changed, 39 insertions(+), 4 deletions(-)

lib/std/os/windows/kernel32.zig+2
...@@ -184,6 +184,8 @@ pub extern "kernel32" stdcallcc fn SetHandleInformation(hObject: HANDLE, dwMask:...@@ -184,6 +184,8 @@ pub extern "kernel32" stdcallcc fn SetHandleInformation(hObject: HANDLE, dwMask:
184184
185pub extern "kernel32" stdcallcc fn Sleep(dwMilliseconds: DWORD) void;185pub extern "kernel32" stdcallcc fn Sleep(dwMilliseconds: DWORD) void;
186186
187pub extern "kernel32" stdcallcc fn SwitchToThread() BOOL;
188
187pub extern "kernel32" stdcallcc fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) BOOL;189pub extern "kernel32" stdcallcc fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) BOOL;
188190
189pub extern "kernel32" stdcallcc fn TlsAlloc() DWORD;191pub extern "kernel32" stdcallcc fn TlsAlloc() DWORD;
lib/std/spinlock.zig+37-4
...@@ -1,8 +1,9 @@...@@ -1,8 +1,9 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const AtomicOrder = builtin.AtomicOrder;
4const AtomicRmwOp = builtin.AtomicRmwOp;
5const assert = std.debug.assert;3const assert = std.debug.assert;
4const time = std.time;
5const linux = std.os.linux;
6const windows = std.os.windows;
67
7pub const SpinLock = struct {8pub const SpinLock = struct {
8 lock: u8, // TODO use a bool or enum9 lock: u8, // TODO use a bool or enum
...@@ -11,7 +12,8 @@ pub const SpinLock = struct {...@@ -11,7 +12,8 @@ pub const SpinLock = struct {
11 spinlock: *SpinLock,12 spinlock: *SpinLock,
1213
13 pub fn release(self: Held) void {14 pub fn release(self: Held) void {
14 assert(@atomicRmw(u8, &self.spinlock.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);15 // TODO: @atomicStore() https://github.com/ziglang/zig/issues/2995
16 assert(@atomicRmw(u8, &self.spinlock.lock, .Xchg, 0, .Release) == 1);
15 }17 }
16 };18 };
1719
...@@ -19,10 +21,41 @@ pub const SpinLock = struct {...@@ -19,10 +21,41 @@ pub const SpinLock = struct {
19 return SpinLock{ .lock = 0 };21 return SpinLock{ .lock = 0 };
20 }22 }
2123
24 // Hybrid spinning from
25 // http://www.1024cores.net/home/lock-free-algorithms/tricks/spinning
22 pub fn acquire(self: *SpinLock) Held {26 pub fn acquire(self: *SpinLock) Held {
23 while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}27 var backoff: usize = 0;
28 while (@atomicRmw(u8, &self.lock, .Xchg, 1, .Acquire) != 0) : (backoff +%= 1) {
29 if (backoff < 10) {
30 yieldCpu();
31 } else if (backoff < 20) {
32 for (([30]void)(undefined)) |_| yieldCpu();
33 } else if (backoff < 24) {
34 yieldThread();
35 } else if (backoff < 26) {
36 time.sleep(1 * time.millisecond);
37 } else {
38 time.sleep(10 * time.millisecond);
39 }
40 }
24 return Held{ .spinlock = self };41 return Held{ .spinlock = self };
25 }42 }
43
44 fn yieldCpu() void {
45 switch (builtin.arch) {
46 .i386, .x86_64 => asm volatile("pause" ::: "memory"),
47 .arm, .aarch64 => asm volatile("yield"),
48 else => time.sleep(0),
49 }
50 }
51
52 fn yieldThread() void {
53 switch (builtin.os) {
54 .linux => assert(linux.syscall0(linux.SYS_sched_yield) == 0),
55 .windows => _ = windows.kernel32.SwitchToThread(),
56 else => time.sleep(1 * time.microsecond),
57 }
58 }
26};59};
2760
28test "spinlock" {61test "spinlock" {