Commit 2f58efcc1f

Andrew Kelley <andrew@ziglang.org>
2021-01-07 01:36:06
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.
1 parent d7d9056
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();
+}
lib/std/spinlock.zig
@@ -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();
-}
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;
CMakeLists.txt
@@ -493,7 +493,7 @@ set(ZIG_STAGE2_SOURCES
     "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivmodti4.zig"
     "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/udivti3.zig"
     "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/umodti3.zig"
-    "${CMAKE_SOURCE_DIR}/lib/std/spinlock.zig"
+    "${CMAKE_SOURCE_DIR}/lib/std/SpinLock.zig"
     "${CMAKE_SOURCE_DIR}/lib/std/start.zig"
     "${CMAKE_SOURCE_DIR}/lib/std/std.zig"
     "${CMAKE_SOURCE_DIR}/lib/std/target.zig"