| author | |
| committer | |
| log | 2418c8206a81d1410850283ea6046c053a24851b |
| tree | cc9ddd3f4b7cbc8102884c6ae1db9c80872c6a14 |
| parent | cf7de64f1a136c9208284362db6cc1d3c81f1111 |
| parent | 767dd772c091f072f4b446365e6053021fa67c26 |
| signature |
std.atomic.{Int,Bool}4 files changed, 67 insertions(+), 3 deletions(-)
CMakeLists.txt+1| ... | @@ -318,6 +318,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -318,6 +318,7 @@ set(ZIG_STAGE2_SOURCES |
| 318 | "${CMAKE_SOURCE_DIR}/lib/std/array_list.zig" | 318 | "${CMAKE_SOURCE_DIR}/lib/std/array_list.zig" |
| 319 | "${CMAKE_SOURCE_DIR}/lib/std/ascii.zig" | 319 | "${CMAKE_SOURCE_DIR}/lib/std/ascii.zig" |
| 320 | "${CMAKE_SOURCE_DIR}/lib/std/atomic.zig" | 320 | "${CMAKE_SOURCE_DIR}/lib/std/atomic.zig" |
| 321 | "${CMAKE_SOURCE_DIR}/lib/std/atomic/bool.zig" | ||
| 321 | "${CMAKE_SOURCE_DIR}/lib/std/atomic/int.zig" | 322 | "${CMAKE_SOURCE_DIR}/lib/std/atomic/int.zig" |
| 322 | "${CMAKE_SOURCE_DIR}/lib/std/atomic/queue.zig" | 323 | "${CMAKE_SOURCE_DIR}/lib/std/atomic/queue.zig" |
| 323 | "${CMAKE_SOURCE_DIR}/lib/std/atomic/stack.zig" | 324 | "${CMAKE_SOURCE_DIR}/lib/std/atomic/stack.zig" |
lib/std/atomic.zig+2| ... | @@ -5,10 +5,12 @@ | ... | @@ -5,10 +5,12 @@ |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | pub const Stack = @import("atomic/stack.zig").Stack; | 6 | pub const Stack = @import("atomic/stack.zig").Stack; |
| 7 | pub const Queue = @import("atomic/queue.zig").Queue; | 7 | pub const Queue = @import("atomic/queue.zig").Queue; |
| 8 | pub const Bool = @import("atomic/bool.zig").Bool; | ||
| 8 | pub const Int = @import("atomic/int.zig").Int; | 9 | pub const Int = @import("atomic/int.zig").Int; |
| 9 | 10 | ||
| 10 | test "std.atomic" { | 11 | test "std.atomic" { |
| 11 | _ = @import("atomic/stack.zig"); | 12 | _ = @import("atomic/stack.zig"); |
| 12 | _ = @import("atomic/queue.zig"); | 13 | _ = @import("atomic/queue.zig"); |
| 14 | _ = @import("atomic/bool.zig"); | ||
| 13 | _ = @import("atomic/int.zig"); | 15 | _ = @import("atomic/int.zig"); |
| 14 | } | 16 | } |
lib/std/atomic/bool.zig created+43| ... | @@ -0,0 +1,43 @@ | ||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | // Copyright (c) 2015-2020 Zig Contributors | ||
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | ||
| 4 | // The MIT license requires this copyright notice to be included in all copies | ||
| 5 | // and substantial portions of the software. | ||
| 6 | |||
| 7 | const std = @import("std"); | ||
| 8 | const builtin = std.builtin; | ||
| 9 | const testing = std.testing; | ||
| 10 | |||
| 11 | /// Thread-safe, lock-free boolean | ||
| 12 | pub const Bool = extern struct { | ||
| 13 | unprotected_value: bool, | ||
| 14 | |||
| 15 | pub const Self = @This(); | ||
| 16 | |||
| 17 | pub fn init(init_val: bool) Self { | ||
| 18 | return Self{ .unprotected_value = init_val }; | ||
| 19 | } | ||
| 20 | |||
| 21 | // xchg is only valid rmw operation for a bool | ||
| 22 | /// Atomically modifies memory and then returns the previous value. | ||
| 23 | pub fn xchg(self: *Self, operand: bool, comptime ordering: std.builtin.AtomicOrder) bool { | ||
| 24 | return @atomicRmw(bool, &self.unprotected_value, .Xchg, operand, ordering); | ||
| 25 | } | ||
| 26 | |||
| 27 | pub fn load(self: *Self, comptime ordering: std.builtin.AtomicOrder) bool { | ||
| 28 | return @atomicLoad(bool, &self.unprotected_value, ordering); | ||
| 29 | } | ||
| 30 | |||
| 31 | pub fn store(self: *Self, value: bool, comptime ordering: std.builtin.AtomicOrder) void { | ||
| 32 | @atomicStore(bool, &self.unprotected_value, value, ordering); | ||
| 33 | } | ||
| 34 | }; | ||
| 35 | |||
| 36 | test "std.atomic.Bool" { | ||
| 37 | var a = Bool.init(false); | ||
| 38 | testing.expectEqual(false, a.xchg(false, .SeqCst)); | ||
| 39 | testing.expectEqual(false, a.load(.SeqCst)); | ||
| 40 | a.store(true, .SeqCst); | ||
| 41 | testing.expectEqual(true, a.xchg(false, .SeqCst)); | ||
| 42 | testing.expectEqual(false, a.load(.SeqCst)); | ||
| 43 | } | ||
lib/std/atomic/int.zig+21-3| ... | @@ -4,11 +4,13 @@ | ... | @@ -4,11 +4,13 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | 6 | ||
| 7 | const builtin = @import("std").builtin; | 7 | const std = @import("std"); |
| 8 | const builtin = std.builtin; | ||
| 9 | const testing = std.testing; | ||
| 8 | 10 | ||
| 9 | /// Thread-safe, lock-free integer | 11 | /// Thread-safe, lock-free integer |
| 10 | pub fn Int(comptime T: type) type { | 12 | pub fn Int(comptime T: type) type { |
| 11 | return struct { | 13 | return extern struct { |
| 12 | unprotected_value: T, | 14 | unprotected_value: T, |
| 13 | 15 | ||
| 14 | pub const Self = @This(); | 16 | pub const Self = @This(); |
| ... | @@ -19,7 +21,7 @@ pub fn Int(comptime T: type) type { | ... | @@ -19,7 +21,7 @@ pub fn Int(comptime T: type) type { |
| 19 | 21 | ||
| 20 | /// Read, Modify, Write | 22 | /// Read, Modify, Write |
| 21 | pub fn rmw(self: *Self, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) T { | 23 | pub fn rmw(self: *Self, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) T { |
| 22 | return @atomicRmw(T, &self.unprotected_value, operand, ordering); | 24 | return @atomicRmw(T, &self.unprotected_value, op, operand, ordering); |
| 23 | } | 25 | } |
| 24 | 26 | ||
| 25 | pub fn load(self: *Self, comptime ordering: builtin.AtomicOrder) T { | 27 | pub fn load(self: *Self, comptime ordering: builtin.AtomicOrder) T { |
| ... | @@ -30,11 +32,13 @@ pub fn Int(comptime T: type) type { | ... | @@ -30,11 +32,13 @@ pub fn Int(comptime T: type) type { |
| 30 | @atomicStore(T, &self.unprotected_value, value, ordering); | 32 | @atomicStore(T, &self.unprotected_value, value, ordering); |
| 31 | } | 33 | } |
| 32 | 34 | ||
| 35 | /// Twos complement wraparound increment | ||
| 33 | /// Returns previous value | 36 | /// Returns previous value |
| 34 | pub fn incr(self: *Self) T { | 37 | pub fn incr(self: *Self) T { |
| 35 | return self.rmw(.Add, 1, .SeqCst); | 38 | return self.rmw(.Add, 1, .SeqCst); |
| 36 | } | 39 | } |
| 37 | 40 | ||
| 41 | /// Twos complement wraparound decrement | ||
| 38 | /// Returns previous value | 42 | /// Returns previous value |
| 39 | pub fn decr(self: *Self) T { | 43 | pub fn decr(self: *Self) T { |
| 40 | return self.rmw(.Sub, 1, .SeqCst); | 44 | return self.rmw(.Sub, 1, .SeqCst); |
| ... | @@ -52,8 +56,22 @@ pub fn Int(comptime T: type) type { | ... | @@ -52,8 +56,22 @@ pub fn Int(comptime T: type) type { |
| 52 | return self.rmw(.Xchg, new_value, .SeqCst); | 56 | return self.rmw(.Xchg, new_value, .SeqCst); |
| 53 | } | 57 | } |
| 54 | 58 | ||
| 59 | /// Twos complement wraparound add | ||
| 60 | /// Returns previous value | ||
| 55 | pub fn fetchAdd(self: *Self, op: T) T { | 61 | pub fn fetchAdd(self: *Self, op: T) T { |
| 56 | return self.rmw(.Add, op, .SeqCst); | 62 | return self.rmw(.Add, op, .SeqCst); |
| 57 | } | 63 | } |
| 58 | }; | 64 | }; |
| 59 | } | 65 | } |
| 66 | |||
| 67 | test "std.atomic.Int" { | ||
| 68 | var a = Int(u8).init(0); | ||
| 69 | testing.expectEqual(@as(u8, 0), a.incr()); | ||
| 70 | testing.expectEqual(@as(u8, 1), a.load(.SeqCst)); | ||
| 71 | a.store(42, .SeqCst); | ||
| 72 | testing.expectEqual(@as(u8, 42), a.decr()); | ||
| 73 | testing.expectEqual(@as(u8, 41), a.xchg(100)); | ||
| 74 | testing.expectEqual(@as(u8, 100), a.fetchAdd(5)); | ||
| 75 | testing.expectEqual(@as(u8, 105), a.get()); | ||
| 76 | a.set(200); | ||
| 77 | } |