authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-10 16:13:36-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-12-10 16:13:36-05:00
loga3de27ef3bbc5212b2129ed75bab3503da09b9cf
treec0b7d12e3d81df6ff1683c8376442efafbcdf803
parent55cac65f957fc374e4e369e26bd338f11b8b37ee
parent88e3a7d6dc7289103b8a644aaf6a63437ff6b6b5
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #7372 from LemonBoy/atomicint

Improvements for std.atomic.{Int,Bool}

4 files changed, 62 insertions(+), 3 deletions(-)

lib/std/atomic/bool.zig+12
...@@ -21,14 +21,26 @@ pub const Bool = extern struct {...@@ -21,14 +21,26 @@ pub const Bool = extern struct {
21 // xchg is only valid rmw operation for a bool21 // xchg is only valid rmw operation for a bool
22 /// Atomically modifies memory and then returns the previous value.22 /// Atomically modifies memory and then returns the previous value.
23 pub fn xchg(self: *Self, operand: bool, comptime ordering: std.builtin.AtomicOrder) bool {23 pub fn xchg(self: *Self, operand: bool, comptime ordering: std.builtin.AtomicOrder) bool {
24 switch (ordering) {
25 .Monotonic, .Acquire, .Release, .AcqRel, .SeqCst => {},
26 else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a RMW operation"),
27 }
24 return @atomicRmw(bool, &self.unprotected_value, .Xchg, operand, ordering);28 return @atomicRmw(bool, &self.unprotected_value, .Xchg, operand, ordering);
25 }29 }
2630
27 pub fn load(self: *Self, comptime ordering: std.builtin.AtomicOrder) bool {31 pub fn load(self: *Self, comptime ordering: std.builtin.AtomicOrder) bool {
32 switch (ordering) {
33 .Unordered, .Monotonic, .Acquire, .SeqCst => {},
34 else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a load operation"),
35 }
28 return @atomicLoad(bool, &self.unprotected_value, ordering);36 return @atomicLoad(bool, &self.unprotected_value, ordering);
29 }37 }
3038
31 pub fn store(self: *Self, value: bool, comptime ordering: std.builtin.AtomicOrder) void {39 pub fn store(self: *Self, value: bool, comptime ordering: std.builtin.AtomicOrder) void {
40 switch (ordering) {
41 .Unordered, .Monotonic, .Release, .SeqCst => {},
42 else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a store operation"),
43 }
32 @atomicStore(bool, &self.unprotected_value, value, ordering);44 @atomicStore(bool, &self.unprotected_value, value, ordering);
33 }45 }
34};46};
lib/std/atomic/int.zig+15
...@@ -10,6 +10,9 @@ const testing = std.testing;...@@ -10,6 +10,9 @@ const testing = std.testing;
1010
11/// Thread-safe, lock-free integer11/// Thread-safe, lock-free integer
12pub fn Int(comptime T: type) type {12pub fn Int(comptime T: type) type {
13 if (!std.meta.trait.isIntegral(T))
14 @compileError("Expected integral type, got '" ++ @typeName(T) ++ "'");
15
13 return extern struct {16 return extern struct {
14 unprotected_value: T,17 unprotected_value: T,
1518
...@@ -21,14 +24,26 @@ pub fn Int(comptime T: type) type {...@@ -21,14 +24,26 @@ pub fn Int(comptime T: type) type {
2124
22 /// Read, Modify, Write25 /// Read, Modify, Write
23 pub fn rmw(self: *Self, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) T {26 pub fn rmw(self: *Self, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) T {
27 switch (ordering) {
28 .Monotonic, .Acquire, .Release, .AcqRel, .SeqCst => {},
29 else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a RMW operation"),
30 }
24 return @atomicRmw(T, &self.unprotected_value, op, operand, ordering);31 return @atomicRmw(T, &self.unprotected_value, op, operand, ordering);
25 }32 }
2633
27 pub fn load(self: *Self, comptime ordering: builtin.AtomicOrder) T {34 pub fn load(self: *Self, comptime ordering: builtin.AtomicOrder) T {
35 switch (ordering) {
36 .Unordered, .Monotonic, .Acquire, .SeqCst => {},
37 else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a load operation"),
38 }
28 return @atomicLoad(T, &self.unprotected_value, ordering);39 return @atomicLoad(T, &self.unprotected_value, ordering);
29 }40 }
3041
31 pub fn store(self: *Self, value: T, comptime ordering: builtin.AtomicOrder) void {42 pub fn store(self: *Self, value: T, comptime ordering: builtin.AtomicOrder) void {
43 switch (ordering) {
44 .Unordered, .Monotonic, .Release, .SeqCst => {},
45 else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a store operation"),
46 }
32 @atomicStore(T, &self.unprotected_value, value, ordering);47 @atomicStore(T, &self.unprotected_value, value, ordering);
33 }48 }
3449
lib/std/meta/trait.zig+32
...@@ -312,6 +312,38 @@ test "std.meta.trait.isNumber" {...@@ -312,6 +312,38 @@ test "std.meta.trait.isNumber" {
312 testing.expect(!isNumber(NotANumber));312 testing.expect(!isNumber(NotANumber));
313}313}
314314
315pub fn isIntegral(comptime T: type) bool {
316 return switch (@typeInfo(T)) {
317 .Int, .ComptimeInt => true,
318 else => false,
319 };
320}
321
322test "isIntegral" {
323 testing.expect(isIntegral(u32));
324 testing.expect(!isIntegral(f32));
325 testing.expect(isIntegral(@TypeOf(102)));
326 testing.expect(!isIntegral(@TypeOf(102.123)));
327 testing.expect(!isIntegral(*u8));
328 testing.expect(!isIntegral([]u8));
329}
330
331pub fn isFloat(comptime T: type) bool {
332 return switch (@typeInfo(T)) {
333 .Float, .ComptimeFloat => true,
334 else => false,
335 };
336}
337
338test "isFloat" {
339 testing.expect(!isFloat(u32));
340 testing.expect(isFloat(f32));
341 testing.expect(!isFloat(@TypeOf(102)));
342 testing.expect(isFloat(@TypeOf(102.123)));
343 testing.expect(!isFloat(*f64));
344 testing.expect(!isFloat([]f32));
345}
346
315pub fn isConstPtr(comptime T: type) bool {347pub fn isConstPtr(comptime T: type) bool {
316 if (!comptime is(.Pointer)(T)) return false;348 if (!comptime is(.Pointer)(T)) return false;
317 return @typeInfo(T).Pointer.is_const;349 return @typeInfo(T).Pointer.is_const;
lib/std/os.zig+3-3
...@@ -5214,7 +5214,7 @@ pub const CopyFileRangeError = error{...@@ -5214,7 +5214,7 @@ pub const CopyFileRangeError = error{
52145214
5215var has_copy_file_range_syscall = init: {5215var has_copy_file_range_syscall = init: {
5216 const kernel_has_syscall = std.Target.current.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true;5216 const kernel_has_syscall = std.Target.current.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true;
5217 break :init std.atomic.Int(bool).init(kernel_has_syscall);5217 break :init std.atomic.Bool.init(kernel_has_syscall);
5218};5218};
52195219
5220/// Transfer data between file descriptors at specified offsets.5220/// Transfer data between file descriptors at specified offsets.
...@@ -5246,7 +5246,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len...@@ -5246,7 +5246,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len
5246 const use_c = std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok;5246 const use_c = std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok;
52475247
5248 if (std.Target.current.os.tag == .linux and5248 if (std.Target.current.os.tag == .linux and
5249 (use_c or has_copy_file_range_syscall.get()))5249 (use_c or has_copy_file_range_syscall.load(.Monotonic)))
5250 {5250 {
5251 const sys = if (use_c) std.c else linux;5251 const sys = if (use_c) std.c else linux;
52525252
...@@ -5271,7 +5271,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len...@@ -5271,7 +5271,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len
5271 EXDEV => {},5271 EXDEV => {},
5272 // syscall added in Linux 4.5, use fallback5272 // syscall added in Linux 4.5, use fallback
5273 ENOSYS => {5273 ENOSYS => {
5274 has_copy_file_range_syscall.set(false);5274 has_copy_file_range_syscall.store(true, .Monotonic);
5275 },5275 },
5276 else => |err| return unexpectedErrno(err),5276 else => |err| return unexpectedErrno(err),
5277 }5277 }