Commit 4ac36d094c

Andrew Kelley <superjoe30@gmail.com>
2018-04-28 01:27:58
add std.atomic.Stack and std.atomic.Queue
1 parent 73bf897
std/atomic/index.zig
@@ -0,0 +1,7 @@
+pub const Stack = @import("stack.zig").Stack;
+pub const Queue = @import("queue.zig").Queue;
+
+test "std.atomic" {
+    _ = @import("stack.zig").Stack;
+    _ = @import("queue.zig").Queue;
+}
std/atomic/queue.zig
@@ -0,0 +1,37 @@
+/// Many reader, many writer, non-allocating, thread-safe, lock-free
+pub fn Queue(comptime T: type) type {
+    return struct {
+        head: &Node,
+        tail: &Node,
+        root: Node,
+
+        pub const Self = this;
+
+        pub const Node = struct {
+            next: ?&Node,
+            data: T,
+        };
+
+        // TODO: well defined copy elision
+        pub fn init(self: &Self) void {
+            self.root.next = null;
+            self.head = &self.root;
+            self.tail = &self.root;
+        }
+
+        pub fn put(self: &Self, node: &Node) void {
+            node.next = null;
+
+            const tail = @atomicRmw(&Node, &self.tail, AtomicRmwOp.Xchg, node, AtomicOrder.SeqCst);
+            _ = @atomicRmw(?&Node, &tail.next, AtomicRmwOp.Xchg, node, AtomicOrder.SeqCst);
+        }
+
+        pub fn get(self: &Self) ?&Node {
+            var head = @atomicLoad(&Node, &self.head, AtomicOrder.Acquire);
+            while (true) {
+                const node = head.next ?? return null;
+                head = @cmpxchgWeak(&Node, &self.head, head, node, AtomicOrder.Release, AtomicOrder.Acquire) ?? return node;
+            }
+        }
+    };
+}
std/atomic/stack.zig
@@ -0,0 +1,45 @@
+/// Many reader, many writer, non-allocating, thread-safe, lock-free
+pub fn Stack(comptime T: type) type {
+    return struct {
+        root: ?&Node,
+
+        pub const Self = this;
+
+        pub const Node = struct {
+            next: ?&Node,
+            data: T,
+        };
+
+        pub fn init() Self {
+            return Self {
+                .root = null,
+            };
+        }
+
+        /// push operation, but only if you are the first item in the stack. if you did not succeed in
+        /// being the first item in the stack, returns the other item that was there.
+        pub fn pushFirst(self: &Self, node: &Node) ?&Node {
+            node.next = null;
+            return @cmpxchgStrong(?&Node, &self.root, null, node, AtomicOrder.AcqRel, AtomicOrder.AcqRel);
+        }
+
+        pub fn push(self: &Self, node: &Node) void {
+            var root = @atomicLoad(?&Node, &self.root, AtomicOrder.Acquire);
+            while (true) {
+                node.next = root;
+                root = @cmpxchgWeak(?&Node, &self.root, root, node, AtomicOrder.Release, AtomicOrder.Acquire) ?? break;
+            }
+        }
+
+        pub fn pop(self: &Self) ?&Node {
+            var root = @atomicLoad(?&Node, &self.root, AtomicOrder.Acquire);
+            while (true) {
+                root = @cmpxchgWeak(?&Node, &self.root, root, (root ?? return null).next, AtomicOrder.Release, AtomicOrder.Acquire) ?? return root;
+            }
+        }
+
+        pub fn isEmpty(self: &Self) bool {
+            return @atomicLoad(?&Node, &self.root, AtomicOrder.Relaxed) == null;
+        }
+    };
+}
std/index.zig
@@ -8,6 +8,7 @@ pub const HashMap = @import("hash_map.zig").HashMap;
 pub const LinkedList = @import("linked_list.zig").LinkedList;
 pub const IntrusiveLinkedList = @import("linked_list.zig").IntrusiveLinkedList;
 
+pub const atomic = @import("atomic/index.zig");
 pub const base64 = @import("base64.zig");
 pub const build = @import("build.zig");
 pub const c = @import("c/index.zig");
@@ -34,6 +35,7 @@ pub const zig = @import("zig/index.zig");
 
 test "std" {
     // run tests from these
+    _ = @import("atomic/index.zig");
     _ = @import("array_list.zig");
     _ = @import("buf_map.zig");
     _ = @import("buf_set.zig");
CMakeLists.txt
@@ -415,6 +415,9 @@ set(ZIG_CPP_SOURCES
 
 set(ZIG_STD_FILES
     "array_list.zig"
+    "atomic/index.zig"
+    "atomic/stack.zig"
+    "atomic/queue.zig"
     "base64.zig"
     "buf_map.zig"
     "buf_set.zig"