step 10: idle mode

This commit is contained in:
Jack Halford 2019-12-15 21:36:49 +01:00
parent e30f016977
commit a8c68611ce
5 changed files with 72 additions and 16 deletions

View file

@ -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");

View file

@ -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);
}

View file

@ -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 {

View file

@ -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();

View file

@ -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
}
}