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 hal::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 is_kernel(&self) -> bool {
41        self.uid == 0
42    }
43}
44
45impl ToIndex for UId {
46    fn to_index<Q: Borrow<Self>>(idx: Option<Q>) -> usize {
47        idx.as_ref().map_or(0, |uid| uid.borrow().uid)
48    }
49}
50
51impl Display for UId {
52    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
53        write!(f, "{}", self.uid)
54    }
55}
56
57#[allow(dead_code)]
58pub struct Attributes {
59    pub resrv_pgs: Option<NonZero<usize>>,
60    pub address_space: Option<mem::vmm::AddressSpace>,
61}
62
63/// The struct representing a task.
64pub struct Task {
65    /// The unique identifier of the task.
66    pub id: UId,
67    /// The counter for the thread ids.
68    tid_cntr: usize,
69    /// Sets up the memory for the task.
70    address_space: mem::vmm::AddressSpace,
71    /// The threads belonging to this task.
72    threads: list::List<thread::ThreadList, thread::UId>,
73}
74
75impl Task {
76    pub fn new(id: UId, attrs: Attributes) -> Result<Self> {
77        let address_space = match attrs.address_space {
78            Some(addr_space) => addr_space,
79            None => {
80                let resrv_pgs = attrs.resrv_pgs.ok_or(kerr!(InvalidArgument))?;
81                mem::vmm::AddressSpace::new(resrv_pgs.get())?
82            }
83        };
84
85        Ok(Self {
86            id,
87            address_space,
88            tid_cntr: 0,
89            threads: list::List::new(),
90        })
91    }
92
93    pub fn allocate_tid(&mut self) -> thread::Id {
94        let tid = self.tid_cntr;
95        self.tid_cntr += 1;
96        thread::Id::new(tid, self.id)
97    }
98
99    pub fn allocate_stack(&mut self, attrs: &thread::Attributes) -> Result<hal::Stack> {
100        let size = DEFAULTS.stack_pages * mem::pfa::PAGE_SIZE;
101        let region = mem::vmm::Region::new(
102            None,
103            size,
104            mem::vmm::Backing::Uninit,
105            mem::vmm::Perms::Read | mem::vmm::Perms::Write,
106        );
107        let pa = self.address_space.map(region)?;
108
109        Ok(unsafe {
110            hal::Stack::new(hal::stack::Descriptor {
111                top: pa + size,
112                size: NonZero::new(size).unwrap(),
113                entry: attrs.entry,
114                fin: attrs.fin,
115            })?
116        })
117    }
118
119    pub fn register_thread<const N: usize>(
120        &mut self,
121        uid: thread::UId,
122        storage: &mut ThreadMap<N>,
123    ) -> Result<()> {
124        self.threads.push_back(uid, storage)
125    }
126
127    #[allow(dead_code)]
128    pub fn tid_cntr(&self) -> usize {
129        self.tid_cntr
130    }
131
132    pub fn threads_mut(&mut self) -> &mut list::List<thread::ThreadList, thread::UId> {
133        &mut self.threads
134    }
135
136    pub fn threads(&self) -> &list::List<thread::ThreadList, thread::UId> {
137        &self.threads
138    }
139}