diff options
author | Himbeer <himbeer@disroot.org> | 2024-07-30 14:43:21 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-07-30 14:43:21 +0200 |
commit | ee824544423fa55884cf0f716a977cd123c6fedf (patch) | |
tree | c176fa3c3046a7441e63cdffc07763a9d54f17a0 | |
parent | 7d3505c96c4e914813871115aa8286bcf08b3b84 (diff) |
syscall: Implement basic asynchronous message passing using unbounded channels (#56)
-rw-r--r-- | src/lib/channel.zig | 54 | ||||
-rw-r--r-- | src/lib/syscall.zig | 25 |
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); +} |