os/task/
processor.rs

1//!Implementation of [`Processor`] and Intersection of control flow
2use super::__switch;
3use super::{TaskContext, TaskControlBlock};
4use super::{TaskStatus, fetch_task};
5use crate::sync::UPSafeCell;
6use crate::trap::TrapContext;
7use alloc::sync::Arc;
8use lazy_static::*;
9///Processor management structure
10pub struct Processor {
11    ///The task currently executing on the current processor
12    current: Option<Arc<TaskControlBlock>>,
13    ///The basic control flow of each core, helping to select and switch process
14    idle_task_cx: TaskContext,
15}
16
17impl Processor {
18    ///Create an empty Processor
19    pub fn new() -> Self {
20        Self {
21            current: None,
22            idle_task_cx: TaskContext::zero_init(),
23        }
24    }
25    ///Get mutable reference to `idle_task_cx`
26    fn get_idle_task_cx_ptr(&mut self) -> *mut TaskContext {
27        &mut self.idle_task_cx as *mut _
28    }
29    ///Get current task in moving semanteme
30    pub fn take_current(&mut self) -> Option<Arc<TaskControlBlock>> {
31        self.current.take()
32    }
33    ///Get current task in cloning semanteme
34    pub fn current(&self) -> Option<Arc<TaskControlBlock>> {
35        self.current.as_ref().map(Arc::clone)
36    }
37}
38
39lazy_static! {
40    pub static ref PROCESSOR: UPSafeCell<Processor> = unsafe { UPSafeCell::new(Processor::new()) };
41}
42///The main part of process execution and scheduling
43///Loop `fetch_task` to get the process that needs to run, and switch the process through `__switch`
44pub fn run_tasks() {
45    loop {
46        let mut processor = PROCESSOR.exclusive_access();
47        if let Some(task) = fetch_task() {
48            let idle_task_cx_ptr = processor.get_idle_task_cx_ptr();
49            // access coming task TCB exclusively
50            let mut task_inner = task.inner_exclusive_access();
51            let next_task_cx_ptr = &task_inner.task_cx as *const TaskContext;
52            task_inner.task_status = TaskStatus::Running;
53            drop(task_inner);
54            // release coming task TCB manually
55            processor.current = Some(task);
56            // release processor manually
57            drop(processor);
58            unsafe {
59                __switch(idle_task_cx_ptr, next_task_cx_ptr);
60            }
61        }
62    }
63}
64///Take the current task,leaving a None in its place
65pub fn take_current_task() -> Option<Arc<TaskControlBlock>> {
66    PROCESSOR.exclusive_access().take_current()
67}
68///Get running task
69pub fn current_task() -> Option<Arc<TaskControlBlock>> {
70    PROCESSOR.exclusive_access().current()
71}
72///Get token of the address space of current task
73pub fn current_user_token() -> usize {
74    let task = current_task().unwrap();
75    let token = task.inner_exclusive_access().get_user_token();
76    token
77}
78///Get the mutable reference to trap context of current task
79pub fn current_trap_cx() -> &'static mut TrapContext {
80    current_task()
81        .unwrap()
82        .inner_exclusive_access()
83        .get_trap_cx()
84}
85///Return to idle control flow for new scheduling
86pub fn schedule(switched_task_cx_ptr: *mut TaskContext) {
87    let mut processor = PROCESSOR.exclusive_access();
88    let idle_task_cx_ptr = processor.get_idle_task_cx_ptr();
89    drop(processor);
90    unsafe {
91        __switch(switched_task_cx_ptr, idle_task_cx_ptr);
92    }
93}