aboutsummaryrefslogtreecommitdiff
path: root/std/atomic/stack.zig
diff options
context:
space:
mode:
Diffstat (limited to 'std/atomic/stack.zig')
-rw-r--r--std/atomic/stack.zig45
1 files changed, 45 insertions, 0 deletions
diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig
new file mode 100644
index 0000000000..4ceecb7b1d
--- /dev/null
+++ b/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;
+ }
+ };
+}