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 {
|
pub fn sti() void {
|
||||||
asm volatile ("sti");
|
asm volatile ("sti");
|
||||||
}
|
}
|
||||||
|
pub inline fn hlt() void {
|
||||||
|
asm volatile ("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
pub inline fn int3() void {
|
pub inline fn int3() void {
|
||||||
asm volatile ("int3");
|
asm volatile ("int3");
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,10 @@ var input_write_index: u10 = 0;
|
||||||
var command: [10]u8 = undefined;
|
var command: [10]u8 = undefined;
|
||||||
var command_len: usize = 0;
|
var command_len: usize = 0;
|
||||||
|
|
||||||
|
fn sleep_for_2() void {
|
||||||
|
task.usleep(2 * 1000 * 1000) catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
fn execute(input: []u8) void {
|
fn execute(input: []u8) void {
|
||||||
const eql = std.mem.eql;
|
const eql = std.mem.eql;
|
||||||
if (eql(u8, input, "clear")) return vga.clear();
|
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();
|
||||||
if (eql(u8, input, "tasks")) return task.format_short();
|
if (eql(u8, input, "tasks")) return task.format_short();
|
||||||
if (eql(u8, input, "lspci")) return pci.lspci();
|
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();
|
if (eql(u8, input, "uptime")) return time.uptime();
|
||||||
println("{}: command not found", input);
|
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();
|
pci.scan();
|
||||||
|
|
||||||
task.new(@ptrToInt(topbar)) catch unreachable;
|
task.new(@ptrToInt(topbar)) catch unreachable;
|
||||||
task.new(@ptrToInt(console.loop)) catch unreachable;
|
// task.new(@ptrToInt(console.loop)) catch unreachable;
|
||||||
|
|
||||||
while (true) {
|
console.loop();
|
||||||
task.lock_scheduler();
|
unreachable;
|
||||||
task.schedule();
|
// while (true) {
|
||||||
}
|
// task.lock_scheduler();
|
||||||
|
// task.schedule();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn panic(a: []const u8, b: ?*builtin.StackTrace) noreturn {
|
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");
|
pub usingnamespace @import("index.zig");
|
||||||
|
|
||||||
var timer_last_count: u64 = 0;
|
|
||||||
var boot_task = Task{ .tid = 0, .esp = 0x47, .state = .Running };
|
var boot_task = Task{ .tid = 0, .esp = 0x47, .state = .Running };
|
||||||
|
|
||||||
const TaskNode = std.TailQueue(*Task).Node;
|
const TaskNode = std.TailQueue(*Task).Node;
|
||||||
|
|
@ -17,6 +16,7 @@ var tid_counter: u16 = 1;
|
||||||
///ASM
|
///ASM
|
||||||
extern fn switch_tasks(new_esp: u32, old_esp_addr: u32) void;
|
extern fn switch_tasks(new_esp: u32, old_esp_addr: u32) void;
|
||||||
|
|
||||||
|
var timer_last_count: u64 = 0;
|
||||||
pub fn update_time_used() void {
|
pub fn update_time_used() void {
|
||||||
const current_count = time.offset_us;
|
const current_count = time.offset_us;
|
||||||
const elapsed = current_count - timer_last_count;
|
const elapsed = current_count - timer_last_count;
|
||||||
|
|
@ -114,7 +114,7 @@ pub fn unblock(node: *TaskNode) void {
|
||||||
pub fn switch_to(chosen: *TaskNode) void {
|
pub fn switch_to(chosen: *TaskNode) void {
|
||||||
assert(chosen.data.state == .ReadyToRun);
|
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) {
|
if (current_task.data.state == .Running) {
|
||||||
current_task.data.state = .ReadyToRun;
|
current_task.data.state = .ReadyToRun;
|
||||||
ready_tasks.append(current_task);
|
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));
|
@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 {
|
pub fn schedule() void {
|
||||||
assert(IRQ_disable_counter > 0);
|
assert(IRQ_disable_counter > 0);
|
||||||
|
|
||||||
update_time_used();
|
update_time_used();
|
||||||
|
|
||||||
// check if somebody wants to run
|
if (ready_tasks.popFirst()) |t| {
|
||||||
const chosen = ready_tasks.popFirst();
|
// somebody is ready to run
|
||||||
if (chosen == null) return unlock_scheduler();
|
|
||||||
|
|
||||||
// std doesn't do this, for developer flexibility maybe?
|
// std doesn't do this, for developer flexibility maybe?
|
||||||
chosen.?.prev = null;
|
t.prev = null;
|
||||||
chosen.?.next = 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
|
// borrow the current task
|
||||||
switch_to(chosen.?);
|
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;
|
var IRQ_disable_counter: usize = 0;
|
||||||
|
|
@ -158,6 +203,7 @@ pub fn lock_scheduler() void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn unlock_scheduler() void {
|
pub fn unlock_scheduler() void {
|
||||||
|
if (IRQ_disable_counter == 0) println("error trying to unlock");
|
||||||
if (constants.SMP == false) {
|
if (constants.SMP == false) {
|
||||||
IRQ_disable_counter -= 1;
|
IRQ_disable_counter -= 1;
|
||||||
if (IRQ_disable_counter == 0) x86.sti();
|
if (IRQ_disable_counter == 0) x86.sti();
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ pub fn topbar() void {
|
||||||
vga.cursor = cursor;
|
vga.cursor = cursor;
|
||||||
vga.background = bg;
|
vga.background = bg;
|
||||||
|
|
||||||
task.usleep(60 * 1000) catch unreachable; // 60ms
|
task.usleep(500 * 1000) catch unreachable; // 60ms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue