aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-07-30 14:43:21 +0200
committerHimbeer <himbeer@disroot.org>2024-07-30 14:43:21 +0200
commitee824544423fa55884cf0f716a977cd123c6fedf (patch)
treec176fa3c3046a7441e63cdffc07763a9d54f17a0
parent7d3505c96c4e914813871115aa8286bcf08b3b84 (diff)
syscall: Implement basic asynchronous message passing using unbounded channels (#56)
-rw-r--r--src/lib/channel.zig54
-rw-r--r--src/lib/syscall.zig25
2 files changed, 79 insertions, 0 deletions
diff --git a/src/lib/channel.zig b/src/lib/channel.zig
new file mode 100644
index 0000000..de02f2b
--- /dev/null
+++ b/src/lib/channel.zig
@@ -0,0 +1,54 @@
+// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+
+pub const Error = error{
+ WouldBlock,
+};
+
+pub const Messages = std.TailQueue([]const u8);
+var message_allocator: Allocator = undefined;
+
+const Queues = std.AutoArrayHashMap(usize, Messages);
+var queues: Queues = undefined;
+
+// The channel takes ownership of `bytes`.
+pub fn pass(channel: usize, bytes: []const u8) !void {
+ const entry = try queues.getOrPut(channel);
+ if (!entry.found_existing) {
+ initQueue(entry.value_ptr);
+ }
+
+ const node = try message_allocator.create(Messages.Node);
+ node.data = bytes;
+ entry.value_ptr.append(node);
+}
+
+pub fn receive(channel: usize, buffer: []u8) !usize {
+ const messages = queues.getPtr(channel) orelse return Error.WouldBlock;
+ const message = messages.popFirst() orelse return Error.WouldBlock;
+
+ defer message_allocator.free(message.data);
+ defer message_allocator.destroy(message);
+
+ const len = @min(buffer.len, message.data.len);
+ @memcpy(buffer[0..len], message.data[0..len]);
+
+ return len;
+}
+
+fn initQueue(messages: *Messages) void {
+ messages.* = .{};
+}
+
+pub fn init(allocator: Allocator) void {
+ queues = Queues.init(allocator);
+ message_allocator = allocator;
+}
+
+pub fn messageAllocator() Allocator {
+ return message_allocator;
+}
diff --git a/src/lib/syscall.zig b/src/lib/syscall.zig
index b618979..03a7979 100644
--- a/src/lib/syscall.zig
+++ b/src/lib/syscall.zig
@@ -5,6 +5,7 @@
const std = @import("std");
const Console = @import("Console.zig");
const TrapFrame = @import("TrapFrame.zig");
+const channel = @import("channel.zig");
const hwinfo = @import("hwinfo.zig");
const mem = @import("mem.zig");
const paging = @import("paging.zig");
@@ -31,6 +32,8 @@ pub fn handler(proc: *process.Info, trap_frame: *TrapFrame) !void {
100006 => trap_frame.setReturnValue(threadId(proc)),
100007 => trap_frame.setReturnValue(rawUserinit(trap_frame)),
100008 => trap_frame.setReturnValue(devicesByKind(trap_frame)),
+ 100011 => trap_frame.setReturnValue(pass(trap_frame)),
+ 100012 => trap_frame.setReturnValue(receive(trap_frame)),
else => return HandleError.UnknownSyscall,
}
}
@@ -167,3 +170,25 @@ fn devicesByKind(trap_frame: *const TrapFrame) !usize {
return i;
}
+
+// pass(channel_id: usize, bytes: [*]const u8, len: usize) !void
+fn pass(trap_frame: *const TrapFrame) !void {
+ const id = trap_frame.general_purpose_registers[10];
+ const bytes_ptr: [*]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[11]);
+ const len = trap_frame.general_purpose_registers[12];
+
+ const bytes = bytes_ptr[0..len];
+ const copy = try channel.messageAllocator().alloc(u8, bytes.len);
+ @memcpy(copy, bytes);
+ try channel.pass(id, copy);
+}
+
+// receive(channel_id: usize, buffer: [*]u8, len: usize) !usize
+fn receive(trap_frame: *const TrapFrame) !usize {
+ const id = trap_frame.general_purpose_registers[10];
+ const buffer_ptr: [*]u8 = @ptrFromInt(trap_frame.general_purpose_registers[11]);
+ const len = trap_frame.general_purpose_registers[12];
+
+ const buffer = buffer_ptr[0..len];
+ return channel.receive(id, buffer);
+}