pudding_kernel/
task.rs

1#![allow(dead_code)]
2
3use core::ptr::NonNull;
4
5use crate::priority_queue::*;
6use crate::timeout_queue::*;
7use crate::*;
8
9pub(crate) type TaskQueue = PriorityQueue<Task, Priority>;
10type TimeQueue = TimeoutQueue<Task, RelativeTime>;
11
12// ---------------------------------
13//  Ready Queue
14// ---------------------------------
15
16pub(crate) fn current_task() -> Option<&'static mut Task> {
17    ready_queue::front() // レディーキューの先頭を実行中タスクとする
18}
19
20pub(crate) fn detach_current_task() -> Option<&'static mut Task> {
21    ready_queue::pop_front() // レディーキューの先頭を実行中タスクとする
22}
23
24mod ready_queue {
25    use super::*;
26
27    static mut READY_QUEUE: TaskQueue = TaskQueue::new();
28
29    pub(crate) fn front() -> Option<&'static mut Task> {
30        unsafe { READY_QUEUE.front() }
31    }
32
33    pub(crate) fn pop_front() -> Option<&'static mut Task> {
34        unsafe { READY_QUEUE.pop_front() }
35    }
36
37    pub(crate) fn attach(task: &mut Task) {
38        unsafe {
39            READY_QUEUE.insert_priority_order(task);
40        }
41    }
42
43    pub(crate) fn detach(task: &mut Task) {
44        unsafe {
45            READY_QUEUE.remove(task);
46        }
47    }
48
49    pub(crate) fn is_attached(task: &Task) -> bool {
50        task.queue == Some(unsafe { NonNull::new_unchecked(&mut READY_QUEUE as *mut TaskQueue) })
51    }
52}
53
54// ---------------------------------
55//  Timeout Queue
56// ---------------------------------
57
58mod timeout_queue {
59    use super::*;
60
61    static mut TIME_QUEUE: TimeQueue = TimeQueue::new();
62
63    pub(crate) fn sig_tim(tick: RelativeTime) {
64        unsafe {
65            TIME_QUEUE.sig_tim(tick);
66        }
67    }
68
69    pub(crate) fn attach(task: &mut Task, time: RelativeTime) {
70        unsafe {
71            TIME_QUEUE.add(task, time);
72        }
73    }
74
75    pub(crate) fn detach(task: &mut Task) {
76        unsafe {
77            TIME_QUEUE.remove(task);
78        }
79    }
80
81    pub(crate) fn is_attached(task: &Task) -> bool {
82        !task.timeout.prev.is_none()
83    }
84}
85
86pub fn supply_time_tick_for_timeout(tick: RelativeTime) {
87    timeout_queue::sig_tim(tick);
88}
89
90// ---------------------------------
91//  Task control block
92// ---------------------------------
93
94struct Timeout {
95    difftim: RelativeTime,
96    next: Option<NonNull<Task>>,
97    prev: Option<NonNull<Task>>,
98}
99
100impl Timeout {
101    const fn new() -> Self {
102        Timeout {
103            difftim: 0,
104            next: None,
105            prev: None,
106        }
107    }
108}
109
110// Task control block
111pub struct Task {
112    context: crate::context::Context,
113    queue: Option<NonNull<TaskQueue>>,
114    next: Option<NonNull<Task>>,
115    priority: Priority,
116    task: Option<fn(isize)>,
117    exinf: isize,
118    actcnt: ActivateCount,
119    timeout: Timeout,
120    result: Result<(), Error>,
121}
122
123impl Task {
124    /// インスタンス生成
125    pub const fn new() -> Self {
126        Task {
127            context: Context::new(),
128            queue: None,
129            next: None,
130            priority: 0,
131            task: None,
132            exinf: 0,
133            actcnt: 0,
134            timeout: Timeout::new(),
135            result: Ok(()),
136        }
137    }
138
139    /// タスク生成
140    pub fn create(&mut self, exinf: isize, task: fn(isize), priority: Priority, stack: &mut [u8]) {
141        extern "C" fn task_entry(exinf: isize) {
142            unsafe {
143                let task_ptr = exinf as *mut Task;
144                let task = &mut *task_ptr;
145                loop {
146                    while task.actcnt > 0 {
147                        task.actcnt -= 1;
148                        cpu_unlock();
149                        (task.task.unwrap())(task.exinf);
150                        cpu_lock();
151                    }
152                    task.detach_from_queue();
153                    task_switch()
154                }
155            }
156        }
157
158        self.exinf = exinf;
159        self.task = Some(task);
160        self.priority = priority;
161
162        let task_ptr = self as *mut Task;
163        self.context.create(stack, task_entry, task_ptr as isize);
164    }
165
166    pub(crate) fn result(&self) -> Result<(), Error> {
167        self.result
168    }
169
170    pub(crate) fn set_result(&mut self, result: Result<(), Error>) {
171        self.result = result;
172    }
173
174    pub(crate) fn is_attached_to_ready_queue(&self) -> bool {
175        ready_queue::is_attached(self)
176    }
177
178    pub(crate) fn is_attached_to_timeout(&self) -> bool {
179        timeout_queue::is_attached(self)
180    }
181
182    pub(crate) fn is_attached_to_any_queue(&self) -> bool {
183        self.queue != None
184    }
185
186    pub(crate) fn is_attached_to_wait_queue(&self) -> bool {
187        !self.is_attached_to_ready_queue() && self.is_attached_to_any_queue()
188    }
189
190    pub(crate) fn attach_to_ready_queue(&mut self) {
191        debug_assert!(!self.is_attached_to_timeout());
192        debug_assert!(!self.is_attached_to_any_queue());
193        ready_queue::attach(self);
194    }
195
196    pub(crate) fn attach_to_queue(&mut self, que: &mut TaskQueue, order: Order) {
197        debug_assert!(!self.is_attached_to_any_queue());
198        match order {
199            Order::Priority => {
200                que.insert_priority_order(self);
201            }
202            Order::Fifo => {
203                que.push_back(self);
204            }
205        }
206    }
207
208    pub(crate) fn detach_from_queue(&mut self) {
209        match self.queue {
210            Some(mut que) => unsafe {
211                que.as_mut().remove(self);
212            },
213            _ => {}
214        }
215    }
216
217    pub(crate) fn attach_to_timeout(&mut self, time: RelativeTime) {
218        debug_assert_eq!(self.timeout.prev, None);
219        timeout_queue::attach(self, time);
220    }
221
222    pub(crate) fn detach_from_timeout(&mut self) {
223        if !self.timeout.prev.is_none() {
224            timeout_queue::detach(self);
225        }
226    }
227
228    // タスクスイッチ
229    unsafe fn switch(&mut self) {
230        self.context.switch();
231    }
232
233    pub fn priority(&self) -> Priority {
234        self.priority
235    }
236
237    pub fn activate(&mut self) {
238        let _sc = SystemCall::new();
239        self.actcnt += 1;
240        if self.queue == None {
241            self.attach_to_ready_queue();
242            set_dispatch_reserve_flag();
243        }
244    }
245}
246
247impl PriorityObject<Task, Priority> for Task {
248    fn next(&self) -> Option<NonNull<Task>> {
249        self.next
250    }
251    fn set_next(&mut self, next: Option<NonNull<Task>>) {
252        self.next = next;
253    }
254    fn priority(&self) -> Priority {
255        self.priority
256    }
257    fn queue(&self) -> Option<NonNull<TaskQueue>> {
258        self.queue
259    }
260
261    fn set_queue(&mut self, que: Option<NonNull<TaskQueue>>) {
262        self.queue = que;
263    }
264
265    fn queue_dropped(&mut self) {}
266}
267
268impl TimeoutObject<Task, RelativeTime> for Task {
269    fn difftim(&self) -> RelativeTime {
270        self.timeout.difftim
271    }
272    fn set_difftim(&mut self, difftim: RelativeTime) {
273        self.timeout.difftim = difftim;
274    }
275
276    fn next(&self) -> Option<NonNull<Task>> {
277        self.timeout.next
278    }
279    fn set_next(&mut self, next: Option<NonNull<Task>>) {
280        self.timeout.next = next;
281    }
282
283    fn prev(&self) -> Option<NonNull<Task>> {
284        self.timeout.prev
285    }
286    fn set_prev(&mut self, prev: Option<NonNull<Task>>) {
287        self.timeout.prev = prev;
288    }
289
290    fn timeout(&mut self) {
291        self.detach_from_queue();
292        self.attach_to_ready_queue();
293        self.result = Err(Error::Timeout);
294        set_dispatch_reserve_flag();
295    }
296
297    fn queue_dropped(&mut self) {}
298}
299
300pub(crate) unsafe fn task_switch() {
301    let head = ready_queue::front();
302    match head {
303        None => {
304            // CURRENT_TASK = None;
305            context_switch_to_system();
306        }
307        Some(task) => {
308            task.switch();
309        }
310    };
311}