mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 22:35:24 +00:00
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.
This commit is contained in:
parent
d7d905696c
commit
2f58efcc1f
@ -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"
|
||||
|
||||
86
lib/std/SpinLock.zig
Normal file
86
lib/std/SpinLock.zig
Normal file
@ -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();
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user