aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-01-06 17:36:06 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-01-06 17:36:06 -0700
commit2f58efcc1f0a435846c0909fcde7b080ec4e5d3a (patch)
treed3d0ef761b3c8055ae69e78816f14d739122da86 /lib/std
parentd7d905696c3e3b0e2b8c691317cb696be940b9a3 (diff)
downloadzig-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.zig86
-rw-r--r--lib/std/spinlock.zig90
-rw-r--r--lib/std/std.zig2
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;