use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use crate::ThreadId;
use super::id::ProcId;
use super::manager::Manage;
use super::scheduler::Schedule;
use super::ProcThreadRel;
use core::marker::PhantomData;
#[cfg(feature = "thread")]
pub struct PThreadManager<P, T, MT: Manage<T, ThreadId> + Schedule<ThreadId>, MP: Manage<P, ProcId>>
{
rel_map: BTreeMap<ProcId, ProcThreadRel>,
proc_manager: Option<MP>,
tid2pid: BTreeMap<ThreadId, ProcId>,
manager: Option<MT>,
current: Option<ThreadId>,
phantom_t: PhantomData<T>,
phantom_p: PhantomData<P>,
}
impl<P, T, MT: Manage<T, ThreadId> + Schedule<ThreadId>, MP: Manage<P, ProcId>>
PThreadManager<P, T, MT, MP>
{
pub const fn new() -> Self {
Self {
rel_map: BTreeMap::new(),
proc_manager: None,
tid2pid: BTreeMap::new(),
manager: None,
current: None,
phantom_t: PhantomData::<T>,
phantom_p: PhantomData::<P>,
}
}
pub fn find_next(&mut self) -> Option<&mut T> {
if let Some(id) = self.manager.as_mut().unwrap().fetch() {
if let Some(task) = self.manager.as_mut().unwrap().get_mut(id) {
self.current = Some(id);
Some(task)
} else {
None
}
} else {
None
}
}
pub fn set_manager(&mut self, manager: MT) {
self.manager = Some(manager);
}
pub fn set_proc_manager(&mut self, proc_manager: MP) {
self.proc_manager = Some(proc_manager);
}
pub fn make_current_suspend(&mut self) {
if let Some(id) = self.current {
self.manager.as_mut().unwrap().add(id);
self.current = None;
}
}
pub fn make_current_exited(&mut self, exit_code: isize) {
if let Some(id) = self.current {
self.manager.as_mut().unwrap().delete(id);
let pid = self.tid2pid.remove(&id).unwrap();
let mut flag = false;
if let Some(current_rel) = self.rel_map.get_mut(&pid) {
current_rel.del_thread(id, exit_code);
if current_rel.threads.is_empty() {
flag = true;
}
}
if flag {
self.del_proc(pid, exit_code);
}
self.current = None;
}
}
pub fn make_current_blocked(&mut self) {
if let Some(_) = self.current {
self.current = None;
}
}
pub fn re_enque(&mut self, id: ThreadId) {
self.manager.as_mut().unwrap().add(id);
}
pub fn add(&mut self, id: ThreadId, task: T, pid: ProcId) {
self.manager.as_mut().unwrap().insert(id, task);
self.manager.as_mut().unwrap().add(id);
if let Some(parent_rel) = self.rel_map.get_mut(&pid) {
parent_rel.add_thread(id);
self.tid2pid.insert(id, pid);
}
}
pub fn current(&mut self) -> Option<&mut T> {
let id = self.current.unwrap();
self.manager.as_mut().unwrap().get_mut(id)
}
#[inline]
pub fn get_task(&mut self, id: ThreadId) -> Option<&mut T> {
self.manager.as_mut().unwrap().get_mut(id)
}
pub fn add_proc(&mut self, id: ProcId, proc: P, parent: ProcId) {
self.proc_manager.as_mut().unwrap().insert(id, proc);
if let Some(parent_rel) = self.rel_map.get_mut(&parent) {
parent_rel.add_child(id);
}
self.rel_map.insert(id, ProcThreadRel::new(parent));
}
pub fn get_proc(&mut self, id: ProcId) -> Option<&mut P> {
self.proc_manager.as_mut().unwrap().get_mut(id)
}
pub fn del_proc(&mut self, id: ProcId, exit_code: isize) {
self.proc_manager.as_mut().unwrap().delete(id);
let current_rel = self.rel_map.remove(&id).unwrap();
let parent_pid = current_rel.parent;
let children = current_rel.children;
if let Some(parent_rel) = self.rel_map.get_mut(&parent_pid) {
parent_rel.del_child(id, exit_code);
}
for i in children {
self.rel_map.get_mut(&i).unwrap().parent = ProcId::from_usize(0);
self.rel_map
.get_mut(&ProcId::from_usize(0))
.unwrap()
.add_child(i);
}
}
pub fn wait(&mut self, child_pid: ProcId) -> Option<(ProcId, isize)> {
let id = self.current.unwrap();
let pid = self.tid2pid.get(&id).unwrap();
let current_rel = self.rel_map.get_mut(pid).unwrap();
if child_pid.get_usize() == usize::MAX {
current_rel.wait_any_child()
} else {
current_rel.wait_child(child_pid)
}
}
pub fn waittid(&mut self, thread_tid: ThreadId) -> Option<isize> {
let id = self.current.unwrap();
let pid = self.tid2pid.get(&id).unwrap();
let current_rel = self.rel_map.get_mut(pid).unwrap();
current_rel.wait_thread(thread_tid)
}
pub fn thread_count(&self, id: ProcId) -> usize {
self.rel_map.get(&id).unwrap().threads.len()
}
pub fn get_thread(&mut self, id: ProcId) -> Option<&Vec<ThreadId>> {
self.rel_map.get_mut(&id).map(|p| &p.threads)
}
pub fn get_current_proc(&mut self) -> Option<&mut P> {
if let Some(id) = self.current {
let pid = self.tid2pid.get(&id).unwrap();
self.proc_manager.as_mut().unwrap().get_mut(*pid)
} else {
None
}
}
}