diff --git a/src/console.zig b/src/console.zig index 68d46a3..9032378 100644 --- a/src/console.zig +++ b/src/console.zig @@ -1,9 +1,6 @@ usingnamespace @import("index.zig"); -// shitty ring buffer, fight me. -var input_ring_buffer: [1024]u8 = [_]u8{0} ** 1024; -var input_read_index: u10 = 0; -var input_write_index: u10 = 0; +var input_ring: Ring(u8) = undefined; var command: [10]u8 = undefined; var command_len: usize = 0; @@ -52,19 +49,17 @@ pub fn keypress(char: u8) void { } } -pub fn buffer_write(char: u8) void { - input_ring_buffer[input_write_index] = char; - input_write_index +%= 1; +pub fn keyboard_callback(char: u8) void { + input_ring.write(char); } pub fn loop() void { - ps2.keyboard_callback = buffer_write; + input_ring.init() catch unreachable; + input_ring.task = task.current_task; + ps2.keyboard_callback = keyboard_callback; print("> "); while (true) { - if (input_write_index - input_read_index > 0) { - keypress(input_ring_buffer[input_read_index]); - input_read_index +%= 1; - } - // task.usleep(10 * 1000) catch unreachable; + while (input_ring.read()) |c| keypress(c); + task.block(.IOWait); } } diff --git a/src/index.zig b/src/index.zig index 1f0a71b..c118b5c 100644 --- a/src/index.zig +++ b/src/index.zig @@ -3,6 +3,7 @@ pub const builtin = @import("builtin"); pub const std = @import("std"); pub const assert = std.debug.assert; pub usingnamespace @import("delta_queue.zig"); +pub usingnamespace @import("ring_buffer.zig"); pub usingnamespace @import("vga.zig"); ///arch diff --git a/src/main.zig b/src/main.zig index 15dd245..04d8740 100644 --- a/src/main.zig +++ b/src/main.zig @@ -22,7 +22,7 @@ export fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn { println("--- x86 initialization ---"); x86.x86_main(info); println("--- core initialization ---"); - vmem.initialize(); + vmem.init(); pci.scan(); task.cleaner_task = task.new(@ptrToInt(task.cleaner_loop)) catch unreachable; diff --git a/src/ring_buffer.zig b/src/ring_buffer.zig new file mode 100644 index 0000000..1149146 --- /dev/null +++ b/src/ring_buffer.zig @@ -0,0 +1,31 @@ +usingnamespace @import("index.zig"); + +pub fn Ring(comptime T: type) type { + return struct { + const Self = @This(); + const Size = u10; // 0-1024 + const size = @import("std").math.maxInt(Size); + buffer: *[size]T, + task: ?*task.TaskNode = null, + read_index: Size = 0, + write_index: Size = 0, + + //TODO: allocator argument and remove the namespace + pub fn init(ring: *Self) !void { + ring.buffer = try vmem.create(@typeOf(ring.buffer.*)); + } + + pub fn write(ring: *Self, elem: T) void { + ring.buffer[ring.write_index] = elem; + ring.write_index +%= 1; + if (ring.task) |t| task.unblock(t); + } + + pub fn read(ring: *Self) ?T { + if (ring.write_index == ring.read_index) return null; + const id = ring.read_index; + ring.read_index +%= 1; + return ring.buffer[id]; + } + }; +} diff --git a/src/task.zig b/src/task.zig index f2525fc..f274413 100644 --- a/src/task.zig +++ b/src/task.zig @@ -25,11 +25,12 @@ pub fn update_time_used() void { } pub const TaskState = enum { - Running, - ReadyToRun, - Paused, - Sleeping, - Terminated, + Running, // <=> current_task + ReadyToRun, // <=> inside of ready_tasks + IOWait, // waiting to be woken up by IO + Paused, // unpaused arbitrarily by another process + Sleeping, // woken up by timer + Terminated, // <=> inside of terminated_tasks, waiting to be destroyed }; pub const Task = struct { @@ -124,6 +125,8 @@ pub fn block(state: TaskState) void { assert(state != .Running); assert(state != .ReadyToRun); + // println("blocking {} as {}", current_task.data.tid, state); + lock_scheduler(); defer unlock_scheduler(); @@ -134,17 +137,22 @@ pub fn block(state: TaskState) void { } pub fn unblock(node: *TaskNode) void { + if (node.data.state != .Paused and node.data.state != .IOWait) return; lock_scheduler(); + defer unlock_scheduler(); + node.data.state = .ReadyToRun; blocked_tasks.remove(node); - if (ready_tasks.first == null) { - // Only one task was running before, so pre-empt - switch_to(node); - } else { - // There's at least one task on the "ready to run" queue already, so don't pre-empt - ready_tasks.append(node); - unlock_scheduler(); - } + + // TODO: find a way to fastpath here, hard because of unblock inside of interrupts + // if (current_task.data.state != .Running and ready_tasks.first == null) { + // // Only one task was running before, fastpath + // switch_to(node); + // } else { + // // There's at least one task on the "ready to run" queue already, so don't pre-empt + // ready_tasks.append(node); + // } + ready_tasks.append(node); } pub fn terminate() void { diff --git a/src/vmem.zig b/src/vmem.zig index 877d3d9..75e0c57 100644 --- a/src/vmem.zig +++ b/src/vmem.zig @@ -1,4 +1,5 @@ pub usingnamespace @import("index.zig"); +pub const allocator: std.mem.Allocator = undefined; // TODO: make a better memory allocator // stupid simple virtual memory allocator @@ -39,7 +40,7 @@ pub fn free(address: usize) void { stack_index += 1; } -pub fn initialize() void { +pub fn init() void { var addr: usize = layout.HEAP; while (addr < layout.HEAP_END) : (addr += x86.PAGE_SIZE) { // println("addr {x}", addr);