add cleaner exit, freeing thread's stack
All checks were successful
continuous-integration/drone/push Build is passing

Signed-off-by: Julien CLEMENT <julien.clement@epita.fr>
This commit is contained in:
Julien CLEMENT 2022-12-31 13:50:24 +01:00
parent 685dea4f6a
commit 563d97f372
2 changed files with 58 additions and 19 deletions

@ -31,6 +31,13 @@ impl ThreadStream {
waker: AtomicWaker::new(), waker: AtomicWaker::new(),
} }
} }
pub fn register(&mut self, id: ThreadId) {
self.ids
.push(id)
.expect("Thread queue full");
self.waker.wake();
}
} }
impl Stream for ThreadStream { impl Stream for ThreadStream {
@ -69,6 +76,7 @@ impl Scheduler {
entry_point: 0, entry_point: 0,
started: true, started: true,
rsp: 0, rsp: 0,
base_stack: 0,
}; };
res.register(Arc::new(RefCell::new(k_thread))); res.register(Arc::new(RefCell::new(k_thread)));
res res
@ -77,10 +85,12 @@ impl Scheduler {
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 {
let thread = self.get_thread(id).unwrap(); if let Some(thread) = self.get_thread(id) { // Thread still exists
unsafe { unsafe {
(&mut*thread.as_ptr()).run(); (&mut*thread.as_ptr()).run();
} }
self.thread_queue.register(id);
}
} }
} }
@ -89,11 +99,13 @@ impl Scheduler {
if self.threads.insert(thread_id, thread).is_some() { if self.threads.insert(thread_id, thread).is_some() {
panic!("Duplicate thread ID") panic!("Duplicate thread ID")
} }
self.thread_queue if thread_id != ThreadId(0) {
.ids self.thread_queue.register(thread_id);
.push(thread_id) }
.expect("Thread queue full"); }
self.thread_queue.waker.wake();
pub fn exit(&mut self, id: ThreadId) {
self.threads.remove(&id).unwrap().borrow().exit();
} }
pub fn get_thread(&mut self, id: ThreadId) -> Option<Threadt> { pub fn get_thread(&mut self, id: ThreadId) -> Option<Threadt> {

@ -34,6 +34,7 @@ pub fn exit() {
.get_thread(ThreadId(0)) .get_thread(ThreadId(0))
.unwrap() .unwrap()
.as_ptr(); .as_ptr();
scheduler.exit(*RUNNING_THREAD.try_lock().unwrap());
} // Drop scheduler mutex guard } // Drop scheduler mutex guard
unsafe { unsafe {
@ -51,24 +52,36 @@ 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
} }
impl Thread { impl Thread {
pub fn new(entry_point: u64) -> Self { pub fn new(entry_point: u64) -> Self {
unsafe { unsafe {
let stack_bottom = alloc(Layout::new::<[u8; STACK_SIZE]>()) as u64;
Thread { Thread {
id: ThreadId::new(), id: ThreadId::new(),
entry_point: entry_point, entry_point: entry_point,
started: false, started: false,
rsp: alloc(Layout::new::<[u8; STACK_SIZE]>()) as u64 + STACK_SIZE as u64, rsp: stack_bottom + STACK_SIZE as u64,
base_stack: stack_bottom,
} }
} }
} }
pub fn exit(&self) {
unsafe {
dealloc(self.base_stack as *mut u8, Layout::new::<[u8; STACK_SIZE]>());
}
}
pub fn run(&mut self) { pub fn run(&mut self) {
println!("Running thread {:?}", self.id); println!("Running thread {:?}", self.id);
unsafe { unsafe {
let mut current_thread_guard = RUNNING_THREAD.try_lock().unwrap(); let mut current_thread_guard = RUNNING_THREAD.try_lock().unwrap();
let mut scheduler = SCHEDULER.try_lock().unwrap();
if let Some(current_thread) = scheduler.get_thread(*current_thread_guard) {
let current_rsp: u64; let current_rsp: u64;
asm!( asm!(
"push rsp", // Recover current rsp "push rsp", // Recover current rsp
@ -76,11 +89,25 @@ impl Thread {
"sub {out}, 56", // Offset to saved registers "sub {out}, 56", // Offset to saved registers
out = out(reg) current_rsp, // Save thread rsp out = out(reg) current_rsp, // Save thread rsp
); );
let mut scheduler = SCHEDULER.try_lock().unwrap();
// TODO: check if the thread still exists
let current_thread = scheduler.get_thread(*current_thread_guard).unwrap();
current_thread.borrow_mut().rsp = current_rsp; current_thread.borrow_mut().rsp = current_rsp;
}
else { // Thread does not exists anymore
*current_thread_guard = self.id; // change running thread
asm!( // Just switch to new thead without saving registers
"push {rsp}", // Set stack pointer to the new thread
"pop rsp",
"pop rdi", // Restore new thread regs
"pop rsi",
"pop rbp",
"pop rdx",
"pop rcx",
"pop rbx",
"pop rax",
rsp = in(reg) self.rsp,
);
return;
}
*current_thread_guard = self.id; // change running thread *current_thread_guard = self.id; // change running thread
} // The scheduler and running thread guards are dropped here } // The scheduler and running thread guards are dropped here