Compare commits
0
Commits
No files matched your search
@@ -53,41 +53,7 @@ extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn syscall_handler_32(_stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn syscall_handler_32(_stack_frame: InterruptStackFrame) {
|
||||||
let rax: u64;
|
|
||||||
let rbx: u64;
|
|
||||||
let rcx: u64;
|
|
||||||
let rdx: u64;
|
|
||||||
let rsi: u64;
|
|
||||||
let rdi: u64;
|
|
||||||
let rbp: u64;
|
|
||||||
unsafe {
|
|
||||||
asm!(
|
|
||||||
"push rax",
|
|
||||||
"push rbx",
|
|
||||||
"push rcx",
|
|
||||||
"push rdx",
|
|
||||||
"push rsi",
|
|
||||||
"push rdi",
|
|
||||||
"push rbp",
|
|
||||||
|
|
||||||
"pop {rbp}",
|
|
||||||
"pop {rdi}",
|
|
||||||
"pop {rsi}",
|
|
||||||
"pop {rdx}",
|
|
||||||
"pop {rcx}",
|
|
||||||
"pop {rbx}",
|
|
||||||
"pop {rax}",
|
|
||||||
rax = out(reg) rax,
|
|
||||||
rbx = out(reg) rbx,
|
|
||||||
rcx = out(reg) rcx,
|
|
||||||
rdx = out(reg) rdx,
|
|
||||||
rsi = out(reg) rsi,
|
|
||||||
rdi = out(reg) rdi,
|
|
||||||
rbp = out(reg) rbp,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
println!("Received syscall");
|
println!("Received syscall");
|
||||||
crate::syscalls::syscall_routine(rax);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn page_fault_handler(
|
extern "x86-interrupt" fn page_fault_handler(
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ pub fn gettick() -> u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
pub extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||||
// TODO: thread preemption
|
|
||||||
unsafe {
|
unsafe {
|
||||||
TICKS += 1;
|
TICKS += 1;
|
||||||
PICS.lock()
|
PICS.lock()
|
||||||
|
|||||||
+10
-36
@@ -1,4 +1,3 @@
|
|||||||
use crate::println;
|
|
||||||
use crate::utils::mutex::AsyncMutex;
|
use crate::utils::mutex::AsyncMutex;
|
||||||
|
|
||||||
use super::thread::{Thread, ThreadId};
|
use super::thread::{Thread, ThreadId};
|
||||||
@@ -15,7 +14,6 @@ use futures_util::task::AtomicWaker;
|
|||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
// TODO: put this in a spin mutex instead
|
|
||||||
pub static ref SCHEDULER: AsyncMutex<Scheduler> = AsyncMutex::new(Scheduler::new());
|
pub static ref SCHEDULER: AsyncMutex<Scheduler> = AsyncMutex::new(Scheduler::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,9 +22,8 @@ pub type Threadt = Arc<RefCell<Thread>>;
|
|||||||
pub const K_THREAD_ID: ThreadId = ThreadId(0); // Kernel main thread identifier
|
pub const K_THREAD_ID: ThreadId = ThreadId(0); // Kernel main thread identifier
|
||||||
|
|
||||||
struct ThreadStream {
|
struct ThreadStream {
|
||||||
// TODO: add the double scheduler queue
|
|
||||||
ids: ArrayQueue<ThreadId>,
|
ids: ArrayQueue<ThreadId>,
|
||||||
waker: AtomicWaker,
|
waker: AtomicWaker
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThreadStream {
|
impl ThreadStream {
|
||||||
@@ -38,7 +35,9 @@ impl ThreadStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn register(&mut self, id: ThreadId) {
|
pub fn register(&mut self, id: ThreadId) {
|
||||||
self.ids.push(id).expect("Thread queue full");
|
self.ids
|
||||||
|
.push(id)
|
||||||
|
.expect("Thread queue full");
|
||||||
self.waker.wake();
|
self.waker.wake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,29 +79,19 @@ impl Scheduler {
|
|||||||
started: true,
|
started: true,
|
||||||
rsp: 0,
|
rsp: 0,
|
||||||
base_stack: 0,
|
base_stack: 0,
|
||||||
is_blocked: false,
|
|
||||||
};
|
};
|
||||||
res.register(Arc::new(RefCell::new(k_thread)));
|
res.register(Arc::new(RefCell::new(k_thread)));
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn run(&mut self) {
|
pub async fn run(&mut self) {
|
||||||
while let Some(id) = self.thread_queue.next().await {
|
while let Some(id) = self.thread_queue.next().await {
|
||||||
if let Some(thread) = self.get_thread(id) {
|
if let Some(thread) = self.get_thread(id) { // Thread still exists
|
||||||
// Thread still exists
|
unsafe {
|
||||||
let blocked: bool;
|
(&mut*thread.as_ptr()).run();
|
||||||
{
|
|
||||||
blocked = thread.borrow().is_blocked;
|
|
||||||
} // Drop thread borrow
|
|
||||||
if !blocked {
|
|
||||||
unsafe {
|
|
||||||
(&mut *thread.as_ptr()).run();
|
|
||||||
}
|
|
||||||
|
|
||||||
if !thread.borrow().is_blocked {
|
|
||||||
self.thread_queue.register(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
self.thread_queue.register(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,21 +106,6 @@ impl Scheduler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn block(&mut self, id: ThreadId) {
|
|
||||||
if let Some(thread) = self.get_thread(id) {
|
|
||||||
thread.borrow_mut().is_blocked = true;
|
|
||||||
println!("Blocked thread {:?}", id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unblock(&mut self, id: ThreadId) {
|
|
||||||
if let Some(thread) = self.get_thread(id) {
|
|
||||||
thread.borrow_mut().is_blocked = false;
|
|
||||||
self.thread_queue.register(id);
|
|
||||||
println!("Unblocked thread {:?}", id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exit(&mut self, id: ThreadId) {
|
pub fn exit(&mut self, id: ThreadId) {
|
||||||
self.threads.remove(&id).unwrap().borrow().exit();
|
self.threads.remove(&id).unwrap().borrow().exit();
|
||||||
}
|
}
|
||||||
@@ -149,4 +123,4 @@ pub async fn scheduler_run() {
|
|||||||
let mut scheduler = SCHEDULER.lock().await;
|
let mut scheduler = SCHEDULER.lock().await;
|
||||||
SCHEDULER.force_unlock();
|
SCHEDULER.force_unlock();
|
||||||
scheduler.run().await;
|
scheduler.run().await;
|
||||||
}
|
}
|
||||||
+21
-14
@@ -1,7 +1,7 @@
|
|||||||
use crate::println;
|
use crate::println;
|
||||||
use crate::utils::mutex::AsyncMutex;
|
use crate::utils::mutex::AsyncMutex;
|
||||||
|
|
||||||
use super::scheduler::{K_THREAD_ID, SCHEDULER};
|
use super::scheduler::{SCHEDULER, K_THREAD_ID};
|
||||||
|
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
use core::sync::atomic::{AtomicU64, Ordering};
|
use core::sync::atomic::{AtomicU64, Ordering};
|
||||||
@@ -25,22 +25,34 @@ impl ThreadId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn exit() {
|
||||||
|
println!("Exiting thread");
|
||||||
|
{
|
||||||
|
let mut scheduler = SCHEDULER.try_lock().unwrap();
|
||||||
|
scheduler.exit(*RUNNING_THREAD.try_lock().unwrap());
|
||||||
|
} // Drop scheduler mutex guard
|
||||||
|
|
||||||
|
resume_k_thread();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resume_k_thread() {
|
pub fn resume_k_thread() {
|
||||||
let k_thread: *mut Thread;
|
let k_thread: *mut Thread;
|
||||||
{
|
{
|
||||||
let mut scheduler = SCHEDULER.try_lock().unwrap();
|
let mut scheduler = SCHEDULER.try_lock().unwrap();
|
||||||
k_thread = scheduler.get_thread(K_THREAD_ID).unwrap().as_ptr();
|
k_thread = scheduler
|
||||||
|
.get_thread(K_THREAD_ID)
|
||||||
|
.unwrap()
|
||||||
|
.as_ptr();
|
||||||
} // Drop scheduler mutex guard
|
} // Drop scheduler mutex guard
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
(&mut *k_thread).run();
|
(&mut* k_thread).run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn routine() {
|
pub fn routine() {
|
||||||
println!("Routine executed");
|
println!("Routine executed");
|
||||||
crate::syscalls::syscall_routine(crate::syscalls::EXIT_ID); // Call exit
|
exit();
|
||||||
println!("SHOULD NEVER BE DISPLAYED");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Thread {
|
pub struct Thread {
|
||||||
@@ -48,8 +60,7 @@ pub struct Thread {
|
|||||||
pub entry_point: u64,
|
pub entry_point: u64,
|
||||||
pub started: bool,
|
pub started: bool,
|
||||||
pub rsp: u64,
|
pub rsp: u64,
|
||||||
pub base_stack: u64,
|
pub base_stack: u64
|
||||||
pub is_blocked: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Thread {
|
impl Thread {
|
||||||
@@ -62,17 +73,13 @@ impl Thread {
|
|||||||
started: false,
|
started: false,
|
||||||
rsp: stack_bottom + STACK_SIZE as u64,
|
rsp: stack_bottom + STACK_SIZE as u64,
|
||||||
base_stack: stack_bottom,
|
base_stack: stack_bottom,
|
||||||
is_blocked: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit(&self) {
|
pub fn exit(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
dealloc(
|
dealloc(self.base_stack as *mut u8, Layout::new::<[u8; STACK_SIZE]>());
|
||||||
self.base_stack as *mut u8,
|
|
||||||
Layout::new::<[u8; STACK_SIZE]>(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,8 +98,8 @@ impl Thread {
|
|||||||
out = out(reg) current_rsp, // Save thread rsp
|
out = out(reg) current_rsp, // Save thread rsp
|
||||||
);
|
);
|
||||||
current_thread.borrow_mut().rsp = current_rsp;
|
current_thread.borrow_mut().rsp = current_rsp;
|
||||||
} else {
|
}
|
||||||
// Thread does not exists anymore
|
else { // Thread does not exists anymore
|
||||||
*current_thread_guard = self.id; // change running thread
|
*current_thread_guard = self.id; // change running thread
|
||||||
asm!( // Just switch to new thead without saving registers
|
asm!( // Just switch to new thead without saving registers
|
||||||
"push {rsp}", // Set stack pointer to the new thread
|
"push {rsp}", // Set stack pointer to the new thread
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
pub type SyscallId = u64;
|
|
||||||
|
|
||||||
pub const EXIT_ID: SyscallId = 0;
|
|
||||||
+3
-58
@@ -1,60 +1,5 @@
|
|||||||
use crate::println;
|
|
||||||
use crate::proc::thread::{resume_k_thread, RUNNING_THREAD};
|
|
||||||
use crate::proc::scheduler::SCHEDULER;
|
|
||||||
use crate::task::yield_executor::YieldExecutor;
|
|
||||||
use crate::task::Task;
|
|
||||||
|
|
||||||
pub use ids::*;
|
|
||||||
|
|
||||||
use alloc::sync::Arc;
|
|
||||||
use core::cell::RefCell;
|
|
||||||
|
|
||||||
pub mod ids;
|
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod proc;
|
|
||||||
|
|
||||||
pub type SyscallContextT = Arc<RefCell<SyscallContext>>;
|
pub fn syscall_dispatcher() -> u64 {
|
||||||
|
0
|
||||||
pub struct SyscallContext {
|
}
|
||||||
id: SyscallId,
|
|
||||||
res: u64,
|
|
||||||
thread_id: crate::proc::thread::ThreadId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SyscallContext {
|
|
||||||
pub async fn run(&mut self) {
|
|
||||||
println!("Running async syscall runner for {:?}", self.id);
|
|
||||||
self.dispatch().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn dispatch(&mut self) {
|
|
||||||
match self.id {
|
|
||||||
EXIT_ID => proc::exit(self).await,
|
|
||||||
_ => bad_syscall().await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async fn syscall_runner(context: SyscallContextT) {
|
|
||||||
context.borrow_mut().run().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn syscall_routine(syscall_id: SyscallId) -> u64 {
|
|
||||||
println!("Running syscall interrupt handler");
|
|
||||||
let context: SyscallContextT = Arc::new(RefCell::new(SyscallContext {
|
|
||||||
id: syscall_id,
|
|
||||||
res: 0,
|
|
||||||
thread_id: *RUNNING_THREAD.try_lock().unwrap(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
println!("Spawning async syscall runner");
|
|
||||||
let mut executor = YieldExecutor::new(context.borrow().thread_id);
|
|
||||||
executor.spawn(Task::new(syscall_runner(context.clone())));
|
|
||||||
executor.run();
|
|
||||||
|
|
||||||
let res = context.borrow().res;
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn bad_syscall() {}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
use crate::println;
|
|
||||||
use crate::proc::scheduler::SCHEDULER;
|
|
||||||
use crate::proc::thread::resume_k_thread;
|
|
||||||
|
|
||||||
use super::SyscallContext;
|
|
||||||
|
|
||||||
pub async fn exit(context: &SyscallContext) {
|
|
||||||
println!("Running exit(2)");
|
|
||||||
SCHEDULER.lock().await.exit(context.thread_id);
|
|
||||||
resume_k_thread();
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,6 @@ use core::sync::atomic::{AtomicU64, Ordering};
|
|||||||
use core::task::{Context, Poll};
|
use core::task::{Context, Poll};
|
||||||
|
|
||||||
pub mod executor;
|
pub mod executor;
|
||||||
pub mod yield_executor;
|
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
|
|
||||||
use crate::println;
|
|
||||||
use crate::proc::thread::{ThreadId, resume_k_thread};
|
|
||||||
use crate::proc::scheduler::SCHEDULER;
|
|
||||||
|
|
||||||
use super::{Task, TaskId};
|
|
||||||
|
|
||||||
use alloc::{collections::BTreeMap, sync::Arc, task::Wake};
|
|
||||||
use core::task::{Context, Poll, Waker};
|
|
||||||
use crossbeam_queue::ArrayQueue;
|
|
||||||
|
|
||||||
pub struct YieldExecutor {
|
|
||||||
tasks: BTreeMap<TaskId, Task>,
|
|
||||||
task_queue: Arc<ArrayQueue<TaskId>>,
|
|
||||||
waker_cache: BTreeMap<TaskId, Waker>,
|
|
||||||
thread_id: ThreadId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl YieldExecutor {
|
|
||||||
pub fn new(thread_id: ThreadId) -> Self {
|
|
||||||
YieldExecutor {
|
|
||||||
tasks: BTreeMap::new(),
|
|
||||||
task_queue: Arc::new(ArrayQueue::new(100)),
|
|
||||||
waker_cache: BTreeMap::new(),
|
|
||||||
thread_id: thread_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
|
||||||
loop {
|
|
||||||
self.run_ready_tasks();
|
|
||||||
if self.done() {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
println!("Blocking thread");
|
|
||||||
SCHEDULER
|
|
||||||
.try_lock()
|
|
||||||
.unwrap()
|
|
||||||
.block(self.thread_id);
|
|
||||||
println!("Returning to scheduler");
|
|
||||||
resume_k_thread();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn done(&self) -> bool {
|
|
||||||
self.tasks.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spawn(&mut self, task: Task) {
|
|
||||||
let task_id = task.id;
|
|
||||||
if self.tasks.insert(task.id, task).is_some() {
|
|
||||||
panic!("Duplicate task ID");
|
|
||||||
}
|
|
||||||
self.task_queue.push(task_id).expect("Task queue full");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_ready_tasks(&mut self) {
|
|
||||||
let Self {
|
|
||||||
tasks,
|
|
||||||
task_queue,
|
|
||||||
waker_cache,
|
|
||||||
thread_id,
|
|
||||||
} = self; // Executor destructuring
|
|
||||||
|
|
||||||
while let Ok(task_id) = task_queue.pop() {
|
|
||||||
let task = match tasks.get_mut(&task_id) {
|
|
||||||
Some(task) => task,
|
|
||||||
None => continue, // Task does not exist anymore
|
|
||||||
};
|
|
||||||
let waker = waker_cache
|
|
||||||
.entry(task_id)
|
|
||||||
.or_insert_with(|| YieldTaskWaker::new(task_id, task_queue.clone(), *thread_id));
|
|
||||||
let mut context = Context::from_waker(waker);
|
|
||||||
match task.poll(&mut context) {
|
|
||||||
Poll::Ready(()) => {
|
|
||||||
// task is done
|
|
||||||
tasks.remove(&task_id);
|
|
||||||
waker_cache.remove(&task_id);
|
|
||||||
}
|
|
||||||
Poll::Pending => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct YieldTaskWaker {
|
|
||||||
task_id: TaskId,
|
|
||||||
task_queue: Arc<ArrayQueue<TaskId>>,
|
|
||||||
thread_id: ThreadId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl YieldTaskWaker {
|
|
||||||
fn new(task_id: TaskId, task_queue: Arc<ArrayQueue<TaskId>>, thread_id: ThreadId) -> Waker {
|
|
||||||
Waker::from(Arc::new(YieldTaskWaker {
|
|
||||||
task_id,
|
|
||||||
task_queue,
|
|
||||||
thread_id
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wake_task(&self) {
|
|
||||||
self.task_queue.push(self.task_id).expect("Task queue full");
|
|
||||||
SCHEDULER
|
|
||||||
.try_lock()
|
|
||||||
.unwrap()
|
|
||||||
.unblock(self.thread_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Wake for YieldTaskWaker {
|
|
||||||
fn wake(self: Arc<Self>) {
|
|
||||||
self.wake_task();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wake_by_ref(self: &Arc<Self>) {
|
|
||||||
self.wake_task();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,6 @@ use futures_util::task::AtomicWaker;
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Lock {
|
struct Lock {
|
||||||
lock: Arc<AtomicBool>,
|
lock: Arc<AtomicBool>,
|
||||||
// TODO: Make a queue of wakers
|
|
||||||
waker: Arc<AtomicWaker>,
|
waker: Arc<AtomicWaker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||