Step 6: block/unblock tasks
This commit is contained in:
parent
f2d2ab867e
commit
a527695202
3 changed files with 48 additions and 35 deletions
|
|
@ -31,5 +31,6 @@ export fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn {
|
||||||
while (true) {
|
while (true) {
|
||||||
task.lock_scheduler();
|
task.lock_scheduler();
|
||||||
task.schedule();
|
task.schedule();
|
||||||
|
if (time.offset_us / 1000000 == 6) task.unblock(task.blocked_tasks.first.?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
80
src/task.zig
80
src/task.zig
|
|
@ -3,13 +3,9 @@ pub usingnamespace @import("index.zig");
|
||||||
var timer_last_count: u64 = 0;
|
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 ListOfTasks = std.TailQueue(*Task);
|
const ListOfTasks = std.TailQueue(*Task);
|
||||||
var first_task = ListOfTasks.Node.init(&boot_task);
|
pub var current_task = &ListOfTasks.Node.init(&boot_task);
|
||||||
var current_task = &first_task;
|
pub var ready_tasks = ListOfTasks.init();
|
||||||
var tasks = ListOfTasks{
|
pub var blocked_tasks = ListOfTasks.init();
|
||||||
.first = &first_task,
|
|
||||||
.last = &first_task,
|
|
||||||
.len = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
const STACK_SIZE = x86.PAGE_SIZE; // Size of thread stacks.
|
const STACK_SIZE = x86.PAGE_SIZE; // Size of thread stacks.
|
||||||
var tid_counter: u16 = 1;
|
var tid_counter: u16 = 1;
|
||||||
|
|
@ -27,6 +23,7 @@ pub fn update_time_used() void {
|
||||||
pub const TaskState = enum {
|
pub const TaskState = enum {
|
||||||
Running,
|
Running,
|
||||||
ReadyToRun,
|
ReadyToRun,
|
||||||
|
Paused,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Task = struct {
|
pub const Task = struct {
|
||||||
|
|
@ -68,43 +65,58 @@ pub const Task = struct {
|
||||||
pub fn new(entrypoint: usize) !void {
|
pub fn new(entrypoint: usize) !void {
|
||||||
const node = try vmem.create(ListOfTasks.Node);
|
const node = try vmem.create(ListOfTasks.Node);
|
||||||
node.data = try Task.create(entrypoint);
|
node.data = try Task.create(entrypoint);
|
||||||
tasks.append(node);
|
ready_tasks.prepend(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn switch_to(new_task: *ListOfTasks.Node) void {
|
/// Block the current task
|
||||||
assert(new_task.data != current_task.data);
|
pub fn block(state: TaskState) void {
|
||||||
|
assert(state != .Running);
|
||||||
|
assert(state != .ReadyToRun);
|
||||||
|
|
||||||
|
lock_scheduler();
|
||||||
|
current_task.data.state = state;
|
||||||
|
schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unblock(node: *ListOfTasks.Node) void {
|
||||||
|
lock_scheduler();
|
||||||
|
node.data.state = .ReadyToRun;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn switch_to(chosen: *ListOfTasks.Node) void {
|
||||||
// save old stack
|
// save old stack
|
||||||
const old_task_esp_addr = ¤t_task.data.esp;
|
const old_task_esp_addr = ¤t_task.data.esp;
|
||||||
|
|
||||||
|
ready_tasks.remove(chosen);
|
||||||
// switch states
|
// switch states
|
||||||
current_task.data.state = .ReadyToRun;
|
switch (current_task.data.state) {
|
||||||
new_task.data.state = .Running;
|
.Running => ready_tasks.append(current_task),
|
||||||
current_task = new_task;
|
else => blocked_tasks.append(current_task),
|
||||||
|
}
|
||||||
|
chosen.data.state = .Running;
|
||||||
|
current_task = chosen;
|
||||||
|
|
||||||
unlock_scheduler();
|
unlock_scheduler();
|
||||||
|
|
||||||
// don't inline the asm function, it needs to ret
|
// don't inline the asm function, it needs to ret
|
||||||
@noInlineCall(switch_tasks, new_task.data.esp, @ptrToInt(old_task_esp_addr));
|
@noInlineCall(switch_tasks, chosen.data.esp, @ptrToInt(old_task_esp_addr));
|
||||||
}
|
|
||||||
|
|
||||||
// circular next
|
|
||||||
pub fn next(node: *ListOfTasks.Node) ?*ListOfTasks.Node {
|
|
||||||
return if (node.next) |n| n else tasks.first;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn first_ready_to_run() ?*ListOfTasks.Node {
|
|
||||||
var node = current_task;
|
|
||||||
while (next(node)) |n| {
|
|
||||||
if (n.data.state == .ReadyToRun) return n;
|
|
||||||
if (n.data.state == .Running) return null;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn schedule() void {
|
pub fn schedule() void {
|
||||||
update_time_used();
|
update_time_used();
|
||||||
if (first_ready_to_run()) |t| switch_to(t);
|
if (ready_tasks.first) |t| {
|
||||||
|
switch_to(t);
|
||||||
|
} else {
|
||||||
|
unlock_scheduler();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var IRQ_disable_counter: usize = 0;
|
var IRQ_disable_counter: usize = 0;
|
||||||
|
|
@ -116,10 +128,6 @@ pub fn lock_scheduler() void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn unlock_scheduler() void {
|
pub fn unlock_scheduler() void {
|
||||||
if (IRQ_disable_counter == 0) {
|
|
||||||
println("trying to unlock here");
|
|
||||||
while (true) asm volatile ("hlt");
|
|
||||||
}
|
|
||||||
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();
|
||||||
|
|
@ -129,8 +137,10 @@ pub fn unlock_scheduler() void {
|
||||||
pub fn introspect() void {
|
pub fn introspect() void {
|
||||||
update_time_used();
|
update_time_used();
|
||||||
|
|
||||||
var it = tasks.first;
|
println("{}", current_task.data);
|
||||||
println("{} tasks", tasks.len);
|
var it = ready_tasks.first;
|
||||||
|
while (it) |node| : (it = node.next) println("{}", node.data);
|
||||||
|
it = blocked_tasks.first;
|
||||||
while (it) |node| : (it = node.next) println("{}", node.data);
|
while (it) |node| : (it = node.next) println("{}", node.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,8 @@ pub fn clear() void {
|
||||||
pub fn topbar() void {
|
pub fn topbar() void {
|
||||||
const bg = vga.background;
|
const bg = vga.background;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
if (time.offset_us / 1000000 == 4) task.block(.Paused);
|
||||||
|
|
||||||
const cursor = vga.cursor;
|
const cursor = vga.cursor;
|
||||||
vga.cursor = 0;
|
vga.cursor = 0;
|
||||||
vga.background = Color.Red;
|
vga.background = Color.Red;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue