Skip to main content

os/syscall/
process.rs

1use crate::fs::{OpenFlags, open_file};
2use crate::mm::{translated_ref, translated_refmut, translated_str};
3use crate::task::{
4    MAX_SIG, SignalAction, SignalFlags, add_task, current_task, current_user_token,
5    exit_current_and_run_next, pid2task, suspend_current_and_run_next,
6};
7use crate::timer::get_time_ms;
8use alloc::string::String;
9use alloc::sync::Arc;
10use alloc::vec::Vec;
11
12pub fn sys_exit(exit_code: i32) -> ! {
13    exit_current_and_run_next(exit_code);
14    panic!("Unreachable in sys_exit!");
15}
16
17pub fn sys_yield() -> isize {
18    suspend_current_and_run_next();
19    0
20}
21
22pub fn sys_get_time() -> isize {
23    get_time_ms() as isize
24}
25
26pub fn sys_getpid() -> isize {
27    current_task().unwrap().pid.0 as isize
28}
29
30pub fn sys_fork() -> isize {
31    let current_task = current_task().unwrap();
32    let new_task = current_task.fork();
33    let new_pid = new_task.pid.0;
34    // modify trap context of new_task, because it returns immediately after switching
35    let trap_cx = new_task.inner_exclusive_access().get_trap_cx();
36    // we do not have to move to next instruction since we have done it before
37    // for child process, fork returns 0
38    trap_cx.x[10] = 0;
39    // add new task to scheduler
40    add_task(new_task);
41    new_pid as isize
42}
43
44pub fn sys_exec(path: *const u8, mut args: *const usize) -> isize {
45    let token = current_user_token();
46    let path = translated_str(token, path);
47    let mut args_vec: Vec<String> = Vec::new();
48    loop {
49        let arg_str_ptr = *translated_ref(token, args);
50        if arg_str_ptr == 0 {
51            break;
52        }
53        args_vec.push(translated_str(token, arg_str_ptr as *const u8));
54        unsafe {
55            args = args.add(1);
56        }
57    }
58    if let Some(app_inode) = open_file(path.as_str(), OpenFlags::RDONLY) {
59        let all_data = app_inode.read_all();
60        let task = current_task().unwrap();
61        let argc = args_vec.len();
62        task.exec(all_data.as_slice(), args_vec);
63        // return argc because cx.x[10] will be covered with it later
64        argc as isize
65    } else {
66        -1
67    }
68}
69
70/// If there is not a child process whose pid is same as given, return -1.
71/// Else if there is a child process but it is still running, return -2.
72pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize {
73    let task = current_task().unwrap();
74    // find a child process
75
76    // ---- access current PCB exclusively
77    let mut inner = task.inner_exclusive_access();
78    if !inner
79        .children
80        .iter()
81        .any(|p| pid == -1 || pid as usize == p.getpid())
82    {
83        return -1;
84        // ---- release current PCB
85    }
86    let pair = inner.children.iter().enumerate().find(|(_, p)| {
87        // ++++ temporarily access child PCB exclusively
88        p.inner_exclusive_access().is_zombie() && (pid == -1 || pid as usize == p.getpid())
89        // ++++ release child PCB
90    });
91    if let Some((idx, _)) = pair {
92        let child = inner.children.remove(idx);
93        // confirm that child will be deallocated after being removed from children list
94        assert_eq!(Arc::strong_count(&child), 1);
95        let found_pid = child.getpid();
96        // ++++ temporarily access child PCB exclusively
97        let exit_code = child.inner_exclusive_access().exit_code;
98        // ++++ release child PCB
99        *translated_refmut(inner.memory_set.token(), exit_code_ptr) = exit_code;
100        found_pid as isize
101    } else {
102        -2
103    }
104    // ---- release current PCB automatically
105}
106
107pub fn sys_kill(pid: usize, signum: i32) -> isize {
108    if let Some(task) = pid2task(pid) {
109        if let Some(flag) = SignalFlags::from_bits(1 << signum) {
110            // insert the signal if legal
111            let mut task_ref = task.inner_exclusive_access();
112            if task_ref.signals.contains(flag) {
113                return -1;
114            }
115            task_ref.signals.insert(flag);
116            0
117        } else {
118            -1
119        }
120    } else {
121        -1
122    }
123}
124
125pub fn sys_sigprocmask(mask: u32) -> isize {
126    if let Some(task) = current_task() {
127        let mut inner = task.inner_exclusive_access();
128        let old_mask = inner.signal_mask;
129        if let Some(flag) = SignalFlags::from_bits(mask) {
130            inner.signal_mask = flag;
131            old_mask.bits() as isize
132        } else {
133            -1
134        }
135    } else {
136        -1
137    }
138}
139
140pub fn sys_sigreturn() -> isize {
141    if let Some(task) = current_task() {
142        let mut inner = task.inner_exclusive_access();
143        inner.handling_sig = -1;
144        // restore the trap context
145        let trap_ctx = inner.get_trap_cx();
146        *trap_ctx = inner.trap_ctx_backup.unwrap();
147        // Here we return the value of a0 in the trap_ctx,
148        // otherwise it will be overwritten after we trap
149        // back to the original execution of the application.
150        trap_ctx.x[10] as isize
151    } else {
152        -1
153    }
154}
155
156fn check_sigaction_error(signal: SignalFlags, action: usize, old_action: usize) -> bool {
157    if action == 0
158        || old_action == 0
159        || signal == SignalFlags::SIGKILL
160        || signal == SignalFlags::SIGSTOP
161    {
162        true
163    } else {
164        false
165    }
166}
167
168pub fn sys_sigaction(
169    signum: i32,
170    action: *const SignalAction,
171    old_action: *mut SignalAction,
172) -> isize {
173    let token = current_user_token();
174    let task = current_task().unwrap();
175    let mut inner = task.inner_exclusive_access();
176    if signum as usize > MAX_SIG {
177        return -1;
178    }
179    if let Some(flag) = SignalFlags::from_bits(1 << signum) {
180        if check_sigaction_error(flag, action as usize, old_action as usize) {
181            return -1;
182        }
183        let prev_action = inner.signal_actions.table[signum as usize];
184        *translated_refmut(token, old_action) = prev_action;
185        inner.signal_actions.table[signum as usize] = *translated_ref(token, action);
186        0
187    } else {
188        -1
189    }
190}