aboutsummaryrefslogtreecommitdiff
path: root/lib/std/Thread/Futex.zig
diff options
context:
space:
mode:
authorDavid Rubin <87927264+Rexicon226@users.noreply.github.com>2024-10-04 15:21:27 -0700
committerGitHub <noreply@github.com>2024-10-04 22:21:27 +0000
commit043b1adb8dff184deaf9e145e6045b36b9bf733b (patch)
tree30c1e0e35c1e9b289ca1590431a59d9d44565520 /lib/std/Thread/Futex.zig
parent163d505e27bfbdb0aed30339fcc98c0f5f364e7a (diff)
downloadzig-043b1adb8dff184deaf9e145e6045b36b9bf733b.tar.gz
zig-043b1adb8dff184deaf9e145e6045b36b9bf733b.zip
remove `@fence` (#21585)
closes #11650
Diffstat (limited to 'lib/std/Thread/Futex.zig')
-rw-r--r--lib/std/Thread/Futex.zig21
1 files changed, 6 insertions, 15 deletions
diff --git a/lib/std/Thread/Futex.zig b/lib/std/Thread/Futex.zig
index fe22fa2011..da3fb916c6 100644
--- a/lib/std/Thread/Futex.zig
+++ b/lib/std/Thread/Futex.zig
@@ -794,9 +794,8 @@ const PosixImpl = struct {
// - T1: bumps pending waiters (was reordered after the ptr == expect check)
// - T1: goes to sleep and misses both the ptr change and T2's wake up
//
- // seq_cst as Acquire barrier to ensure the announcement happens before the ptr check below.
- // seq_cst as shared modification order to form a happens-before edge with the fence(.seq_cst)+load() in wake().
- var pending = bucket.pending.fetchAdd(1, .seq_cst);
+ // acquire barrier to ensure the announcement happens before the ptr check below.
+ var pending = bucket.pending.fetchAdd(1, .acquire);
assert(pending < std.math.maxInt(usize));
// If the wait gets cancelled, remove the pending count we previously added.
@@ -858,15 +857,8 @@ const PosixImpl = struct {
//
// What we really want here is a Release load, but that doesn't exist under the C11 memory model.
// We could instead do `bucket.pending.fetchAdd(0, Release) == 0` which achieves effectively the same thing,
- // but the RMW operation unconditionally marks the cache-line as modified for others causing unnecessary fetching/contention.
- //
- // Instead we opt to do a full-fence + load instead which avoids taking ownership of the cache-line.
- // fence(seq_cst) effectively converts the ptr update to seq_cst and the pending load to seq_cst: creating a Store-Load barrier.
- //
- // The pending count increment in wait() must also now use seq_cst for the update + this pending load
- // to be in the same modification order as our load isn't using release/acquire to guarantee it.
- bucket.pending.fence(.seq_cst);
- if (bucket.pending.load(.monotonic) == 0) {
+ // LLVM lowers the fetchAdd(0, .release) into an mfence+load which avoids gaining ownership of the cache-line.
+ if (bucket.pending.fetchAdd(0, .release) == 0) {
return;
}
@@ -979,15 +971,14 @@ test "broadcasting" {
fn wait(self: *@This()) !void {
// Decrement the counter.
// Release ensures stuff before this barrier.wait() happens before the last one.
- const count = self.count.fetchSub(1, .release);
+ // Acquire for the last counter ensures stuff before previous barrier.wait()s happened before it.
+ const count = self.count.fetchSub(1, .acq_rel);
try testing.expect(count <= num_threads);
try testing.expect(count > 0);
// First counter to reach zero wakes all other threads.
- // Acquire for the last counter ensures stuff before previous barrier.wait()s happened before it.
// Release on futex update ensures stuff before all barrier.wait()'s happens before they all return.
if (count - 1 == 0) {
- _ = self.count.load(.acquire); // TODO: could be fence(acquire) if not for TSAN
self.futex.store(1, .release);
Futex.wake(&self.futex, num_threads - 1);
return;