step 10: idle mode
This commit is contained in:
parent
e30f016977
commit
a8c68611ce
5 changed files with 72 additions and 16 deletions
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
12
src/main.zig
12
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 {
|
||||
|
|
|
|||
66
src/task.zig
66
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?
|
||||
chosen.?.prev = null;
|
||||
chosen.?.next = null;
|
||||
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();
|
||||
|
||||
// switch
|
||||
switch_to(chosen.?);
|
||||
// borrow the current task
|
||||
const borrow = current_task;
|
||||
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue