add cleaner exit, freeing thread's stack
All checks were successful
continuous-integration/drone/push Build is passing
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:
parent
685dea4f6a
commit
563d97f372
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user