diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e5a907ffe6848b7baa04ea5b9cf47b35f25e5cb..16e3d7a3477c68cb837ea27ee3816e91674ccfb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -318,6 +318,7 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/std/array_list.zig" "${CMAKE_SOURCE_DIR}/lib/std/ascii.zig" "${CMAKE_SOURCE_DIR}/lib/std/atomic.zig" + "${CMAKE_SOURCE_DIR}/lib/std/atomic/bool.zig" "${CMAKE_SOURCE_DIR}/lib/std/atomic/int.zig" "${CMAKE_SOURCE_DIR}/lib/std/atomic/queue.zig" "${CMAKE_SOURCE_DIR}/lib/std/atomic/stack.zig" diff --git a/lib/std/atomic.zig b/lib/std/atomic.zig index c465708ffa75c37b935bbd956e6066161ca713d8..4402ca462b7639ceea2759d8c16acb2f445234f7 100644 --- a/lib/std/atomic.zig +++ b/lib/std/atomic.zig @@ -5,10 +5,12 @@ // and substantial portions of the software. pub const Stack = @import("atomic/stack.zig").Stack; pub const Queue = @import("atomic/queue.zig").Queue; +pub const Bool = @import("atomic/bool.zig").Bool; pub const Int = @import("atomic/int.zig").Int; test "std.atomic" { _ = @import("atomic/stack.zig"); _ = @import("atomic/queue.zig"); + _ = @import("atomic/bool.zig"); _ = @import("atomic/int.zig"); } diff --git a/lib/std/atomic/bool.zig b/lib/std/atomic/bool.zig new file mode 100644 index 0000000000000000000000000000000000000000..c686fdfae08e4069e88a8ba884dc096d77e36739 --- /dev/null +++ b/lib/std/atomic/bool.zig @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. + +const std = @import("std"); +const builtin = std.builtin; +const testing = std.testing; + +/// Thread-safe, lock-free boolean +pub const Bool = extern struct { + unprotected_value: bool, + + pub const Self = @This(); + + pub fn init(init_val: bool) Self { + return Self{ .unprotected_value = init_val }; + } + + // xchg is only valid rmw operation for a bool + /// Atomically modifies memory and then returns the previous value. + pub fn xchg(self: *Self, operand: bool, comptime ordering: std.builtin.AtomicOrder) bool { + return @atomicRmw(bool, &self.unprotected_value, .Xchg, operand, ordering); + } + + pub fn load(self: *Self, comptime ordering: std.builtin.AtomicOrder) bool { + return @atomicLoad(bool, &self.unprotected_value, ordering); + } + + pub fn store(self: *Self, value: bool, comptime ordering: std.builtin.AtomicOrder) void { + @atomicStore(bool, &self.unprotected_value, value, ordering); + } +}; + +test "std.atomic.Bool" { + var a = Bool.init(false); + testing.expectEqual(false, a.xchg(false, .SeqCst)); + testing.expectEqual(false, a.load(.SeqCst)); + a.store(true, .SeqCst); + testing.expectEqual(true, a.xchg(false, .SeqCst)); + testing.expectEqual(false, a.load(.SeqCst)); +} diff --git a/lib/std/atomic/int.zig b/lib/std/atomic/int.zig index 2ec280732b8d3bd71c08b59e066b73002584d228..155a340b0adefb7288e3a81d3feb987e71b94b1f 100644 --- a/lib/std/atomic/int.zig +++ b/lib/std/atomic/int.zig @@ -4,11 +4,13 @@ // The MIT license requires this copyright notice to be included in all copies // and substantial portions of the software. -const builtin = @import("std").builtin; +const std = @import("std"); +const builtin = std.builtin; +const testing = std.testing; /// Thread-safe, lock-free integer pub fn Int(comptime T: type) type { - return struct { + return extern struct { unprotected_value: T, pub const Self = @This(); @@ -19,7 +21,7 @@ pub fn Int(comptime T: type) type { /// Read, Modify, Write pub fn rmw(self: *Self, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) T { - return @atomicRmw(T, &self.unprotected_value, operand, ordering); + return @atomicRmw(T, &self.unprotected_value, op, operand, ordering); } pub fn load(self: *Self, comptime ordering: builtin.AtomicOrder) T { @@ -30,11 +32,13 @@ pub fn Int(comptime T: type) type { @atomicStore(T, &self.unprotected_value, value, ordering); } + /// Twos complement wraparound increment /// Returns previous value pub fn incr(self: *Self) T { return self.rmw(.Add, 1, .SeqCst); } + /// Twos complement wraparound decrement /// Returns previous value pub fn decr(self: *Self) T { return self.rmw(.Sub, 1, .SeqCst); @@ -52,8 +56,22 @@ pub fn Int(comptime T: type) type { return self.rmw(.Xchg, new_value, .SeqCst); } + /// Twos complement wraparound add + /// Returns previous value pub fn fetchAdd(self: *Self, op: T) T { return self.rmw(.Add, op, .SeqCst); } }; } + +test "std.atomic.Int" { + var a = Int(u8).init(0); + testing.expectEqual(@as(u8, 0), a.incr()); + testing.expectEqual(@as(u8, 1), a.load(.SeqCst)); + a.store(42, .SeqCst); + testing.expectEqual(@as(u8, 42), a.decr()); + testing.expectEqual(@as(u8, 41), a.xchg(100)); + testing.expectEqual(@as(u8, 100), a.fetchAdd(5)); + testing.expectEqual(@as(u8, 105), a.get()); + a.set(200); +}