1use core::borrow::Borrow;
3use core::fmt::Display;
4use core::num::NonZero;
5
6use envparse::parse_env;
7
8use crate::hal::{self, stack::Stacklike};
9
10use crate::error::Result;
11use crate::mem;
12use crate::sched::{ThreadMap, thread};
13use crate::types::list;
14
15use crate::mem::vmm::AddressSpacelike;
16use crate::types::traits::ToIndex;
17
18pub struct Defaults {
19 pub stack_pages: usize,
20}
21
22const DEFAULTS: Defaults = Defaults {
23 stack_pages: parse_env!("OSIRIS_STACKPAGES" as usize),
24};
25
26pub const KERNEL_TASK: UId = UId { uid: 0 };
27
28#[proc_macros::fmt]
30#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
31pub struct UId {
32 uid: usize,
33}
34
35impl UId {
36 pub fn new(uid: usize) -> Self {
37 Self { uid }
38 }
39
40 pub fn as_usize(&self) -> usize {
41 self.uid
42 }
43
44 pub fn is_kernel(&self) -> bool {
45 self.uid == 0
46 }
47}
48
49impl ToIndex for UId {
50 fn to_index<Q: Borrow<Self>>(idx: Option<Q>) -> usize {
51 idx.as_ref().map_or(0, |uid| uid.borrow().uid)
52 }
53}
54
55impl Display for UId {
56 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
57 write!(f, "{}", self.uid)
58 }
59}
60
61#[allow(dead_code)]
62pub struct Attributes {
63 pub resrv_pgs: Option<NonZero<usize>>,
64 pub address_space: Option<mem::vmm::AddressSpace>,
65}
66
67pub struct Task {
69 pub id: UId,
71 tid_cntr: usize,
73 address_space: mem::vmm::AddressSpace,
75 threads: list::List<thread::ThreadList, thread::UId>,
77}
78
79impl Task {
80 pub fn new(id: UId, attrs: Attributes) -> Result<Self> {
81 let address_space = match attrs.address_space {
82 Some(addr_space) => addr_space,
83 None => {
84 let resrv_pgs = attrs.resrv_pgs.ok_or(kerr!(EINVAL))?;
85 mem::vmm::AddressSpace::new(resrv_pgs.get())?
86 }
87 };
88
89 Ok(Self {
90 id,
91 address_space,
92 tid_cntr: 0,
93 threads: list::List::new(),
94 })
95 }
96
97 pub fn allocate_tid(&mut self) -> thread::Id {
98 let tid = self.tid_cntr;
99 self.tid_cntr += 1;
100 thread::Id::new(tid, self.id)
101 }
102
103 pub fn allocate_stack(&mut self, attrs: &thread::Attributes) -> Result<hal::Stack> {
104 let size = DEFAULTS.stack_pages * mem::pfa::PAGE_SIZE;
105 let region = mem::vmm::Region::new(
106 None,
107 size,
108 mem::vmm::Backing::Uninit,
109 mem::vmm::Perms::Read | mem::vmm::Perms::Write,
110 );
111 let pa = self.address_space.map(region)?;
112
113 Ok(unsafe {
114 hal::Stack::new(hal::stack::Descriptor {
115 top: pa + size,
116 size: NonZero::new(size).unwrap(),
117 entry: attrs.entry,
118 ctx: attrs.ctx,
119 fin: attrs.fin.or(Some(super::thread_finalizer)),
120 })?
121 })
122 }
123
124 pub fn register_thread<const N: usize>(
125 &mut self,
126 uid: thread::UId,
127 storage: &mut ThreadMap<N>,
128 ) -> Result<()> {
129 self.threads.push_back(uid, storage)
130 }
131
132 #[allow(dead_code)]
133 pub fn tid_cntr(&self) -> usize {
134 self.tid_cntr
135 }
136
137 pub fn threads_mut(&mut self) -> &mut list::List<thread::ThreadList, thread::UId> {
138 &mut self.threads
139 }
140
141 pub fn threads(&self) -> &list::List<thread::ThreadList, thread::UId> {
142 &self.threads
143 }
144
145 #[cfg(any(feature = "metrics", metrics))]
146 pub(crate) fn allocator_metrics(&self) -> crate::mem::alloc::Metrics {
147 self.address_space.metrics()
148 }
149}