use crate::{
config::MAX_SYSCALL_NUM,
fs::{open_file, OpenFlags},
mm::{translated_ref, translated_refmut, translated_str},
task::{
add_task, current_task, current_user_token, exit_current_and_run_next, pid2task,
suspend_current_and_run_next, SignalAction, SignalFlags, TaskStatus, MAX_SIG,
},
};
use alloc::{string::String, sync::Arc, vec::Vec};
#[repr(C)]
#[derive(Debug)]
pub struct TimeVal {
pub sec: usize,
pub usec: usize,
}
#[allow(dead_code)]
pub struct TaskInfo {
status: TaskStatus,
syscall_times: [u32; MAX_SYSCALL_NUM],
time: usize,
}
pub fn sys_exit(exit_code: i32) -> ! {
trace!("kernel:pid[{}] sys_exit",current_task().unwrap().pid.0);
exit_current_and_run_next(exit_code);
panic!("Unreachable in sys_exit!");
}
pub fn sys_yield() -> isize {
suspend_current_and_run_next();
0
}
pub fn sys_getpid() -> isize {
trace!("kernel: sys_getpid pid:{}", current_task().unwrap().pid.0);
current_task().unwrap().pid.0 as isize
}
pub fn sys_fork() -> isize {
trace!("kernel:pid[{}] sys_fork", current_task().unwrap().pid.0);
let current_task = current_task().unwrap();
let new_task = current_task.fork();
let new_pid = new_task.pid.0;
let trap_cx = new_task.inner_exclusive_access().get_trap_cx();
trap_cx.x[10] = 0;
add_task(new_task);
new_pid as isize
}
pub fn sys_exec(path: *const u8, mut args: *const usize) -> isize {
trace!("kernel:pid[{}] sys_exec", current_task().unwrap().pid.0);
let token = current_user_token();
let path = translated_str(token, path);
let mut args_vec: Vec<String> = Vec::new();
loop {
let arg_str_ptr = *translated_ref(token, args);
if arg_str_ptr == 0 {
break;
}
args_vec.push(translated_str(token, arg_str_ptr as *const u8));
unsafe {
args = args.add(1);
}
}
if let Some(app_inode) = open_file(path.as_str(), OpenFlags::RDONLY) {
let all_data = app_inode.read_all();
let task = current_task().unwrap();
let argc = args_vec.len();
task.exec(all_data.as_slice(), args_vec);
argc as isize
} else {
-1
}
}
pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize {
let task = current_task().unwrap();
let mut inner = task.inner_exclusive_access();
if !inner
.children
.iter()
.any(|p| pid == -1 || pid as usize == p.getpid())
{
return -1;
}
let pair = inner.children.iter().enumerate().find(|(_, p)| {
p.inner_exclusive_access().is_zombie() && (pid == -1 || pid as usize == p.getpid())
});
if let Some((idx, _)) = pair {
let child = inner.children.remove(idx);
assert_eq!(Arc::strong_count(&child), 1);
let found_pid = child.getpid();
let exit_code = child.inner_exclusive_access().exit_code;
*translated_refmut(inner.memory_set.token(), exit_code_ptr) = exit_code;
found_pid as isize
} else {
-2
}
}
pub fn sys_kill(pid: usize, signum: i32) -> isize {
trace!("kernel:pid[{}] sys_kill", current_task().unwrap().pid.0);
if let Some(task) = pid2task(pid) {
if let Some(flag) = SignalFlags::from_bits(1 << signum) {
let mut task_ref = task.inner_exclusive_access();
if task_ref.signals.contains(flag) {
return -1;
}
task_ref.signals.insert(flag);
0
} else {
-1
}
} else {
-1
}
}
pub fn sys_get_time(_ts: *mut TimeVal, _tz: usize) -> isize {
trace!("kernel:pid[{}] sys_get_time NOT IMPLEMENTED", current_task().unwrap().pid.0);
-1
}
pub fn sys_task_info(_ti: *mut TaskInfo) -> isize {
trace!("kernel:pid[{}] sys_task_info NOT IMPLEMENTED", current_task().unwrap().pid.0);
-1
}
pub fn sys_mmap(_start: usize, _len: usize, _port: usize) -> isize {
trace!("kernel:pid[{}] sys_mmap NOT IMPLEMENTED", current_task().unwrap().pid.0);
-1
}
pub fn sys_munmap(_start: usize, _len: usize) -> isize {
trace!("kernel:pid[{}] sys_munmap NOT IMPLEMENTED", current_task().unwrap().pid.0);
-1
}
pub fn sys_sbrk(size: i32) -> isize {
trace!("kernel:pid[{}] sys_sbrk", current_task().unwrap().pid.0);
if let Some(old_brk) = current_task().unwrap().change_program_brk(size) {
old_brk as isize
} else {
-1
}
}
pub fn sys_spawn(_path: *const u8) -> isize {
trace!("kernel:pid[{}] sys_spawn NOT IMPLEMENTED", current_task().unwrap().pid.0);
-1
}
pub fn sys_set_priority(_prio: isize) -> isize {
trace!("kernel:pid[{}] sys_set_priority NOT IMPLEMENTED", current_task().unwrap().pid.0);
-1
}
pub fn sys_sigprocmask(mask: u32) -> isize {
trace!("kernel:pid[{}] sys_sigprocmask", current_task().unwrap().pid.0);
if let Some(task) = current_task() {
let mut inner = task.inner_exclusive_access();
let old_mask = inner.signal_mask;
if let Some(flag) = SignalFlags::from_bits(mask) {
inner.signal_mask = flag;
old_mask.bits() as isize
} else {
-1
}
} else {
-1
}
}
pub fn sys_sigreturn() -> isize {
trace!("kernel:pid[{}] sys_sigreturn", current_task().unwrap().pid.0);
if let Some(task) = current_task() {
let mut inner = task.inner_exclusive_access();
inner.handling_sig = -1;
let trap_ctx = inner.get_trap_cx();
*trap_ctx = inner.trap_ctx_backup.unwrap();
trap_ctx.x[10] as isize
} else {
-1
}
}
fn check_sigaction_error(signal: SignalFlags, action: usize, old_action: usize) -> bool {
if action == 0
|| old_action == 0
|| signal == SignalFlags::SIGKILL
|| signal == SignalFlags::SIGSTOP
{
true
} else {
false
}
}
pub fn sys_sigaction(
signum: i32,
action: *const SignalAction,
old_action: *mut SignalAction,
) -> isize {
trace!("kernel:pid[{}] sys_sigaction", current_task().unwrap().pid.0);
let token = current_user_token();
let task = current_task().unwrap();
let mut inner = task.inner_exclusive_access();
if signum as usize > MAX_SIG {
return -1;
}
if let Some(flag) = SignalFlags::from_bits(1 << signum) {
if check_sigaction_error(flag, action as usize, old_action as usize) {
return -1;
}
let prev_action = inner.signal_actions.table[signum as usize];
*translated_refmut(token, old_action) = prev_action;
inner.signal_actions.table[signum as usize] = *translated_ref(token, action);
0
} else {
-1
}
}