core: Add sleep support to the scheduler
This commit is contained in:
parent
8f6c952331
commit
b87150a35f
@ -20,7 +20,8 @@ pub fn setupCore(allocator: *pmm.FrameAllocator) !void {
|
||||
|
||||
const core: *arch.Core = @ptrFromInt(frame.virtualAddress(vmm.PHYSICAL_MAPPING_BASE));
|
||||
core.id = 0; // FIXME: Actually check core id
|
||||
core.thread_list = .{};
|
||||
core.active_thread_list = .{};
|
||||
core.sleeping_thread_list = .{};
|
||||
|
||||
const idle_thread = &core.idle_thread.data;
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
const thread = @import("../../thread.zig");
|
||||
|
||||
pub const Core = struct { id: u32, thread_list: thread.ThreadList, current_thread: *thread.ThreadControlBlock, idle_thread: thread.ThreadList.Node };
|
||||
pub const Core = struct { id: u32, active_thread_list: thread.ThreadList, sleeping_thread_list: thread.ThreadList, current_thread: *thread.ThreadControlBlock, idle_thread: thread.ThreadList.Node };
|
||||
|
@ -73,8 +73,6 @@ export fn _start(magic: u32, info: MultibootInfo) callconv(.C) noreturn {
|
||||
thread.arch.initUserRegisters(&init.regs);
|
||||
thread.arch.setArgument(&init.regs, base);
|
||||
|
||||
thread.addThreadToScheduler(cpu.thisCore(), init);
|
||||
|
||||
const ctx = Context{ .allocator = &allocator, .mapper = mapper, .regs = &init.regs };
|
||||
|
||||
multiboot.findMultibootTags(easyboot.multiboot_tag_module_t, @ptrCast(info), struct {
|
||||
|
@ -19,3 +19,7 @@ pub fn getPriority(_: *interrupts.InterruptStackFrame, _: *sys.Arguments, retval
|
||||
const core = cpu.thisCore();
|
||||
retval.* = core.current_thread.user_priority;
|
||||
}
|
||||
|
||||
pub fn sleep(regs: *interrupts.InterruptStackFrame, args: *sys.Arguments, _: *isize) anyerror!void {
|
||||
_ = thread.startSleep(regs, args.arg0);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ pub const Arguments = struct {
|
||||
|
||||
const SystemCall = *const fn (frame: *interrupts.InterruptStackFrame, args: *Arguments, retval: *isize) anyerror!void;
|
||||
|
||||
const syscalls = [_]SystemCall{ print, mem.allocFrame, mem.lockFrame, mem.freeFrame, sched.yield, sched.setPriority, sched.getPriority };
|
||||
const syscalls = [_]SystemCall{ print, mem.allocFrame, mem.lockFrame, mem.freeFrame, sched.yield, sched.setPriority, sched.getPriority, sched.sleep };
|
||||
|
||||
pub fn invokeSyscall(number: usize, frame: *interrupts.InterruptStackFrame, args: *Arguments, retval: *isize) void {
|
||||
if (number >= syscalls.len) {
|
||||
|
@ -9,6 +9,7 @@ pub const ThreadState = enum {
|
||||
Inactive,
|
||||
Running,
|
||||
Blocked,
|
||||
Sleeping,
|
||||
};
|
||||
|
||||
pub const ThreadControlBlock = struct {
|
||||
@ -21,6 +22,8 @@ pub const ThreadControlBlock = struct {
|
||||
|
||||
user_priority: u8,
|
||||
current_priority: u32,
|
||||
|
||||
sleep_ticks: u64,
|
||||
};
|
||||
|
||||
pub const ThreadList = std.DoublyLinkedList(ThreadControlBlock);
|
||||
@ -57,7 +60,7 @@ pub fn switchTask(regs: *interrupts.InterruptStackFrame, new_task: *ThreadContro
|
||||
}
|
||||
|
||||
pub fn fetchNewTask(core: *cpu.arch.Core, should_idle_if_not_found: bool) ?*ThreadControlBlock {
|
||||
const last = core.thread_list.last orelse {
|
||||
const last = core.active_thread_list.last orelse {
|
||||
if (should_idle_if_not_found) {
|
||||
return &core.idle_thread.data;
|
||||
} else return null;
|
||||
@ -71,7 +74,7 @@ pub fn fetchNewTask(core: *cpu.arch.Core, should_idle_if_not_found: bool) ?*Thre
|
||||
}
|
||||
|
||||
pub fn scheduleNewTask(core: *cpu.arch.Core, regs: *interrupts.InterruptStackFrame, new_thread: *ThreadControlBlock) *ThreadControlBlock {
|
||||
if (core.thread_list.first) |first| {
|
||||
if (core.active_thread_list.first) |first| {
|
||||
first.data.current_priority +|= 4;
|
||||
}
|
||||
|
||||
@ -85,6 +88,11 @@ pub fn scheduleNewTask(core: *cpu.arch.Core, regs: *interrupts.InterruptStackFra
|
||||
pub fn preempt(regs: *interrupts.InterruptStackFrame) void {
|
||||
const core = cpu.thisCore();
|
||||
|
||||
updateSleepQueue(core);
|
||||
while (popSleepQueue(core)) |thread| {
|
||||
reviveThread(core, thread);
|
||||
}
|
||||
|
||||
core.current_thread.ticks -|= 1;
|
||||
if (core.current_thread.ticks == 0) {
|
||||
const new_thread = fetchNewTask(core, false) orelse return;
|
||||
@ -93,12 +101,81 @@ pub fn preempt(regs: *interrupts.InterruptStackFrame) void {
|
||||
}
|
||||
}
|
||||
|
||||
var next_id: std.atomic.Value(u64) = std.atomic.Value(u64).init(1);
|
||||
pub fn block(regs: *interrupts.InterruptStackFrame) *ThreadControlBlock {
|
||||
const core = cpu.thisCore();
|
||||
|
||||
pub fn addThreadToScheduler(core: *cpu.arch.Core, thread: *ThreadControlBlock) void {
|
||||
// fetchNewTask() always returns a thread if should_idle_if_not_found is set to true.
|
||||
const new_thread = fetchNewTask(core, true) orelse unreachable;
|
||||
const current_thread = scheduleNewTask(core, regs, new_thread);
|
||||
current_thread.state = .Blocked;
|
||||
|
||||
return current_thread;
|
||||
}
|
||||
|
||||
pub fn startSleep(regs: *interrupts.InterruptStackFrame, ticks: u64) *ThreadControlBlock {
|
||||
const core = cpu.thisCore();
|
||||
|
||||
// fetchNewTask() always returns a thread if should_idle_if_not_found is set to true.
|
||||
const new_thread = fetchNewTask(core, true) orelse unreachable;
|
||||
const current_thread = scheduleNewTask(core, regs, new_thread);
|
||||
current_thread.state = .Sleeping;
|
||||
addThreadToSleepQueue(core, current_thread, ticks);
|
||||
|
||||
return current_thread;
|
||||
}
|
||||
|
||||
pub fn addThreadToSleepQueue(core: *cpu.arch.Core, thread: *ThreadControlBlock, ticks: u64) void {
|
||||
thread.sleep_ticks = ticks;
|
||||
|
||||
var it: ?*ThreadList.Node = core.sleeping_thread_list.first;
|
||||
while (it) |n| : (it = n.next) {
|
||||
if (thread.sleep_ticks <= n.data.sleep_ticks) {
|
||||
n.data.sleep_ticks -|= thread.sleep_ticks;
|
||||
core.sleeping_thread_list.insertBefore(n, @fieldParentPtr("data", thread));
|
||||
return;
|
||||
}
|
||||
thread.sleep_ticks -|= n.data.sleep_ticks;
|
||||
}
|
||||
|
||||
core.sleeping_thread_list.append(@fieldParentPtr("data", thread));
|
||||
}
|
||||
|
||||
pub fn removeThreadFromSleepQueue(core: *cpu.arch.Core, thread: *ThreadControlBlock) void {
|
||||
const node: *ThreadList.Node = @fieldParentPtr("data", thread);
|
||||
|
||||
if (node.next) |n| {
|
||||
n.data.sleep_ticks +|= thread.sleep_ticks;
|
||||
}
|
||||
|
||||
core.sleeping_thread_list.remove(node);
|
||||
|
||||
reviveThread(core, thread);
|
||||
}
|
||||
|
||||
pub fn updateSleepQueue(core: *cpu.arch.Core) void {
|
||||
const first = core.sleeping_thread_list.first orelse return;
|
||||
|
||||
first.data.sleep_ticks -|= 1;
|
||||
}
|
||||
|
||||
pub fn popSleepQueue(core: *cpu.arch.Core) ?*ThreadControlBlock {
|
||||
const first = core.sleeping_thread_list.first orelse return null;
|
||||
|
||||
if (first.data.sleep_ticks == 0) {
|
||||
core.sleeping_thread_list.remove(first);
|
||||
return &first.data;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn reviveThread(core: *cpu.arch.Core, thread: *ThreadControlBlock) void {
|
||||
thread.state = .Running;
|
||||
addThreadToPriorityQueue(core, thread);
|
||||
}
|
||||
|
||||
var next_id: std.atomic.Value(u64) = std.atomic.Value(u64).init(1);
|
||||
|
||||
pub fn createThreadControlBlock(allocator: *pmm.FrameAllocator) !*ThreadControlBlock {
|
||||
const frame = try pmm.allocFrame(allocator);
|
||||
|
||||
@ -116,17 +193,17 @@ pub fn createThreadControlBlock(allocator: *pmm.FrameAllocator) !*ThreadControlB
|
||||
pub fn addThreadToPriorityQueue(core: *cpu.arch.Core, thread: *ThreadControlBlock) void {
|
||||
thread.current_priority = thread.user_priority;
|
||||
|
||||
var it: ?*ThreadList.Node = core.thread_list.first;
|
||||
var it: ?*ThreadList.Node = core.active_thread_list.first;
|
||||
while (it) |n| : (it = n.next) {
|
||||
if (thread.current_priority <= n.data.current_priority) {
|
||||
n.data.current_priority -|= thread.current_priority;
|
||||
core.thread_list.insertBefore(n, @fieldParentPtr("data", thread));
|
||||
core.active_thread_list.insertBefore(n, @fieldParentPtr("data", thread));
|
||||
return;
|
||||
}
|
||||
thread.current_priority -|= n.data.current_priority;
|
||||
}
|
||||
|
||||
core.thread_list.append(@fieldParentPtr("data", thread));
|
||||
core.active_thread_list.append(@fieldParentPtr("data", thread));
|
||||
}
|
||||
|
||||
pub fn removeThreadFromPriorityQueue(core: *cpu.arch.Core, thread: *ThreadControlBlock) void {
|
||||
@ -136,5 +213,5 @@ pub fn removeThreadFromPriorityQueue(core: *cpu.arch.Core, thread: *ThreadContro
|
||||
n.data.current_priority +|= thread.current_priority;
|
||||
}
|
||||
|
||||
core.thread_list.remove(node);
|
||||
core.active_thread_list.remove(node);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ const SystemCall = enum(u64) {
|
||||
Yield,
|
||||
SetPriority,
|
||||
GetPriority,
|
||||
Sleep,
|
||||
};
|
||||
|
||||
const SystemError = error{
|
||||
@ -49,3 +50,7 @@ pub fn setPriority(priority: u8) void {
|
||||
pub fn getPriority() u8 {
|
||||
return @truncate(@as(u64, @bitCast(syscall(.GetPriority, 0))));
|
||||
}
|
||||
|
||||
pub fn sleep(ms: u64) void {
|
||||
_ = syscall(.Sleep, ms);
|
||||
}
|
||||
|
@ -4,10 +4,10 @@ export fn _start(base: u64) callconv(.C) noreturn {
|
||||
kernel.print(base);
|
||||
kernel.print(kernel.getPriority());
|
||||
|
||||
kernel.setPriority(128);
|
||||
kernel.print(kernel.getPriority());
|
||||
var counter: u64 = 0;
|
||||
|
||||
while (true) {
|
||||
kernel.yield();
|
||||
while (true) : (counter += 4) {
|
||||
kernel.sleep(1000);
|
||||
kernel.print(counter);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user