feat: implement a 2-way channel for message passing

This commit is contained in:
Rekai Nyangadzayi Musuka 2023-03-10 02:01:26 -06:00
parent 52ac8d952f
commit d5e66caf21
1 changed files with 27 additions and 6 deletions

View File

@ -1,8 +1,29 @@
const std = @import("std");
const Log2Int = std.math.Log2Int;
pub fn Channel(comptime T: type) type {
const EmuMessage = enum { Pause, Resume, Quit };
const GuiMessage = enum { Paused, Quit };
pub const TwoWayChannel = struct {
const Self = @This();
emu: Channel(EmuMessage),
gui: Channel(GuiMessage),
pub fn init(items: []u8) Self {
comptime std.debug.assert(@sizeOf(EmuMessage) == @sizeOf(GuiMessage));
comptime std.debug.assert(@sizeOf(@typeInfo([]u8).Pointer.child) == @sizeOf(EmuMessage));
std.debug.assert(items.len % 2 == 0);
const left = @ptrCast([*]EmuMessage, items)[0 .. items.len / 2];
const right = @ptrCast([*]GuiMessage, items)[items.len / 2 .. items.len];
return .{ .emu = Channel(EmuMessage).init(left), .gui = Channel(GuiMessage).init(right) };
}
};
fn Channel(comptime T: type) type {
return struct {
const Self = @This();
const Index = usize;
@ -29,12 +50,12 @@ pub fn Channel(comptime T: type) type {
};
}
pub fn push(self: *Self, value: T) Error!void {
pub fn push(self: *Self, value: T) void {
const read_idx = self.read.load(.Acquire);
const write_idx = self.write.load(.Acquire);
// Check to see if Queue is full
if (write_idx - read_idx == self.buf.len) return Error.buffer_full;
if (write_idx - read_idx == self.buf.len) @panic("Channel: Buffer is full");
self.buf[self.mask(write_idx)] = value;
@ -49,7 +70,7 @@ pub fn Channel(comptime T: type) type {
if (read_idx == write_idx) return null;
std.atomic.fence(.Acquire);
const value = self.buf[self.mask(self.read)];
const value = self.buf[self.mask(read_idx)];
std.atomic.fence(.Release);
self.read.store(read_idx + 1, .Release);
@ -159,4 +180,4 @@ pub inline fn rotr(comptime T: type, x: T, r: anytype) T {
const ar = @intCast(Log2Int(T), @mod(r, @typeInfo(T).Int.bits));
return x >> ar | x << (1 +% ~ar);
}
}