Skip to main content

osiris/sched/
task.rs

1//! This module provides the basic task and thread structures for the scheduler.
2use 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/// Id of a task. This is unique across all tasks.
29#[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
67/// The struct representing a task.
68pub struct Task {
69    /// The unique identifier of the task.
70    pub id: UId,
71    /// The counter for the thread ids.
72    tid_cntr: usize,
73    /// Sets up the memory for the task.
74    address_space: mem::vmm::AddressSpace,
75    /// The threads belonging to this task.
76    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}