mirror of
https://github.com/ziglang/zig.git
synced 2024-11-28 08:02:32 +00:00
4616af0ca4
* re-introduce `std.build.Target` which is distinct from `std.Target`. `std.build.Target` wraps `std.Target` so that it can be annotated as "the native target" or an explicitly specified target. * `std.Target.Os` is moved to `std.Target.Os.Tag`. The former is now a struct which has the tag as well as version range information. * `std.elf` gains some more ELF header constants. * `std.Target.parse` gains the ability to parse operating system version ranges as well as glibc version. * Added `std.Target.isGnuLibC()`. * self-hosted dynamic linker detection and glibc version detection. This also adds the improved logic using `/usr/bin/env` rather than invoking the system C compiler to find the dynamic linker when zig is statically linked. Related: #2084 Note: this `/usr/bin/env` code is work-in-progress. * `-target-glibc` CLI option is removed in favor of the new `-target` syntax. Example: `-target x86_64-linux-gnu.2.27` closes #1907
86 lines
2.3 KiB
Zig
86 lines
2.3 KiB
Zig
const std = @import("std.zig");
|
|
const builtin = @import("builtin");
|
|
|
|
pub const SpinLock = struct {
|
|
state: State,
|
|
|
|
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();
|
|
}
|