forked from AbleOS/ableos
So I have two news for you. One good and one bad.
We have async, but we got rid of the preëmptive sched... wait, that's two good news, anyways, have a nice day. — Erin
This commit is contained in:
parent
8e09af7f15
commit
cd8e6e4b3b
30
Cargo.lock
generated
30
Cargo.lock
generated
|
@ -203,6 +203,25 @@ name = "cpuio"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
source = "git+https://git.ablecorp.us/ondra05/cpuio.git#093cc103101b4ba4abd02d77c884113a376cdc64"
|
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]]
|
[[package]]
|
||||||
name = "downcast-rs"
|
name = "downcast-rs"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -295,8 +314,10 @@ dependencies = [
|
||||||
name = "kernel"
|
name = "kernel"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"crossbeam-queue",
|
||||||
"linked_list_allocator",
|
"linked_list_allocator",
|
||||||
"log",
|
"log",
|
||||||
|
"slab",
|
||||||
"versioning",
|
"versioning",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -647,6 +668,15 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
|
|
@ -98,34 +98,11 @@ extern "x86-interrupt" fn double_fault_handler(
|
||||||
* As long as nothing in this function does something that would
|
* As long as nothing in this function does something that would
|
||||||
* normally trigger an error, this function is relatively safe.
|
* normally trigger an error, this function is relatively safe.
|
||||||
*/
|
*/
|
||||||
#[naked]
|
|
||||||
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||||
use super::task_switcher;
|
crate::kmain::tick();
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
PICS.lock()
|
||||||
|
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
|
||||||
|
|
||||||
// "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),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +169,7 @@ pub fn init_idt() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://wiki.osdev.org/Pit
|
/// https://wiki.osdev.org/Pit
|
||||||
///
|
///
|
||||||
const PIT_MAX_FREQ: u32 = 1193182;
|
const PIT_MAX_FREQ: u32 = 1193182;
|
||||||
|
|
||||||
pub fn set_pit_frequency(pit: u16, freq: u32) {
|
pub fn set_pit_frequency(pit: u16, freq: u32) {
|
||||||
|
|
|
@ -10,8 +10,6 @@ pub mod init;
|
||||||
pub mod interrupts;
|
pub mod interrupts;
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
|
|
||||||
mod task_switcher;
|
|
||||||
|
|
||||||
use crate::arch::drivers::allocator;
|
use crate::arch::drivers::allocator;
|
||||||
use bootloader::{entry_point, BootInfo};
|
use bootloader::{entry_point, BootInfo};
|
||||||
use x86_64::{instructions::hlt, VirtAddr};
|
use x86_64::{instructions::hlt, VirtAddr};
|
||||||
|
|
|
@ -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),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,7 @@ use crate::arch::{drivers::sysinfo::master, init, sloop};
|
||||||
use crate::hardware;
|
use crate::hardware;
|
||||||
use crate::relib::network::socket::{SimpleSock, Socket};
|
use crate::relib::network::socket::{SimpleSock, Socket};
|
||||||
use crate::{
|
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 kernel::KERNEL_VERSION;
|
||||||
use spin::Lazy;
|
use spin::Lazy;
|
||||||
|
@ -66,16 +66,7 @@ pub fn kernel_main() -> ! {
|
||||||
/*
|
/*
|
||||||
log_version_data();
|
log_version_data();
|
||||||
// */
|
// */
|
||||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
scratchpad();
|
||||||
let mut scheduler = SCHEDULER.lock();
|
|
||||||
// comment this out to resume normal use
|
|
||||||
// scheduler.enqueue_spawn(traceloop);
|
|
||||||
|
|
||||||
scheduler.enqueue_spawn(scratchpad);
|
|
||||||
});
|
|
||||||
|
|
||||||
// scratchpad();
|
|
||||||
|
|
||||||
sloop()
|
sloop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,6 @@ pub mod prelude;
|
||||||
pub mod ps2_mouse;
|
pub mod ps2_mouse;
|
||||||
pub mod relib;
|
pub mod relib;
|
||||||
pub mod rhai_shell;
|
pub mod rhai_shell;
|
||||||
pub mod scheduler;
|
|
||||||
pub mod scratchpad;
|
pub mod scratchpad;
|
||||||
pub mod stdio;
|
pub mod stdio;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
use alloc::collections::VecDeque;
|
|
||||||
use spin::{Lazy, Mutex};
|
|
||||||
|
|
||||||
pub static SCHEDULER: Lazy<Mutex<Scheduler>> = 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<Task>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<Task> {
|
|
||||||
self.task_queue.pop_front()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum WakeConditions {
|
|
||||||
Time,
|
|
||||||
ReceivedMessageInChannel,
|
|
||||||
GainedAccessToChannel,
|
|
||||||
}
|
|
|
@ -6,6 +6,12 @@ version = "0.1.2"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
linked_list_allocator = "0.9"
|
linked_list_allocator = "0.9"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
|
slab = { version = "0.4", default-features = false }
|
||||||
|
|
||||||
|
[dependencies.crossbeam-queue]
|
||||||
|
version = "0.3"
|
||||||
|
default-features = false
|
||||||
|
features = ["alloc"]
|
||||||
|
|
||||||
[dependencies.versioning]
|
[dependencies.versioning]
|
||||||
git = "https://git.ablecorp.us/able/aos_userland"
|
git = "https://git.ablecorp.us/able/aos_userland"
|
||||||
|
|
|
@ -16,6 +16,7 @@ pub mod messaging;
|
||||||
// pub mod panic;
|
// pub mod panic;
|
||||||
pub mod proccess;
|
pub mod proccess;
|
||||||
pub mod syscalls;
|
pub mod syscalls;
|
||||||
|
pub mod task;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
|
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
|
|
101
kernel/src/task.rs
Normal file
101
kernel/src/task.rs
Normal file
|
@ -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<SegQueue<TaskId>>;
|
||||||
|
|
||||||
|
/// Tasks executor
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Executor {
|
||||||
|
/// All spawned tasks' stash
|
||||||
|
tasks: Slab<Task>,
|
||||||
|
|
||||||
|
/// Awake tasks' queue
|
||||||
|
queue: TaskQueue,
|
||||||
|
|
||||||
|
/// Wakers
|
||||||
|
wakers: BTreeMap<TaskId, Waker>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Executor {
|
||||||
|
/// Spawn a future
|
||||||
|
pub fn spawn(&mut self, future: impl Future<Output = ()> + '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<Box<dyn Future<Output = ()>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Task {
|
||||||
|
/// Create a new task from a future
|
||||||
|
fn new(future: impl Future<Output = ()> + '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>) {
|
||||||
|
self.wake_by_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wake_by_ref(self: &Arc<Self>) {
|
||||||
|
self.queue.push(self.id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,8 +29,8 @@ impl Subcommand {
|
||||||
match str.as_ref() {
|
match str.as_ref() {
|
||||||
"doc" => Subcommand::Doc,
|
"doc" => Subcommand::Doc,
|
||||||
"help" => Subcommand::Help,
|
"help" => Subcommand::Help,
|
||||||
"run" => Subcommand::Run,
|
"run" | "r" => Subcommand::Run,
|
||||||
"test" => Subcommand::Test,
|
"test" | "t" => Subcommand::Test,
|
||||||
"" => Subcommand::Empty,
|
"" => Subcommand::Empty,
|
||||||
unknown => Subcommand::Unknown(unknown.to_string()),
|
unknown => Subcommand::Unknown(unknown.to_string()),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue