mirror of
https://github.com/rdmsr/zag.git
synced 2026-10-28 14:08:22 +00:00
55 lines
1.5 KiB
Zig
55 lines
1.5 KiB
Zig
const std = @import("std");
|
|
const rtl = @import("rtl");
|
|
|
|
pub fn SeqLock(comptime T: type) type {
|
|
return struct {
|
|
const Self = @This();
|
|
|
|
raw: T,
|
|
sequence: std.atomic.Value(usize),
|
|
|
|
pub fn init(val: T) Self {
|
|
return .{ .raw = val, .sequence = .init(0) };
|
|
}
|
|
|
|
pub fn load(self: *Self) T {
|
|
var ret: T = undefined;
|
|
|
|
while (true) {
|
|
const seq = self.sequence.load(.acquire);
|
|
if (seq & 1 != 0) {
|
|
std.atomic.spinLoopHint();
|
|
continue;
|
|
}
|
|
|
|
// Relaxed load memcpy is needed here since data races are UB.
|
|
rtl.barrier.atomic_load_memcpy(&ret, &self.raw, .monotonic);
|
|
|
|
// Ensure the sequence read happens *after* the data is fully loaded.
|
|
rtl.barrier.rmb();
|
|
|
|
if (self.sequence.load(.monotonic) == seq)
|
|
break;
|
|
|
|
std.atomic.spinLoopHint();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
pub fn store(self: *Self, data: T) void {
|
|
const seq = self.sequence.load(.monotonic);
|
|
|
|
self.sequence.store(seq + 1, .monotonic);
|
|
|
|
// Ensure the data write happens *after* the sequence is incremented.
|
|
rtl.barrier.wmb();
|
|
|
|
// Relaxed store memcpy is needed here since data races are UB.
|
|
rtl.barrier.atomic_store_memcpy(&self.raw, &data, .monotonic);
|
|
|
|
self.sequence.store(seq + 2, .release);
|
|
}
|
|
};
|
|
}
|