rstubs/threading/thread.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
use core::fmt;
use crate::arch::context::*;
use crate::interrupts::guard::GUARD;
/// The Thread is an object used by the scheduler.
pub struct Thread {
/// Thread id, each thread should have a different one
pub id: usize,
/// Saved registers
pub registers: Registers,
/// Kernel stack
kernel_stack: &'static mut [u32],
/// If this thread has been killed
pub exited: bool,
/// Function pointer
action: extern "C" fn() -> !,
}
impl fmt::Debug for Thread {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Thread")
.field("id", &self.id)
.field("registers", &self.registers)
.field("kernel_stack", &self.kernel_stack())
.field("exited", &self.exited)
.finish_non_exhaustive()
}
}
impl Thread {
/// Creates a new thread with the given action.
pub fn new(action: extern "C" fn() -> !) -> Self {
Self {
id: 0,
registers: Registers::new(),
kernel_stack: &mut [],
exited: false,
action,
}
}
pub fn init(&mut self, kernel_stack: &'static mut [u32]) {
// Setup stack
self.registers.esp = {
let len = kernel_stack.len();
kernel_stack[len - 1] = self.action as u32; // arg 1
kernel_stack[len - 2] = 0xbeefcace; // return addr
kernel_stack[len - 3] = Self::kernel_kickoff as *const () as u32; // start function
(&kernel_stack[len - 3]) as *const u32 as u32
};
self.kernel_stack = kernel_stack;
}
/// Returns the top of the kernel stack pointer.
pub fn kernel_stack(&self) -> *mut () {
self.kernel_stack.as_ptr_range().end.cast_mut().cast()
}
/// Kickoff function that is called in kernel mode.
///
/// If the thread was configured with a user stack, `user_kickoff` is called in user mode.
/// Otherwise the `action` is executed directly in the kernel.
extern "C" fn kernel_kickoff(action: extern "C" fn()) {
GUARD.leave();
(action)();
}
/// Switches from the currently running thread to the `next` one.
///
/// The values currently present in the callee-saved registers will be
/// stored in this threads context-structure, the corresponding values
/// belonging to `next` thread will be loaded.
pub fn resume(&mut self, next: &Self) {
unsafe { switch(&mut self.registers, &next.registers) };
}
/// Activates the first thread on this CPU.
///
/// Calling the method starts the first thread on the calling CPU.
/// From then on, [Thread::resume] must be used all subsequent context
/// switches.
pub fn go(&self) {
unsafe { launch(&self.registers) };
}
}