diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-01-06 17:36:06 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-01-06 17:36:06 -0700 |
| commit | 2f58efcc1f0a435846c0909fcde7b080ec4e5d3a (patch) | |
| tree | d3d0ef761b3c8055ae69e78816f14d739122da86 /lib/std | |
| parent | d7d905696c3e3b0e2b8c691317cb696be940b9a3 (diff) | |
| download | zig-2f58efcc1f0a435846c0909fcde7b080ec4e5d3a.tar.gz zig-2f58efcc1f0a435846c0909fcde7b080ec4e5d3a.zip | |
std.SpinLock: flatten and remove init/deinit
structs which are intended to be directly initialized and support static
initialization should not have init/deinit methods.
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/SpinLock.zig | 86 | ||||
| -rw-r--r-- | lib/std/spinlock.zig | 90 | ||||
| -rw-r--r-- | lib/std/std.zig | 2 |
3 files changed, 87 insertions, 91 deletions
diff --git a/lib/std/SpinLock.zig b/lib/std/SpinLock.zig new file mode 100644 index 0000000000..a16cfa930b --- /dev/null +++ b/lib/std/SpinLock.zig @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2021 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +//! A mutually exclusive lock that grinds the CPU rather than interacting with +//! the operating system. It does however yield to the OS scheduler while +//! spinning, when targeting an OS that supports it. +//! This struct can be initialized directly and statically initialized. The +//! default state is unlocked. + +state: State = State.Unlocked, + +const std = @import("std.zig"); +const builtin = @import("builtin"); +const SpinLock = @This(); + +const State = enum(u8) { + Unlocked, + Locked, +}; + +pub const Held = struct { + spinlock: *SpinLock, + + pub fn release(self: Held) void { + @atomicStore(State, &self.spinlock.state, .Unlocked, .Release); + } +}; + +pub fn tryAcquire(self: *SpinLock) ?Held { + return switch (@atomicRmw(State, &self.state, .Xchg, .Locked, .Acquire)) { + .Unlocked => Held{ .spinlock = self }, + .Locked => null, + }; +} + +pub fn acquire(self: *SpinLock) Held { + while (true) { + return self.tryAcquire() orelse { + yield(); + continue; + }; + } +} + +pub fn yield() void { + // On native windows, SwitchToThread is too expensive, + // and yielding for 380-410 iterations was found to be + // a nice sweet spot. Posix systems on the other hand, + // especially linux, perform better by yielding the thread. + switch (builtin.os.tag) { + .windows => loopHint(400), + else => std.os.sched_yield() catch loopHint(1), + } +} + +/// Hint to the cpu that execution is spinning +/// for the given amount of iterations. +pub fn loopHint(iterations: usize) void { + var i = iterations; + while (i != 0) : (i -= 1) { + switch (builtin.arch) { + // these instructions use a memory clobber as they + // flush the pipeline of any speculated reads/writes. + .i386, .x86_64 => asm volatile ("pause" + : + : + : "memory" + ), + .arm, .aarch64 => asm volatile ("yield" + : + : + : "memory" + ), + else => std.os.sched_yield() catch {}, + } + } +} + +test "basic usage" { + var lock: SpinLock = .{}; + + const held = lock.acquire(); + defer held.release(); +} diff --git a/lib/std/spinlock.zig b/lib/std/spinlock.zig deleted file mode 100644 index 8a9cbca837..0000000000 --- a/lib/std/spinlock.zig +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2015-2021 Zig Contributors -// This file is part of [zig](https://ziglang.org/), which is MIT licensed. -// The MIT license requires this copyright notice to be included in all copies -// and substantial portions of the software. -const std = @import("std.zig"); -const builtin = @import("builtin"); - -pub const SpinLock = struct { - state: State = .Unlocked, - - const State = enum(u8) { - Unlocked, - Locked, - }; - - pub const Held = struct { - spinlock: *SpinLock, - - pub fn release(self: Held) void { - @atomicStore(State, &self.spinlock.state, .Unlocked, .Release); - } - }; - - pub fn init() SpinLock { - return SpinLock{ .state = .Unlocked }; - } - - pub fn deinit(self: *SpinLock) void { - self.* = undefined; - } - - pub fn tryAcquire(self: *SpinLock) ?Held { - return switch (@atomicRmw(State, &self.state, .Xchg, .Locked, .Acquire)) { - .Unlocked => Held{ .spinlock = self }, - .Locked => null, - }; - } - - pub fn acquire(self: *SpinLock) Held { - while (true) { - return self.tryAcquire() orelse { - yield(); - continue; - }; - } - } - - pub fn yield() void { - // On native windows, SwitchToThread is too expensive, - // and yielding for 380-410 iterations was found to be - // a nice sweet spot. Posix systems on the other hand, - // especially linux, perform better by yielding the thread. - switch (builtin.os.tag) { - .windows => loopHint(400), - else => std.os.sched_yield() catch loopHint(1), - } - } - - /// Hint to the cpu that execution is spinning - /// for the given amount of iterations. - pub fn loopHint(iterations: usize) void { - var i = iterations; - while (i != 0) : (i -= 1) { - switch (builtin.arch) { - // these instructions use a memory clobber as they - // flush the pipeline of any speculated reads/writes. - .i386, .x86_64 => asm volatile ("pause" - : - : - : "memory" - ), - .arm, .aarch64 => asm volatile ("yield" - : - : - : "memory" - ), - else => std.os.sched_yield() catch {}, - } - } - } -}; - -test "spinlock" { - var lock = SpinLock.init(); - defer lock.deinit(); - - const held = lock.acquire(); - defer held.release(); -} diff --git a/lib/std/std.zig b/lib/std/std.zig index 091095bdb5..d736899a45 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -32,7 +32,7 @@ pub const Progress = @import("Progress.zig"); pub const ResetEvent = @import("ResetEvent.zig"); pub const SemanticVersion = @import("SemanticVersion.zig"); pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList; -pub const SpinLock = @import("spinlock.zig").SpinLock; +pub const SpinLock = @import("SpinLock.zig"); pub const StaticResetEvent = @import("StaticResetEvent.zig"); pub const StringHashMap = hash_map.StringHashMap; pub const StringHashMapUnmanaged = hash_map.StringHashMapUnmanaged; |
