#![allow(unused)]
use core::alloc::Layout;
use core::mem;
use core::mem::size_of_val;
use core::ops::Deref;
use core::ptr;
use crate::alloc::allocator::AllocError;
use crate::exec::process;
use crate::exec::process::ProcessInternal;
use crate::exec::runnable::{Priority, Runnable, RunnableResult, Transition};
use crate::mem::boxed::Box;
use crate::sched;
use crate::sched::event::Event;
use crate::stack::Stack;
use crate::syscall;
use crate::time;
use bern_arch::arch::memory_protection::MemoryRegion;
use bern_arch::arch::Arch;
use bern_arch::memory_protection::{Access, Config, Permission, Type};
use bern_arch::IMemoryProtection;
use bern_conf::CONF;
use core::ptr::NonNull;
pub struct Thread {}
impl Thread {
pub fn new(context: &process::Context) -> ThreadBuilder {
ThreadBuilder {
process: context.process(),
stack: None,
priority: Default::default(),
name: None,
}
}
}
pub struct ThreadBuilder {
process: &'static ProcessInternal,
stack: Option<Stack>,
priority: Priority,
name: Option<&'static str>,
}
impl ThreadBuilder {
pub fn stack(&mut self, stack: Stack) -> &mut Self {
self.stack = Some(stack);
self
}
pub fn priority(&mut self, priority: Priority) -> &mut Self {
self.priority = priority;
self
}
pub fn idle_task(&mut self) -> &mut Self {
self.priority = Priority::idle();
self
}
pub fn name(&mut self, name: &'static str) -> &mut Self {
self.name = Some(name);
self
}
pub fn spawn<F>(&mut self, entry: F)
where
F: 'static + FnMut() -> RunnableResult,
{
let stack = match &mut self.stack {
None => panic!("Allocate a stack."),
Some(s) => s,
};
let entry_size = size_of_val(&entry);
if stack.size() < entry_size {
panic!("Stack too small for closure.");
}
let entry_ref = unsafe {
let entry_ptr = stack.ptr().cast::<F>().offset(-1);
entry_ptr.write(entry);
stack.set_ptr((stack.ptr() as usize - entry_size) as *mut usize);
&(&mut *entry_ptr as &mut dyn FnMut() -> RunnableResult)
};
syscall::thread_spawn(self, entry_ref);
}
pub(crate) fn build(&mut self, entry: &&mut (dyn FnMut() -> RunnableResult)) {
let mut stack = match self.stack.take() {
Some(stack) => stack,
None => panic!("todo: return error"),
};
let mut ptr = stack.ptr() as *mut u8;
let entry_len = mem::size_of_val(entry);
unsafe {
ptr = Self::align_ptr(ptr, 8);
ptr = ptr.offset(-(entry_len as isize));
ptr::write(ptr as *mut _, entry.deref());
}
let runnable_ptr = ptr as *mut usize;
unsafe {
ptr = Self::align_ptr(ptr, 8);
}
stack.set_ptr(ptr as *mut usize);
let mut thread = Runnable::new(self.process, runnable_ptr, stack, self.priority, self.name);
sched::add_task(thread)
}
unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
let offset = ptr as usize % align;
ptr.offset(-(offset as isize))
}
}
#[cfg(all(test, not(target_os = "none")))]
mod tests {
use super::*;
use bern_arch::arch::Arch;
#[test]
fn empty() {}
}