Files
Zag/src/rtl/seqlock.zig
T
2026-03-24 08:06:24 -04:00

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);
}
};
}