diff --git a/src/rtl/mem.zig b/src/rtl/mem.zig index fb44bc1..9e459c8 100644 --- a/src/rtl/mem.zig +++ b/src/rtl/mem.zig @@ -30,3 +30,8 @@ pub fn read_struct( return result; } + +/// Racily read a pointer on purpose. +pub fn racy_read(comptime T: type, ptr: *T) T { + return @atomicLoad(T, ptr, .unordered); +} diff --git a/src/rtl/seqlock.zig b/src/rtl/seqlock.zig index 5e2d8a2..a2e20f7 100644 --- a/src/rtl/seqlock.zig +++ b/src/rtl/seqlock.zig @@ -24,8 +24,8 @@ pub fn SeqLockType(comptime T: type) type { continue; } - // Relaxed load memcpy is needed here since data races are UB. - rtl.barrier.atomic_load_memcpy(&ret, &self.raw, .monotonic); + // Unordered load memcpy is needed here since data races are UB. + rtl.barrier.atomic_load_memcpy(&ret, &self.raw, .unordered); // Ensure the sequence read happens *after* the data is fully // loaded. @@ -49,8 +49,8 @@ pub fn SeqLockType(comptime T: type) type { // is incremented. rtl.barrier.fence(.release); - // Relaxed store memcpy is needed here since data races are UB. - rtl.barrier.atomic_store_memcpy(&self.raw, &data, .monotonic); + // Unordered store memcpy is needed here since data races are UB. + rtl.barrier.atomic_store_memcpy(&self.raw, &data, .unordered); self.sequence.store(seq + 2, .release); } diff --git a/src/sys/ex/work.zig b/src/sys/ex/work.zig index 87634b4..1f5b949 100644 --- a/src/sys/ex/work.zig +++ b/src/sys/ex/work.zig @@ -144,13 +144,12 @@ const Pool = struct { /// Return whether or not a new worker thread should be added to this pool. fn should_grow(self: *Pool) bool { - // NOTE: lockless racy check whether or not the queue is empty + // Lockless racy check whether or not the queue is empty // and its active count. // This is fine as this is best effort anyway and is a heuristic. - const is_empty = @atomicLoad( + const is_empty = rtl.mem.racy_read( *rtl.List.Entry, &self.queue.items.head.next, - .monotonic, ) == &self.queue.items.head; const active = self.queue.active.load(.monotonic); diff --git a/src/sys/kern/log_ring.zig b/src/sys/kern/log_ring.zig index 69ddac8..1d3105b 100644 --- a/src/sys/kern/log_ring.zig +++ b/src/sys/kern/log_ring.zig @@ -293,11 +293,7 @@ pub fn RingBufferType(data_size_bits: usize, avg_msg_bits: usize) type { // Loading the ID here is purposely racey because // we check if the descriptor is valid anyway. const id: Id = @truncate( - @atomicLoad( - usize, - @as(*usize, @ptrCast(&blk.id)), - .monotonic, - ), + rtl.mem.racy_read(usize, @ptrCast(&blk.id)), ); const res = self.read_desc(id); desc = res.desc; diff --git a/src/sys/kern/mutex.zig b/src/sys/kern/mutex.zig index 63db513..355d8d4 100644 --- a/src/sys/kern/mutex.zig +++ b/src/sys/kern/mutex.zig @@ -175,10 +175,9 @@ pub const Mutex = struct { var gas: usize = 0; - while (@atomicLoad( + while (rtl.mem.racy_read( ?*ke.Thread, cpu_curtd, - .unordered, ) == owner and gas < optimistic_spins) : (gas += 1) { if (m.state.load(.monotonic) == State.uncontended) { // Got released, retry acquiring it. diff --git a/src/sys/kern/sched.zig b/src/sys/kern/sched.zig index fd0505f..530e6a6 100644 --- a/src/sys/kern/sched.zig +++ b/src/sys/kern/sched.zig @@ -1779,11 +1779,7 @@ pub fn idle(_: ?*anyopaque) noreturn { while (true) { // Racy but only a hint anyway - const next = @atomicLoad( - ?*ke.Thread, - &cpu.next_thread, - .monotonic, - ); + const next = rtl.mem.racy_read(?*ke.Thread, &cpu.next_thread); if (cpu.load.load(.monotonic) != 0 or next != null) { std.atomic.spinLoopHint(); diff --git a/src/sys/mm/zone.zig b/src/sys/mm/zone.zig index 33105d9..71cbf0b 100644 --- a/src/sys/mm/zone.zig +++ b/src/sys/mm/zone.zig @@ -736,7 +736,7 @@ pub const Zone = struct { // Local depot is empty, rebalance with the zone depot. // Purposefully race against cpu_depot_size because locking is // tricky here, we may get a stale value but it is harmless. - const n = @atomicLoad(usize, &self.cpu_depot_size, .monotonic); + const n = rtl.mem.racy_read(usize, &self.cpu_depot_size); self.alloc_depot_rebalance(n, cpu); @@ -924,7 +924,7 @@ pub const Zone = struct { // Local depot is empty, rebalance with the zone depot. // Race explained in alloc. - const n = @atomicLoad(usize, &self.cpu_depot_size, .monotonic); + const n = rtl.mem.racy_read(usize, &self.cpu_depot_size); self.free_depot_rebalance(n, cpu);