diff --git a/.gitignore b/.gitignore index d12ece0..3389c86 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ -zig-cache/ -demo -demo.o +.zig-cache/ +zig-out/ diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..3f18aeb --- /dev/null +++ b/build.zig @@ -0,0 +1,29 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const mod = b.addModule("spsc_ring", .{ + .root_source_file = b.path("src/spsc_ring.zig"), + .target = target, + }); + + const example_exe = b.addExecutable(.{ + .name = "demo", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/demo.zig"), + .target = target, + .optimize = optimize, + .imports = &.{ + .{ .name = "spsc_ring", .module = mod }, + }, + }), + }); + b.installArtifact(example_exe); + + const run_example = b.step("run", "Run the example"); + const run_example_cmd = b.addRunArtifact(example_exe); + run_example.dependOn(&run_example_cmd.step); + if (b.args) |args| run_example_cmd.addArgs(args); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..8c144b0 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,15 @@ +.{ + .name = .zig_spsc_ring, + .version = "0.0.0", + .fingerprint = 0x2991ff75c63dce16, // Changing this has security and trust implications. + .minimum_zig_version = "0.15.1", + .dependencies = .{}, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + // For example... + //"LICENSE", + //"README.md", + }, +} diff --git a/demo.zig b/src/demo.zig similarity index 76% rename from demo.zig rename to src/demo.zig index cd92908..6753774 100644 --- a/demo.zig +++ b/src/demo.zig @@ -16,14 +16,14 @@ fn producer(ring: *Ring(u64)) void { } fn consumer(ring: *Ring(u64)) !void { - const stdout_file = std.io.getStdOut().writer(); - var bw = std.io.bufferedWriter(stdout_file); - const stdout = bw.writer(); + var stdout_buffer: [1024]u8 = undefined; + var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); + const stdout = &stdout_writer.interface; while (true) { if (ring.dequeue()) |answer| { try stdout.print("answer = {}\n", .{answer}); - try bw.flush(); + try stdout.flush(); return; } } diff --git a/spsc_ring.zig b/src/spsc_ring.zig similarity index 74% rename from spsc_ring.zig rename to src/spsc_ring.zig index 691807b..cdf1fe5 100644 --- a/spsc_ring.zig +++ b/src/spsc_ring.zig @@ -23,13 +23,13 @@ const std = @import("std"); const PaddedConsumer = struct { - head: std.atomic.Atomic(usize), - padding: [std.atomic.cache_line - @sizeOf(std.atomic.Atomic(usize))]u8 = undefined, + head: std.atomic.Value(usize), + padding: [std.atomic.cache_line - @sizeOf(std.atomic.Value(usize))]u8 = undefined, }; const PaddedProducer = struct { - tail: std.atomic.Atomic(usize), - padding: [std.atomic.cache_line - @sizeOf(std.atomic.Atomic(usize))]u8 = undefined, + tail: std.atomic.Value(usize), + padding: [std.atomic.cache_line - @sizeOf(std.atomic.Value(usize))]u8 = undefined, }; pub fn Ring(comptime T: type) type { @@ -45,16 +45,16 @@ pub fn Ring(comptime T: type) type { std.debug.assert(std.math.isPowerOfTwo(items.len)); return Self{ - .consumer = PaddedConsumer{ .head = std.atomic.Atomic(usize).init(0) }, - .producer = PaddedProducer{ .tail = std.atomic.Atomic(usize).init(0) }, + .consumer = PaddedConsumer{ .head = std.atomic.Value(usize).init(0) }, + .producer = PaddedProducer{ .tail = std.atomic.Value(usize).init(0) }, .items = items, .mask = items.len - 1, }; } pub inline fn enqueue(self: *Self, value: T) bool { - const consumer = self.consumer.head.load(std.atomic.Ordering.Acquire); - const producer = self.producer.tail.load(std.atomic.Ordering.Acquire); + const consumer = self.consumer.head.load(.acquire); + const producer = self.producer.tail.load(.acquire); const delta = producer + 1; if (delta & self.mask == consumer & self.mask) @@ -62,32 +62,28 @@ pub fn Ring(comptime T: type) type { self.items[producer & self.mask] = value; - std.atomic.fence(std.atomic.Ordering.Release); - self.producer.tail.store(delta, std.atomic.Ordering.Release); + self.producer.tail.store(delta, .release); return true; } pub inline fn dequeue(self: *Self) ?T { - const consumer = self.consumer.head.load(std.atomic.Ordering.Acquire); - const producer = self.producer.tail.load(std.atomic.Ordering.Acquire); + const consumer = self.consumer.head.load(.acquire); + const producer = self.producer.tail.load(.acquire); if (consumer == producer) return null; - std.atomic.fence(std.atomic.Ordering.Acquire); - const value = self.items[consumer & self.mask]; - std.atomic.fence(std.atomic.Ordering.Release); - self.consumer.head.store(consumer + 1, std.atomic.Ordering.Release); + self.consumer.head.store(consumer + 1, .release); return value; } pub inline fn length(self: *Self) usize { - const consumer = self.consumer.head.load(std.atomic.Ordering.Acquire); - const producer = self.producer.tail.load(std.atomic.Ordering.Acquire); + const consumer = self.consumer.head.load(.acquire); + const producer = self.producer.tail.load(.acquire); return (producer - consumer) & self.mask; } };