diff --git a/src/arch/x86/lib/instructions.zig b/src/arch/x86/lib/instructions.zig index 94c4c88..f93edbe 100644 --- a/src/arch/x86/lib/instructions.zig +++ b/src/arch/x86/lib/instructions.zig @@ -19,6 +19,9 @@ pub fn cli() void { pub fn sti() void { asm volatile ("sti"); } +pub inline fn hlt() void { + asm volatile ("hlt"); +} pub inline fn int3() void { asm volatile ("int3"); diff --git a/src/console.zig b/src/console.zig index 0246a90..38d6e39 100644 --- a/src/console.zig +++ b/src/console.zig @@ -8,6 +8,10 @@ var input_write_index: u10 = 0; var command: [10]u8 = undefined; var command_len: usize = 0; +fn sleep_for_2() void { + task.usleep(2 * 1000 * 1000) catch unreachable; +} + fn execute(input: []u8) void { const eql = std.mem.eql; if (eql(u8, input, "clear")) return vga.clear(); @@ -16,6 +20,7 @@ fn execute(input: []u8) void { if (eql(u8, input, "tasks")) return task.format(); if (eql(u8, input, "tasks")) return task.format_short(); if (eql(u8, input, "lspci")) return pci.lspci(); + if (eql(u8, input, "sleep2")) return sleep_for_2(); if (eql(u8, input, "uptime")) return time.uptime(); println("{}: command not found", input); } diff --git a/src/main.zig b/src/main.zig index 4556c86..c060679 100644 --- a/src/main.zig +++ b/src/main.zig @@ -26,12 +26,14 @@ export fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn { pci.scan(); task.new(@ptrToInt(topbar)) catch unreachable; - task.new(@ptrToInt(console.loop)) catch unreachable; + // task.new(@ptrToInt(console.loop)) catch unreachable; - while (true) { - task.lock_scheduler(); - task.schedule(); - } + console.loop(); + unreachable; + // while (true) { + // task.lock_scheduler(); + // task.schedule(); + // } } pub fn panic(a: []const u8, b: ?*builtin.StackTrace) noreturn { diff --git a/src/task.zig b/src/task.zig index 3c071b8..4f8fef7 100644 --- a/src/task.zig +++ b/src/task.zig @@ -1,6 +1,5 @@ pub usingnamespace @import("index.zig"); -var timer_last_count: u64 = 0; var boot_task = Task{ .tid = 0, .esp = 0x47, .state = .Running }; const TaskNode = std.TailQueue(*Task).Node; @@ -17,6 +16,7 @@ var tid_counter: u16 = 1; ///ASM extern fn switch_tasks(new_esp: u32, old_esp_addr: u32) void; +var timer_last_count: u64 = 0; pub fn update_time_used() void { const current_count = time.offset_us; const elapsed = current_count - timer_last_count; @@ -114,7 +114,7 @@ pub fn unblock(node: *TaskNode) void { pub fn switch_to(chosen: *TaskNode) void { assert(chosen.data.state == .ReadyToRun); - // in case of self preemption + // in case of self preemption, shouldn't happen really if (current_task.data.state == .Running) { current_task.data.state = .ReadyToRun; ready_tasks.append(current_task); @@ -133,21 +133,66 @@ pub fn switch_to(chosen: *TaskNode) void { @noInlineCall(switch_tasks, chosen.data.esp, @ptrToInt(old_task_esp_addr)); } +fn notify_idle() void { + const bg = vga.background; + const fg = vga.foreground; + const cursor = vga.cursor; + vga.background = fg; + vga.foreground = bg; + vga.cursor = 80 - 4; + vga.cursor_enabled = false; + + print("IDLE"); + + vga.cursor_enabled = true; + vga.cursor = cursor; + vga.background = bg; + vga.foreground = fg; +} + +pub var CPU_idle_time: u64 = 0; +pub var CPU_idle_start_time: u64 = 0; pub fn schedule() void { assert(IRQ_disable_counter > 0); update_time_used(); - // check if somebody wants to run - const chosen = ready_tasks.popFirst(); - if (chosen == null) return unlock_scheduler(); + if (ready_tasks.popFirst()) |t| { + // somebody is ready to run + // std doesn't do this, for developer flexibility maybe? + t.prev = null; + t.next = null; + switch_to(t); + } else if (current_task.data.state == .Running) { + // single task mode, carry on + return unlock_scheduler(); + } else { + // idle mode + notify_idle(); - // std doesn't do this, for developer flexibility maybe? - chosen.?.prev = null; - chosen.?.next = null; + // borrow the current task + const borrow = current_task; - // switch - switch_to(chosen.?); + CPU_idle_start_time = time.offset_us; //for power management + + while (true) { // idle loop + if (ready_tasks.popFirst()) |t| { // found a new task + CPU_idle_time += time.offset_us - CPU_idle_start_time; // count time as idle + timer_last_count = time.offset_us; // don't count time as used + println("went into idle mode for {}usecs", time.offset_us - CPU_idle_start_time); + + if (t == borrow) { + t.data.state = .Running; + return unlock_scheduler(); //no need to ctx_switch we are already running this + } + return switch_to(t); + } else { // no tasks ready, let the timer fire + x86.sti(); // enable interrupts to allow the timer to fire + x86.hlt(); // halt and wait for the timer to fire + x86.cli(); // disable interrupts again to see if there is something to do + } + } + } } var IRQ_disable_counter: usize = 0; @@ -158,6 +203,7 @@ pub fn lock_scheduler() void { } } pub fn unlock_scheduler() void { + if (IRQ_disable_counter == 0) println("error trying to unlock"); if (constants.SMP == false) { IRQ_disable_counter -= 1; if (IRQ_disable_counter == 0) x86.sti(); diff --git a/src/vga.zig b/src/vga.zig index 7d1e247..94fe865 100644 --- a/src/vga.zig +++ b/src/vga.zig @@ -79,7 +79,7 @@ pub fn topbar() void { vga.cursor = cursor; vga.background = bg; - task.usleep(60 * 1000) catch unreachable; // 60ms + task.usleep(500 * 1000) catch unreachable; // 60ms } }