From 1b51942a12d7caa71809b8e7963b38aa7c58b94c Mon Sep 17 00:00:00 2001 From: ondra05 Date: Sun, 7 Aug 2022 23:42:23 +0200 Subject: [PATCH] So I have two news for you. One good and one bad. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have async, but we got rid of the preëmptive sched... wait, that's two good news, anyways, have a nice day. — Ondra --- Cargo.lock | 30 +++++++ ableos/src/arch/x86_64/interrupts.rs | 31 +------- ableos/src/arch/x86_64/mod.rs | 2 - ableos/src/arch/x86_64/task_switcher.rs | 99 ----------------------- ableos/src/kmain.rs | 13 +-- ableos/src/lib.rs | 1 - ableos/src/scheduler.rs | 46 ----------- kernel/Cargo.toml | 6 ++ kernel/src/lib.rs | 1 + kernel/src/task.rs | 101 ++++++++++++++++++++++++ repbuild/src/main.rs | 4 +- 11 files changed, 146 insertions(+), 188 deletions(-) delete mode 100644 ableos/src/arch/x86_64/task_switcher.rs delete mode 100644 ableos/src/scheduler.rs create mode 100644 kernel/src/task.rs diff --git a/Cargo.lock b/Cargo.lock index 01b48c70..1d304991 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,6 +203,25 @@ name = "cpuio" version = "0.3.2" source = "git+https://git.ablecorp.us/ondra05/cpuio.git#093cc103101b4ba4abd02d77c884113a376cdc64" +[[package]] +name = "crossbeam-queue" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +dependencies = [ + "cfg-if", +] + [[package]] name = "downcast-rs" version = "1.2.0" @@ -295,8 +314,10 @@ dependencies = [ name = "kernel" version = "0.1.2" dependencies = [ + "crossbeam-queue", "linked_list_allocator", "log", + "slab", "versioning", ] @@ -647,6 +668,15 @@ dependencies = [ "syn", ] +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + [[package]] name = "spin" version = "0.5.2" diff --git a/ableos/src/arch/x86_64/interrupts.rs b/ableos/src/arch/x86_64/interrupts.rs index 9f63f2ef..7ae3d3ec 100644 --- a/ableos/src/arch/x86_64/interrupts.rs +++ b/ableos/src/arch/x86_64/interrupts.rs @@ -98,34 +98,11 @@ extern "x86-interrupt" fn double_fault_handler( * As long as nothing in this function does something that would * normally trigger an error, this function is relatively safe. */ -#[naked] extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) { - use super::task_switcher; + crate::kmain::tick(); unsafe { - asm!( - - - // "call {disable}", - // Kernel tick - "call {tick}", - - // Push task's state onto stack - // and save task pointer into scheduler - task_switcher::save_tasks_state!(), - "mov rdi, rsp", - "call {save}", - - // "call {enable}", - // Switch to next task (interrupt'll be returned there) - "jmp {switch_to_next}", - - tick = sym crate::kmain::tick, - save = sym task_switcher::save_and_enqueue, - // disable = sym x86_64::instructions::interrupts::disable, - // enable = sym x86_64::instructions::interrupts::enable, - switch_to_next = sym task_switcher::switch_to_next, - options(noreturn), - ); + PICS.lock() + .notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); } } @@ -192,7 +169,7 @@ pub fn init_idt() { } /// https://wiki.osdev.org/Pit -/// +/// const PIT_MAX_FREQ: u32 = 1193182; pub fn set_pit_frequency(pit: u16, freq: u32) { diff --git a/ableos/src/arch/x86_64/mod.rs b/ableos/src/arch/x86_64/mod.rs index 6ebf783d..ce008fa9 100644 --- a/ableos/src/arch/x86_64/mod.rs +++ b/ableos/src/arch/x86_64/mod.rs @@ -10,8 +10,6 @@ pub mod init; pub mod interrupts; pub mod memory; -mod task_switcher; - use crate::arch::drivers::allocator; use bootloader::{entry_point, BootInfo}; use x86_64::{instructions::hlt, VirtAddr}; diff --git a/ableos/src/arch/x86_64/task_switcher.rs b/ableos/src/arch/x86_64/task_switcher.rs deleted file mode 100644 index eb0ea9d1..00000000 --- a/ableos/src/arch/x86_64/task_switcher.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::scheduler::{Task, SCHEDULER}; - -/// Saves task's state onto stack -macro_rules! save_tasks_state { - () => { - " - // Copy task's state - push [rsp + 32] // SS - push [rsp + 32] // RSP - push [rsp + 32] // RFLAGS - push [rsp + 32] // CS - push [rsp + 32] // RIP - - // Save task's registers - push r15 - push r14 - push r13 - push r12 - push r11 - push r10 - push r9 - push r8 - push rdi - push rsi - push rdx - push rcx - push rbx - push rax - " - }; -} - -pub(super) use save_tasks_state; - -/// Save provided stack pointer into scheduler's queue -pub extern "C" fn save_and_enqueue(sp: u64) { - SCHEDULER.lock().enqueue_suspended(sp); -} - -// Fetch and load next task -pub unsafe extern "C" fn switch_to_next() -> ! { - // Fetch next task - let next = SCHEDULER.lock().pop().expect("no task in the task queue"); - match next { - Task::Suspended(sp) => asm!( - // Restore task's registers - "mov rsp, {}", - "pop rax", - "pop rbx", - "pop rcx", - "pop rdx", - "pop rsi", - "pop rdi", - "pop r8", - "pop r9", - "pop r10", - "pop r11", - "pop r12", - "pop r13", - "pop r14", - "pop r15", - - // Copy things up the stack - "add rsp, 80", // Move 8 bytes above exception stack frame - "push [rsp - 48]", // SS - "push [rsp - 48]", // RSP - "push [rsp - 48]", // RFLAGS - "push [rsp - 48]", // CS - "push [rsp - 48]", // RIP - - // Signalise end of the interrupt and return - "push rax", - "mov al, 32", - "out 20h, al", - "pop rax", - "iretq", - - in(reg) sp, - options(noreturn), - ), - Task::Spawn { - function, - stack_start, - } => asm!( - "add rsp, 160", // Move above saved registries - "mov [rsp], {ip}", // Set task's instruction pointer - "mov [rsp + 24], {sp}", // Set task's stack pointer - - // Signalise the end of the interrupt and return - "mov al, 32", - "out 20h, al", - "iretq", - - ip = in(reg) function, - sp = in(reg) stack_start, - options(noreturn), - ), - } -} diff --git a/ableos/src/kmain.rs b/ableos/src/kmain.rs index 195ed833..9a4cc1d2 100644 --- a/ableos/src/kmain.rs +++ b/ableos/src/kmain.rs @@ -6,7 +6,7 @@ use crate::arch::{drivers::sysinfo::master, init, sloop}; use crate::hardware; use crate::relib::network::socket::{SimpleSock, Socket}; use crate::{ - boot_conf::KernelConfig, scheduler::SCHEDULER, scratchpad, systeminfo::RELEASE_TYPE, TERM, + boot_conf::KernelConfig, scratchpad, systeminfo::RELEASE_TYPE, TERM, }; use kernel::KERNEL_VERSION; use spin::Lazy; @@ -66,16 +66,7 @@ pub fn kernel_main() -> ! { /* log_version_data(); // */ - x86_64::instructions::interrupts::without_interrupts(|| { - let mut scheduler = SCHEDULER.lock(); - // comment this out to resume normal use - // scheduler.enqueue_spawn(traceloop); - - scheduler.enqueue_spawn(scratchpad); - }); - - // scratchpad(); - + scratchpad(); sloop() } diff --git a/ableos/src/lib.rs b/ableos/src/lib.rs index 97f12a6e..2ab6915a 100644 --- a/ableos/src/lib.rs +++ b/ableos/src/lib.rs @@ -66,7 +66,6 @@ pub mod prelude; pub mod ps2_mouse; pub mod relib; pub mod rhai_shell; -pub mod scheduler; pub mod scratchpad; pub mod stdio; pub mod time; diff --git a/ableos/src/scheduler.rs b/ableos/src/scheduler.rs deleted file mode 100644 index ea709917..00000000 --- a/ableos/src/scheduler.rs +++ /dev/null @@ -1,46 +0,0 @@ -use alloc::collections::VecDeque; -use spin::{Lazy, Mutex}; - -pub static SCHEDULER: Lazy> = Lazy::new(|| Mutex::new(Scheduler::default())); - -/// Task's stack size (in kiB) -const STACK_SIZE: usize = 512; - -pub enum Task { - Suspended(u64), - Spawn { function: fn(), stack_start: usize }, -} - -#[derive(Default)] -pub struct Scheduler { - task_queue: VecDeque, -} - -impl Scheduler { - pub fn enqueue_spawn(&mut self, function: fn()) { - self.task_queue.push_back(Task::Spawn { - function, - stack_start: unsafe { - let size = STACK_SIZE * 1024; - alloc::alloc::alloc( - alloc::alloc::Layout::from_size_align(size, 1).expect("invalid layout"), - ) - .add(size - 1) as _ - }, - }); - } - - pub fn enqueue_suspended(&mut self, sp: u64) { - self.task_queue.push_back(Task::Suspended(sp)); - } - - pub fn pop(&mut self) -> Option { - self.task_queue.pop_front() - } -} - -pub enum WakeConditions { - Time, - ReceivedMessageInChannel, - GainedAccessToChannel, -} diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 8a86d749..d2c0d1cd 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -6,6 +6,12 @@ version = "0.1.2" [dependencies] linked_list_allocator = "0.9" log = "0.4.14" +slab = { version = "0.4", default-features = false } + +[dependencies.crossbeam-queue] +version = "0.3" +default-features = false +features = ["alloc"] [dependencies.versioning] git = "https://git.ablecorp.us/able/aos_userland" diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 9b89327a..e354bda0 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -16,6 +16,7 @@ pub mod messaging; // pub mod panic; pub mod proccess; pub mod syscalls; +pub mod task; pub mod time; use core::arch::asm; diff --git a/kernel/src/task.rs b/kernel/src/task.rs new file mode 100644 index 00000000..39f26d15 --- /dev/null +++ b/kernel/src/task.rs @@ -0,0 +1,101 @@ +//! Async task and executor + +use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake}; +use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, Waker}, +}; +use crossbeam_queue::SegQueue; +use slab::Slab; + +type TaskQueue = Arc>; + +/// Tasks executor +#[derive(Default)] +pub struct Executor { + /// All spawned tasks' stash + tasks: Slab, + + /// Awake tasks' queue + queue: TaskQueue, + + /// Wakers + wakers: BTreeMap, +} + +impl Executor { + /// Spawn a future + pub fn spawn(&mut self, future: impl Future + 'static) { + self.queue + .push(TaskId(self.tasks.insert(Task::new(future)))); + } + + /// Run tasks + pub fn run(&mut self) -> ! { + loop { + while let Some(id) = self.queue.pop() { + let task = match self.tasks.get_mut(id.0) { + Some(t) => t, + None => continue, + }; + + let mut cx = Context::from_waker( + self.wakers + .entry(id) + .or_insert_with(|| TaskWaker::new(id, Arc::clone(&self.queue))), + ); + + match task.poll(&mut cx) { + Poll::Ready(()) => { + self.tasks.remove(id.0); + self.wakers.remove(&id); + } + Poll::Pending => (), + } + } + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +struct TaskId(usize); + +/// Async task +struct Task { + future: Pin>>, +} + +impl Task { + /// Create a new task from a future + fn new(future: impl Future + 'static) -> Self { + Self { + future: Box::pin(future), + } + } + + fn poll(&mut self, cx: &mut Context) -> Poll<()> { + self.future.as_mut().poll(cx) + } +} + +struct TaskWaker { + id: TaskId, + queue: TaskQueue, +} + +impl TaskWaker { + fn new(id: TaskId, queue: TaskQueue) -> Waker { + Waker::from(Arc::new(Self { id, queue })) + } +} + +impl Wake for TaskWaker { + fn wake(self: Arc) { + self.wake_by_ref(); + } + + fn wake_by_ref(self: &Arc) { + self.queue.push(self.id); + } +} diff --git a/repbuild/src/main.rs b/repbuild/src/main.rs index b8dc610b..2deb7793 100644 --- a/repbuild/src/main.rs +++ b/repbuild/src/main.rs @@ -29,8 +29,8 @@ impl Subcommand { match str.as_ref() { "doc" => Subcommand::Doc, "help" => Subcommand::Help, - "run" => Subcommand::Run, - "test" => Subcommand::Test, + "run" | "r" => Subcommand::Run, + "test" | "t" => Subcommand::Test, "" => Subcommand::Empty, unknown => Subcommand::Unknown(unknown.to_string()), }