Skip to main content

os/task/
mod.rs

1mod action;
2mod context;
3mod manager;
4mod pid;
5mod processor;
6mod signal;
7mod switch;
8#[allow(clippy::module_inception)]
9mod task;
10
11use crate::fs::{OpenFlags, open_file};
12use crate::sbi::shutdown;
13use alloc::sync::Arc;
14pub use context::TaskContext;
15use lazy_static::*;
16use manager::fetch_task;
17use manager::remove_from_pid2task;
18use switch::__switch;
19use task::{TaskControlBlock, TaskStatus};
20
21pub use action::{SignalAction, SignalActions};
22pub use manager::{add_task, pid2task};
23pub use pid::{KernelStack, PidHandle, pid_alloc};
24pub use processor::{
25    current_task, current_trap_cx, current_user_token, run_tasks, schedule, take_current_task,
26};
27pub use signal::{MAX_SIG, SignalFlags};
28
29pub fn suspend_current_and_run_next() {
30    // There must be an application running.
31    let task = take_current_task().unwrap();
32
33    // ---- access current TCB exclusively
34    let mut task_inner = task.inner_exclusive_access();
35    let task_cx_ptr = &mut task_inner.task_cx as *mut TaskContext;
36    // Change status to Ready
37    task_inner.task_status = TaskStatus::Ready;
38    drop(task_inner);
39    // ---- release current PCB
40
41    // push back to ready queue.
42    add_task(task);
43    // jump to scheduling cycle
44    schedule(task_cx_ptr);
45}
46
47/// pid of usertests app in make run TEST=1
48pub const IDLE_PID: usize = 1;
49
50/// Exit the current 'Running' task and run the next task in task list.
51pub fn exit_current_and_run_next(exit_code: i32) {
52    // take from Processor
53    let task = take_current_task().unwrap();
54
55    let pid = task.getpid();
56    if pid == IDLE_PID {
57        println!(
58            "[kernel] Idle process exit with exit_code {} ...",
59            exit_code
60        );
61        if exit_code != 0 {
62            //crate::sbi::shutdown(255); //255 == -1 for err hint
63            shutdown(true)
64        } else {
65            //crate::sbi::shutdown(0); //0 for success hint
66            shutdown(false)
67        }
68    }
69
70    // remove from pid2task
71    remove_from_pid2task(task.getpid());
72    // **** access current TCB exclusively
73    let mut inner = task.inner_exclusive_access();
74    // Change status to Zombie
75    inner.task_status = TaskStatus::Zombie;
76    // Record exit code
77    inner.exit_code = exit_code;
78    // do not move to its parent but under initproc
79
80    // ++++++ access initproc TCB exclusively
81    {
82        let mut initproc_inner = INITPROC.inner_exclusive_access();
83        for child in inner.children.iter() {
84            child.inner_exclusive_access().parent = Some(Arc::downgrade(&INITPROC));
85            initproc_inner.children.push(child.clone());
86        }
87    }
88    // ++++++ release parent PCB
89
90    inner.children.clear();
91    // deallocate user space
92    inner.memory_set.recycle_data_pages();
93    // drop file descriptors
94    inner.fd_table.clear();
95    drop(inner);
96    // **** release current PCB
97    // drop task manually to maintain rc correctly
98    drop(task);
99    // we do not have to save task context
100    let mut _unused = TaskContext::zero_init();
101    schedule(&mut _unused as *mut _);
102}
103
104lazy_static! {
105    pub static ref INITPROC: Arc<TaskControlBlock> = Arc::new({
106        let inode = open_file("initproc", OpenFlags::RDONLY).unwrap();
107        let v = inode.read_all();
108        TaskControlBlock::new(v.as_slice())
109    });
110}
111
112pub fn add_initproc() {
113    add_task(INITPROC.clone());
114}
115
116pub fn check_signals_error_of_current() -> Option<(i32, &'static str)> {
117    let task = current_task().unwrap();
118    let task_inner = task.inner_exclusive_access();
119    // println!(
120    //     "[K] check_signals_error_of_current {:?}",
121    //     task_inner.signals
122    // );
123    task_inner.signals.check_error()
124}
125
126pub fn current_add_signal(signal: SignalFlags) {
127    let task = current_task().unwrap();
128    let mut task_inner = task.inner_exclusive_access();
129    task_inner.signals |= signal;
130    // println!(
131    //     "[K] current_add_signal:: current task sigflag {:?}",
132    //     task_inner.signals
133    // );
134}
135
136fn call_kernel_signal_handler(signal: SignalFlags) {
137    let task = current_task().unwrap();
138    let mut task_inner = task.inner_exclusive_access();
139    match signal {
140        SignalFlags::SIGSTOP => {
141            task_inner.frozen = true;
142            task_inner.signals ^= SignalFlags::SIGSTOP;
143        }
144        SignalFlags::SIGCONT => {
145            if task_inner.signals.contains(SignalFlags::SIGCONT) {
146                task_inner.signals ^= SignalFlags::SIGCONT;
147                task_inner.frozen = false;
148            }
149        }
150        _ => {
151            // println!(
152            //     "[K] call_kernel_signal_handler:: current task sigflag {:?}",
153            //     task_inner.signals
154            // );
155            task_inner.killed = true;
156        }
157    }
158}
159
160fn call_user_signal_handler(sig: usize, signal: SignalFlags) {
161    let task = current_task().unwrap();
162    let mut task_inner = task.inner_exclusive_access();
163
164    let handler = task_inner.signal_actions.table[sig].handler;
165    if handler != 0 {
166        // user handler
167
168        // handle flag
169        task_inner.handling_sig = sig as isize;
170        task_inner.signals ^= signal;
171
172        // backup trapframe
173        let trap_ctx = task_inner.get_trap_cx();
174        task_inner.trap_ctx_backup = Some(*trap_ctx);
175
176        // modify trapframe
177        trap_ctx.sepc = handler;
178
179        // put args (a0)
180        trap_ctx.x[10] = sig;
181    } else {
182        // default action
183        println!("[K] task/call_user_signal_handler: default action: ignore it or kill process");
184    }
185}
186
187fn check_pending_signals() {
188    for sig in 0..(MAX_SIG + 1) {
189        let task = current_task().unwrap();
190        let task_inner = task.inner_exclusive_access();
191        let signal = SignalFlags::from_bits(1 << sig).unwrap();
192        if task_inner.signals.contains(signal) && (!task_inner.signal_mask.contains(signal)) {
193            let mut masked = true;
194            let handling_sig = task_inner.handling_sig;
195            if handling_sig == -1 {
196                masked = false;
197            } else {
198                let handling_sig = handling_sig as usize;
199                if !task_inner.signal_actions.table[handling_sig]
200                    .mask
201                    .contains(signal)
202                {
203                    masked = false;
204                }
205            }
206            if !masked {
207                drop(task_inner);
208                drop(task);
209                if signal == SignalFlags::SIGKILL
210                    || signal == SignalFlags::SIGSTOP
211                    || signal == SignalFlags::SIGCONT
212                    || signal == SignalFlags::SIGDEF
213                {
214                    // signal is a kernel signal
215                    call_kernel_signal_handler(signal);
216                } else {
217                    // signal is a user signal
218                    call_user_signal_handler(sig, signal);
219                    return;
220                }
221            }
222        }
223    }
224}
225
226pub fn handle_signals() {
227    loop {
228        check_pending_signals();
229        let (frozen, killed) = {
230            let task = current_task().unwrap();
231            let task_inner = task.inner_exclusive_access();
232            (task_inner.frozen, task_inner.killed)
233        };
234        if !frozen || killed {
235            break;
236        }
237        suspend_current_and_run_next();
238    }
239}