authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-22 14:27:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-22 14:27:49-07:00
log1fa2e911d923d9f843f1f179db28ab815d4a105d
tree7184e51747cbfeb6d42b5eb1a849423a34f9a1ec
parente4977f3e89fcc164a4d02cd38eb066cfe1a1124f

std.atomic: remove some APIs

* remove `std.atomic.Ordering` - it is provided by the language with `std.builtin.AtomicOrder`. * remove `std.atomic.fence` - it is provided by the language with `@fence`. * remove `std.atomic.compilerFence` - if this is desired, it should be a language feature, not a standard library function with inline asm.

2 files changed, 43 insertions(+), 71 deletions(-)

lib/std/atomic.zig+4-32
...@@ -1,8 +1,6 @@...@@ -1,8 +1,6 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub const Ordering = std.builtin.AtomicOrder;
5
6pub const Stack = @import("atomic/stack.zig").Stack;4pub const Stack = @import("atomic/stack.zig").Stack;
7pub const Queue = @import("atomic/queue.zig").Queue;5pub const Queue = @import("atomic/queue.zig").Queue;
8pub const Atomic = @import("atomic/Atomic.zig").Atomic;6pub const Atomic = @import("atomic/Atomic.zig").Atomic;
...@@ -13,31 +11,6 @@ test {...@@ -13,31 +11,6 @@ test {
13 _ = @import("atomic/Atomic.zig");11 _ = @import("atomic/Atomic.zig");
14}12}
1513
16pub inline fn fence(comptime ordering: Ordering) void {
17 switch (ordering) {
18 .Acquire, .Release, .AcqRel, .SeqCst => {
19 @fence(ordering);
20 },
21 else => {
22 @compileLog(ordering, " only applies to a given memory location");
23 },
24 }
25}
26
27pub inline fn compilerFence(comptime ordering: Ordering) void {
28 switch (ordering) {
29 .Acquire, .Release, .AcqRel, .SeqCst => asm volatile ("" ::: "memory"),
30 else => @compileLog(ordering, " only applies to a given memory location"),
31 }
32}
33
34test "fence/compilerFence" {
35 inline for (.{ .Acquire, .Release, .AcqRel, .SeqCst }) |ordering| {
36 compilerFence(ordering);
37 fence(ordering);
38 }
39}
40
41/// Signals to the processor that the caller is inside a busy-wait spin-loop.14/// Signals to the processor that the caller is inside a busy-wait spin-loop.
42pub inline fn spinLoopHint() void {15pub inline fn spinLoopHint() void {
43 switch (builtin.target.cpu.arch) {16 switch (builtin.target.cpu.arch) {
...@@ -74,9 +47,8 @@ pub inline fn spinLoopHint() void {...@@ -74,9 +47,8 @@ pub inline fn spinLoopHint() void {
74 }47 }
75}48}
7649
77test "spinLoopHint" {50test spinLoopHint {
78 var i: usize = 10;51 for (0..10) |_| {
79 while (i > 0) : (i -= 1) {
80 spinLoopHint();52 spinLoopHint();
81 }53 }
82}54}
...@@ -85,8 +57,8 @@ test "spinLoopHint" {...@@ -85,8 +57,8 @@ test "spinLoopHint" {
85/// Add this much padding or align to this boundary to avoid atomically-updated57/// Add this much padding or align to this boundary to avoid atomically-updated
86/// memory from forcing cache invalidations on near, but non-atomic, memory.58/// memory from forcing cache invalidations on near, but non-atomic, memory.
87///59///
88// https://en.wikipedia.org/wiki/False_sharing60/// https://en.wikipedia.org/wiki/False_sharing
89// https://github.com/golang/go/search?q=CacheLinePadSize61/// https://github.com/golang/go/search?q=CacheLinePadSize
90pub const cache_line = switch (builtin.cpu.arch) {62pub const cache_line = switch (builtin.cpu.arch) {
91 // x86_64: Starting from Intel's Sandy Bridge, the spatial prefetcher pulls in pairs of 64-byte cache lines at a time.63 // x86_64: Starting from Intel's Sandy Bridge, the spatial prefetcher pulls in pairs of 64-byte cache lines at a time.
92 // - https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf64 // - https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf
lib/std/atomic/Atomic.zig+39-39
...@@ -2,7 +2,7 @@ const std = @import("../std.zig");...@@ -2,7 +2,7 @@ const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4const testing = std.testing;4const testing = std.testing;
5const Ordering = std.atomic.Ordering;5const AtomicOrder = std.builtin.AtomicOrder;
66
7pub fn Atomic(comptime T: type) type {7pub fn Atomic(comptime T: type) type {
8 return extern struct {8 return extern struct {
...@@ -38,7 +38,7 @@ pub fn Atomic(comptime T: type) type {...@@ -38,7 +38,7 @@ pub fn Atomic(comptime T: type) type {
38 /// }38 /// }
39 /// };39 /// };
40 /// ```40 /// ```
41 pub inline fn fence(self: *Self, comptime ordering: Ordering) void {41 pub inline fn fence(self: *Self, comptime ordering: AtomicOrder) void {
42 // LLVM's ThreadSanitizer doesn't support the normal fences so we specialize for it.42 // LLVM's ThreadSanitizer doesn't support the normal fences so we specialize for it.
43 if (builtin.sanitize_thread) {43 if (builtin.sanitize_thread) {
44 const tsan = struct {44 const tsan = struct {
...@@ -58,7 +58,14 @@ pub fn Atomic(comptime T: type) type {...@@ -58,7 +58,14 @@ pub fn Atomic(comptime T: type) type {
58 };58 };
59 }59 }
6060
61 return std.atomic.fence(ordering);61 return @fence(ordering);
62 }
63
64 test fence {
65 inline for (.{ .Acquire, .Release, .AcqRel, .SeqCst }) |ordering| {
66 var x = Atomic(usize).init(0);
67 x.fence(ordering);
68 }
62 }69 }
6370
64 /// Non-atomically load from the atomic value without synchronization.71 /// Non-atomically load from the atomic value without synchronization.
...@@ -73,23 +80,23 @@ pub fn Atomic(comptime T: type) type {...@@ -73,23 +80,23 @@ pub fn Atomic(comptime T: type) type {
73 self.value = value;80 self.value = value;
74 }81 }
7582
76 pub inline fn load(self: *const Self, comptime ordering: Ordering) T {83 pub inline fn load(self: *const Self, comptime ordering: AtomicOrder) T {
77 return switch (ordering) {84 return switch (ordering) {
78 .AcqRel => @compileError(@tagName(ordering) ++ " implies " ++ @tagName(Ordering.Release) ++ " which is only allowed on atomic stores"),85 .AcqRel => @compileError(@tagName(ordering) ++ " implies " ++ @tagName(AtomicOrder.Release) ++ " which is only allowed on atomic stores"),
79 .Release => @compileError(@tagName(ordering) ++ " is only allowed on atomic stores"),86 .Release => @compileError(@tagName(ordering) ++ " is only allowed on atomic stores"),
80 else => @atomicLoad(T, &self.value, ordering),87 else => @atomicLoad(T, &self.value, ordering),
81 };88 };
82 }89 }
8390
84 pub inline fn store(self: *Self, value: T, comptime ordering: Ordering) void {91 pub inline fn store(self: *Self, value: T, comptime ordering: AtomicOrder) void {
85 switch (ordering) {92 switch (ordering) {
86 .AcqRel => @compileError(@tagName(ordering) ++ " implies " ++ @tagName(Ordering.Acquire) ++ " which is only allowed on atomic loads"),93 .AcqRel => @compileError(@tagName(ordering) ++ " implies " ++ @tagName(AtomicOrder.Acquire) ++ " which is only allowed on atomic loads"),
87 .Acquire => @compileError(@tagName(ordering) ++ " is only allowed on atomic loads"),94 .Acquire => @compileError(@tagName(ordering) ++ " is only allowed on atomic loads"),
88 else => @atomicStore(T, &self.value, value, ordering),95 else => @atomicStore(T, &self.value, value, ordering),
89 }96 }
90 }97 }
9198
92 pub inline fn swap(self: *Self, value: T, comptime ordering: Ordering) T {99 pub inline fn swap(self: *Self, value: T, comptime ordering: AtomicOrder) T {
93 return self.rmw(.Xchg, value, ordering);100 return self.rmw(.Xchg, value, ordering);
94 }101 }
95102
...@@ -97,8 +104,8 @@ pub fn Atomic(comptime T: type) type {...@@ -97,8 +104,8 @@ pub fn Atomic(comptime T: type) type {
97 self: *Self,104 self: *Self,
98 compare: T,105 compare: T,
99 exchange: T,106 exchange: T,
100 comptime success: Ordering,107 comptime success: AtomicOrder,
101 comptime failure: Ordering,108 comptime failure: AtomicOrder,
102 ) ?T {109 ) ?T {
103 return self.cmpxchg(true, compare, exchange, success, failure);110 return self.cmpxchg(true, compare, exchange, success, failure);
104 }111 }
...@@ -107,8 +114,8 @@ pub fn Atomic(comptime T: type) type {...@@ -107,8 +114,8 @@ pub fn Atomic(comptime T: type) type {
107 self: *Self,114 self: *Self,
108 compare: T,115 compare: T,
109 exchange: T,116 exchange: T,
110 comptime success: Ordering,117 comptime success: AtomicOrder,
111 comptime failure: Ordering,118 comptime failure: AtomicOrder,
112 ) ?T {119 ) ?T {
113 return self.cmpxchg(false, compare, exchange, success, failure);120 return self.cmpxchg(false, compare, exchange, success, failure);
114 }121 }
...@@ -118,16 +125,16 @@ pub fn Atomic(comptime T: type) type {...@@ -118,16 +125,16 @@ pub fn Atomic(comptime T: type) type {
118 comptime is_strong: bool,125 comptime is_strong: bool,
119 compare: T,126 compare: T,
120 exchange: T,127 exchange: T,
121 comptime success: Ordering,128 comptime success: AtomicOrder,
122 comptime failure: Ordering,129 comptime failure: AtomicOrder,
123 ) ?T {130 ) ?T {
124 if (success == .Unordered or failure == .Unordered) {131 if (success == .Unordered or failure == .Unordered) {
125 @compileError(@tagName(Ordering.Unordered) ++ " is only allowed on atomic loads and stores");132 @compileError(@tagName(AtomicOrder.Unordered) ++ " is only allowed on atomic loads and stores");
126 }133 }
127134
128 const success_is_stronger = switch (failure) {135 const success_is_stronger = switch (failure) {
129 .SeqCst => success == .SeqCst,136 .SeqCst => success == .SeqCst,
130 .AcqRel => @compileError(@tagName(failure) ++ " implies " ++ @tagName(Ordering.Release) ++ " which is only allowed on success"),137 .AcqRel => @compileError(@tagName(failure) ++ " implies " ++ @tagName(AtomicOrder.Release) ++ " which is only allowed on success"),
131 .Acquire => success == .SeqCst or success == .AcqRel or success == .Acquire,138 .Acquire => success == .SeqCst or success == .AcqRel or success == .Acquire,
132 .Release => @compileError(@tagName(failure) ++ " is only allowed on success"),139 .Release => @compileError(@tagName(failure) ++ " is only allowed on success"),
133 .Monotonic => true,140 .Monotonic => true,
...@@ -148,40 +155,40 @@ pub fn Atomic(comptime T: type) type {...@@ -148,40 +155,40 @@ pub fn Atomic(comptime T: type) type {
148 self: *Self,155 self: *Self,
149 comptime op: std.builtin.AtomicRmwOp,156 comptime op: std.builtin.AtomicRmwOp,
150 value: T,157 value: T,
151 comptime ordering: Ordering,158 comptime ordering: AtomicOrder,
152 ) T {159 ) T {
153 return @atomicRmw(T, &self.value, op, value, ordering);160 return @atomicRmw(T, &self.value, op, value, ordering);
154 }161 }
155162
156 pub inline fn fetchAdd(self: *Self, value: T, comptime ordering: Ordering) T {163 pub inline fn fetchAdd(self: *Self, value: T, comptime ordering: AtomicOrder) T {
157 return self.rmw(.Add, value, ordering);164 return self.rmw(.Add, value, ordering);
158 }165 }
159166
160 pub inline fn fetchSub(self: *Self, value: T, comptime ordering: Ordering) T {167 pub inline fn fetchSub(self: *Self, value: T, comptime ordering: AtomicOrder) T {
161 return self.rmw(.Sub, value, ordering);168 return self.rmw(.Sub, value, ordering);
162 }169 }
163170
164 pub inline fn fetchMin(self: *Self, value: T, comptime ordering: Ordering) T {171 pub inline fn fetchMin(self: *Self, value: T, comptime ordering: AtomicOrder) T {
165 return self.rmw(.Min, value, ordering);172 return self.rmw(.Min, value, ordering);
166 }173 }
167174
168 pub inline fn fetchMax(self: *Self, value: T, comptime ordering: Ordering) T {175 pub inline fn fetchMax(self: *Self, value: T, comptime ordering: AtomicOrder) T {
169 return self.rmw(.Max, value, ordering);176 return self.rmw(.Max, value, ordering);
170 }177 }
171178
172 pub inline fn fetchAnd(self: *Self, value: T, comptime ordering: Ordering) T {179 pub inline fn fetchAnd(self: *Self, value: T, comptime ordering: AtomicOrder) T {
173 return self.rmw(.And, value, ordering);180 return self.rmw(.And, value, ordering);
174 }181 }
175182
176 pub inline fn fetchNand(self: *Self, value: T, comptime ordering: Ordering) T {183 pub inline fn fetchNand(self: *Self, value: T, comptime ordering: AtomicOrder) T {
177 return self.rmw(.Nand, value, ordering);184 return self.rmw(.Nand, value, ordering);
178 }185 }
179186
180 pub inline fn fetchOr(self: *Self, value: T, comptime ordering: Ordering) T {187 pub inline fn fetchOr(self: *Self, value: T, comptime ordering: AtomicOrder) T {
181 return self.rmw(.Or, value, ordering);188 return self.rmw(.Or, value, ordering);
182 }189 }
183190
184 pub inline fn fetchXor(self: *Self, value: T, comptime ordering: Ordering) T {191 pub inline fn fetchXor(self: *Self, value: T, comptime ordering: AtomicOrder) T {
185 return self.rmw(.Xor, value, ordering);192 return self.rmw(.Xor, value, ordering);
186 }193 }
187194
...@@ -192,19 +199,19 @@ pub fn Atomic(comptime T: type) type {...@@ -192,19 +199,19 @@ pub fn Atomic(comptime T: type) type {
192 Toggle,199 Toggle,
193 };200 };
194201
195 pub inline fn bitSet(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {202 pub inline fn bitSet(self: *Self, bit: Bit, comptime ordering: AtomicOrder) u1 {
196 return bitRmw(self, .Set, bit, ordering);203 return bitRmw(self, .Set, bit, ordering);
197 }204 }
198205
199 pub inline fn bitReset(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {206 pub inline fn bitReset(self: *Self, bit: Bit, comptime ordering: AtomicOrder) u1 {
200 return bitRmw(self, .Reset, bit, ordering);207 return bitRmw(self, .Reset, bit, ordering);
201 }208 }
202209
203 pub inline fn bitToggle(self: *Self, bit: Bit, comptime ordering: Ordering) u1 {210 pub inline fn bitToggle(self: *Self, bit: Bit, comptime ordering: AtomicOrder) u1 {
204 return bitRmw(self, .Toggle, bit, ordering);211 return bitRmw(self, .Toggle, bit, ordering);
205 }212 }
206213
207 inline fn bitRmw(self: *Self, comptime op: BitRmwOp, bit: Bit, comptime ordering: Ordering) u1 {214 inline fn bitRmw(self: *Self, comptime op: BitRmwOp, bit: Bit, comptime ordering: AtomicOrder) u1 {
208 // x86 supports dedicated bitwise instructions215 // x86 supports dedicated bitwise instructions
209 if (comptime builtin.target.cpu.arch.isX86() and @sizeOf(T) >= 2 and @sizeOf(T) <= 8) {216 if (comptime builtin.target.cpu.arch.isX86() and @sizeOf(T) >= 2 and @sizeOf(T) <= 8) {
210 // TODO: this causes std lib test failures when enabled217 // TODO: this causes std lib test failures when enabled
...@@ -223,7 +230,7 @@ pub fn Atomic(comptime T: type) type {...@@ -223,7 +230,7 @@ pub fn Atomic(comptime T: type) type {
223 return @intFromBool(value & mask != 0);230 return @intFromBool(value & mask != 0);
224 }231 }
225232
226 inline fn x86BitRmw(self: *Self, comptime op: BitRmwOp, bit: Bit, comptime ordering: Ordering) u1 {233 inline fn x86BitRmw(self: *Self, comptime op: BitRmwOp, bit: Bit, comptime ordering: AtomicOrder) u1 {
227 const old_bit: u8 = switch (@sizeOf(T)) {234 const old_bit: u8 = switch (@sizeOf(T)) {
228 2 => switch (op) {235 2 => switch (op) {
229 .Set => asm volatile ("lock btsw %[bit], %[ptr]"236 .Set => asm volatile ("lock btsw %[bit], %[ptr]"
...@@ -305,13 +312,6 @@ pub fn Atomic(comptime T: type) type {...@@ -305,13 +312,6 @@ pub fn Atomic(comptime T: type) type {
305 };312 };
306}313}
307314
308test "Atomic.fence" {
309 inline for (.{ .Acquire, .Release, .AcqRel, .SeqCst }) |ordering| {
310 var x = Atomic(usize).init(0);
311 x.fence(ordering);
312 }
313}
314
315fn atomicIntTypes() []const type {315fn atomicIntTypes() []const type {
316 comptime var bytes = 1;316 comptime var bytes = 1;
317 comptime var types: []const type = &[_]type{};317 comptime var types: []const type = &[_]type{};
...@@ -357,7 +357,7 @@ test "Atomic.store" {...@@ -357,7 +357,7 @@ test "Atomic.store" {
357 }357 }
358}358}
359359
360const atomic_rmw_orderings = [_]Ordering{360const atomic_rmw_orderings = [_]AtomicOrder{
361 .Monotonic,361 .Monotonic,
362 .Acquire,362 .Acquire,
363 .Release,363 .Release,
...@@ -389,7 +389,7 @@ test "Atomic.swap" {...@@ -389,7 +389,7 @@ test "Atomic.swap" {
389 }389 }
390}390}
391391
392const atomic_cmpxchg_orderings = [_][2]Ordering{392const atomic_cmpxchg_orderings = [_][2]AtomicOrder{
393 .{ .Monotonic, .Monotonic },393 .{ .Monotonic, .Monotonic },
394 .{ .Acquire, .Monotonic },394 .{ .Acquire, .Monotonic },
395 .{ .Acquire, .Acquire },395 .{ .Acquire, .Acquire },