diff --git a/core/src/arch/cpu.zig b/core/src/arch/cpu.zig index 100cd80..0130910 100644 --- a/core/src/arch/cpu.zig +++ b/core/src/arch/cpu.zig @@ -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; diff --git a/core/src/arch/x86_64/cpu.zig b/core/src/arch/x86_64/cpu.zig index 9e806e2..a0eb369 100644 --- a/core/src/arch/x86_64/cpu.zig +++ b/core/src/arch/x86_64/cpu.zig @@ -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 }; diff --git a/core/src/main.zig b/core/src/main.zig index dcc3df5..7b88bee 100644 --- a/core/src/main.zig +++ b/core/src/main.zig @@ -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 { diff --git a/core/src/sys/sched.zig b/core/src/sys/sched.zig index 3587af9..5ba4235 100644 --- a/core/src/sys/sched.zig +++ b/core/src/sys/sched.zig @@ -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); +} diff --git a/core/src/sys/syscall.zig b/core/src/sys/syscall.zig index 663e1d3..7962ea8 100644 --- a/core/src/sys/syscall.zig +++ b/core/src/sys/syscall.zig @@ -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) { diff --git a/core/src/thread.zig b/core/src/thread.zig index bd02e36..af63cbe 100644 --- a/core/src/thread.zig +++ b/core/src/thread.zig @@ -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); } diff --git a/system/init/kernel.zig b/system/init/kernel.zig index 6e90838..200518b 100644 --- a/system/init/kernel.zig +++ b/system/init/kernel.zig @@ -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); +} diff --git a/system/init/main.zig b/system/init/main.zig index ed52b48..449e450 100644 --- a/system/init/main.zig +++ b/system/init/main.zig @@ -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); } }