mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
新增系统调用,并对照linux-6.1.9改写sys_wait4 (#440)
* 1. 新增以下系统调用 - SYS_LSTAT - SYS_READV - SYS_ACCESS - SYS_UNLINK - SYS_CHMOD - SYS_FCHMOD - SYS_UMASK - SYS_SYSINFO - SYS_CLOCK_GETTIME - SYS_FCHMODAT - SYS_FACCESSAT 2. 修改sys_wait4,使得其部分符合Linux的行为(还是有些地方不符合的,详情请对比linux-6.1.9的sys_wait4接口)
This commit is contained in:
parent
9b0abe6da7
commit
bf4a48994a
@ -277,6 +277,42 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
/// SIGCHLD si_codes
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, ToPrimitive)]
|
||||
#[allow(dead_code)]
|
||||
pub enum SigChildCode {
|
||||
/// child has exited
|
||||
///
|
||||
/// CLD_EXITED
|
||||
Exited = 1,
|
||||
/// child was killed
|
||||
///
|
||||
/// CLD_KILLED
|
||||
Killed = 2,
|
||||
/// child terminated abnormally
|
||||
///
|
||||
/// CLD_DUMPED
|
||||
Dumped = 3,
|
||||
/// traced child has trapped
|
||||
///
|
||||
/// CLD_TRAPPED
|
||||
Trapped = 4,
|
||||
/// child has stopped
|
||||
///
|
||||
/// CLD_STOPPED
|
||||
Stopped = 5,
|
||||
/// stopped child has continued
|
||||
///
|
||||
/// CLD_CONTINUED
|
||||
Continued = 6,
|
||||
}
|
||||
|
||||
impl Into<i32> for SigChildCode {
|
||||
fn into(self) -> i32 {
|
||||
self as i32
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, align(16))]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SigFrame {
|
||||
|
@ -22,15 +22,16 @@ impl Syscall {
|
||||
envp: Vec<String>,
|
||||
regs: &mut TrapFrame,
|
||||
) -> Result<(), SystemError> {
|
||||
// kdebug!(
|
||||
// "tmp_rs_execve: path: {:?}, argv: {:?}, envp: {:?}\n",
|
||||
// 关中断,防止在设置地址空间的时候,发生中断,然后进调度器,出现错误。
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
// crate::kdebug!(
|
||||
// "pid: {:?} do_execve: path: {:?}, argv: {:?}, envp: {:?}\n",
|
||||
// pcb.pid(),
|
||||
// path,
|
||||
// argv,
|
||||
// envp
|
||||
// );
|
||||
// 关中断,防止在设置地址空间的时候,发生中断,然后进调度器,出现错误。
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
|
||||
let mut basic_info = pcb.basic_mut();
|
||||
// 暂存原本的用户地址空间的引用(因为如果在切换页表之前释放了它,可能会造成内存use after free)
|
||||
@ -109,7 +110,7 @@ impl Syscall {
|
||||
|
||||
// kdebug!("regs: {:?}\n", regs);
|
||||
|
||||
// kdebug!(
|
||||
// crate::kdebug!(
|
||||
// "tmp_rs_execve: done, load_result.entry_point()={:?}",
|
||||
// load_result.entry_point()
|
||||
// );
|
||||
|
@ -7,15 +7,25 @@ use crate::{
|
||||
ipc::signal_types::SignalArch,
|
||||
libs::align::SafeForZero,
|
||||
mm::VirtAddr,
|
||||
process::ProcessManager,
|
||||
syscall::{Syscall, SystemError, SYS_RT_SIGRETURN},
|
||||
};
|
||||
use alloc::string::String;
|
||||
|
||||
use super::{interrupt::TrapFrame, mm::barrier::mfence};
|
||||
|
||||
pub const SYS_LSTAT: usize = 6;
|
||||
pub const SYS_READV: usize = 19;
|
||||
pub const SYS_ACCESS: usize = 21;
|
||||
pub const SYS_PRLIMIT64: usize = 302;
|
||||
pub const SYS_UNLINK: usize = 87;
|
||||
pub const SYS_CHMOD: usize = 90;
|
||||
pub const SYS_FCHMOD: usize = 91;
|
||||
pub const SYS_UMASK: usize = 95;
|
||||
pub const SYS_SYSINFO: usize = 99;
|
||||
pub const SYS_CLOCK_GETTIME: usize = 228;
|
||||
pub const SYS_FCHMODAT: usize = 268;
|
||||
pub const SYS_FACCESSAT: usize = 269;
|
||||
pub const SYS_PRLIMIT64: usize = 302;
|
||||
pub const SYS_FACCESSAT2: usize = 439;
|
||||
|
||||
/// ### 存储PCB系统调用栈以及在syscall过程中暂存用户态rsp的结构体
|
||||
@ -44,9 +54,15 @@ extern "C" {
|
||||
}
|
||||
|
||||
macro_rules! syscall_return {
|
||||
($val:expr, $regs:expr) => {{
|
||||
($val:expr, $regs:expr, $show:expr) => {{
|
||||
let ret = $val;
|
||||
$regs.rax = ret as u64;
|
||||
|
||||
if $show {
|
||||
let pid = ProcessManager::current_pcb().pid();
|
||||
crate::kdebug!("syscall return:pid={:?},ret= {:?}\n", pid, ret as isize);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
CurrentIrqArch::interrupt_disable();
|
||||
}
|
||||
@ -69,18 +85,34 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) -> () {
|
||||
frame.r9 as usize,
|
||||
];
|
||||
mfence();
|
||||
let pid = ProcessManager::current_pcb().pid();
|
||||
let show = false;
|
||||
// let show = if syscall_num != SYS_SCHED && pid.data() > 3 {
|
||||
// true
|
||||
// } else {
|
||||
// false
|
||||
// };
|
||||
|
||||
if show {
|
||||
crate::kdebug!("syscall: pid: {:?}, num={:?}\n", pid, syscall_num);
|
||||
}
|
||||
|
||||
// Arch specific syscall
|
||||
match syscall_num {
|
||||
SYS_RT_SIGRETURN => {
|
||||
syscall_return!(X86_64SignalArch::sys_rt_sigreturn(frame) as usize, frame);
|
||||
syscall_return!(
|
||||
X86_64SignalArch::sys_rt_sigreturn(frame) as usize,
|
||||
frame,
|
||||
show
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
syscall_return!(
|
||||
Syscall::handle(syscall_num, &args, frame).unwrap_or_else(|e| e.to_posix_errno() as usize)
|
||||
as u64,
|
||||
frame
|
||||
frame,
|
||||
show
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -16,10 +16,15 @@ use crate::{
|
||||
vfs::{mount::MountFS, syscall::ModeType, AtomicInodeId, FileSystem, FileType},
|
||||
},
|
||||
kdebug, kerror, kinfo,
|
||||
process::ProcessManager,
|
||||
syscall::SystemError,
|
||||
};
|
||||
|
||||
use super::{file::FileMode, utils::rsplit_path, IndexNode, InodeId, MAX_PATHLEN};
|
||||
use super::{
|
||||
file::FileMode,
|
||||
utils::{rsplit_path, user_path_at},
|
||||
IndexNode, InodeId, MAX_PATHLEN, VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
||||
};
|
||||
|
||||
/// @brief 原子地生成新的Inode号。
|
||||
/// 请注意,所有的inode号都需要通过该函数来生成.全局的inode号,除了以下两个特殊的以外,都是唯一的
|
||||
@ -206,13 +211,17 @@ pub fn do_mkdir(path: &str, _mode: FileMode) -> Result<u64, SystemError> {
|
||||
}
|
||||
|
||||
/// @brief 删除文件夹
|
||||
pub fn do_remove_dir(path: &str) -> Result<u64, SystemError> {
|
||||
pub fn do_remove_dir(dirfd: i32, path: &str) -> Result<u64, SystemError> {
|
||||
// 文件名过长
|
||||
if path.len() > MAX_PATHLEN as usize {
|
||||
return Err(SystemError::ENAMETOOLONG);
|
||||
}
|
||||
|
||||
let inode: Result<Arc<dyn IndexNode>, SystemError> = ROOT_INODE().lookup(path);
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let (inode_begin, remain_path) = user_path_at(&pcb, dirfd, path.to_string())?;
|
||||
|
||||
let inode: Result<Arc<dyn IndexNode>, SystemError> =
|
||||
inode_begin.lookup_follow_symlink(remain_path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES);
|
||||
|
||||
if inode.is_err() {
|
||||
let errno = inode.unwrap_err();
|
||||
@ -222,9 +231,10 @@ pub fn do_remove_dir(path: &str) -> Result<u64, SystemError> {
|
||||
}
|
||||
}
|
||||
|
||||
let (filename, parent_path) = rsplit_path(path);
|
||||
let (filename, parent_path) = rsplit_path(&remain_path);
|
||||
// 查找父目录
|
||||
let parent_inode: Arc<dyn IndexNode> = ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
|
||||
let parent_inode: Arc<dyn IndexNode> = inode_begin
|
||||
.lookup_follow_symlink(parent_path.unwrap_or("/"), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
|
||||
|
||||
if parent_inode.metadata()?.file_type != FileType::Dir {
|
||||
return Err(SystemError::ENOTDIR);
|
||||
@ -242,13 +252,16 @@ pub fn do_remove_dir(path: &str) -> Result<u64, SystemError> {
|
||||
}
|
||||
|
||||
/// @brief 删除文件
|
||||
pub fn do_unlink_at(path: &str, _mode: FileMode) -> Result<u64, SystemError> {
|
||||
pub fn do_unlink_at(dirfd: i32, path: &str) -> Result<u64, SystemError> {
|
||||
// 文件名过长
|
||||
if path.len() > MAX_PATHLEN as usize {
|
||||
return Err(SystemError::ENAMETOOLONG);
|
||||
}
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let (inode_begin, remain_path) = user_path_at(&pcb, dirfd, path.to_string())?;
|
||||
|
||||
let inode: Result<Arc<dyn IndexNode>, SystemError> = ROOT_INODE().lookup(path);
|
||||
let inode: Result<Arc<dyn IndexNode>, SystemError> =
|
||||
inode_begin.lookup_follow_symlink(&remain_path, VFS_MAX_FOLLOW_SYMLINK_TIMES);
|
||||
|
||||
if inode.is_err() {
|
||||
let errno = inode.clone().unwrap_err();
|
||||
@ -264,7 +277,8 @@ pub fn do_unlink_at(path: &str, _mode: FileMode) -> Result<u64, SystemError> {
|
||||
|
||||
let (filename, parent_path) = rsplit_path(path);
|
||||
// 查找父目录
|
||||
let parent_inode: Arc<dyn IndexNode> = ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
|
||||
let parent_inode: Arc<dyn IndexNode> = inode_begin
|
||||
.lookup_follow_symlink(parent_path.unwrap_or("/"), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
|
||||
|
||||
if parent_inode.metadata()?.file_type != FileType::Dir {
|
||||
return Err(SystemError::ENOTDIR);
|
||||
|
@ -19,6 +19,7 @@ use super::{Dirent, FileType, IndexNode, InodeId, Metadata, SpecialNodeData};
|
||||
|
||||
/// 文件私有信息的枚举类型
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub enum FilePrivateData {
|
||||
/// 管道文件私有信息
|
||||
Pipefs(PipeFsPrivateData),
|
||||
@ -198,6 +199,7 @@ impl File {
|
||||
}
|
||||
|
||||
/// @brief 根据inode号获取子目录项的名字
|
||||
#[allow(dead_code)]
|
||||
pub fn get_entry_name(&self, ino: InodeId) -> Result<String, SystemError> {
|
||||
return self.inode.get_entry_name(ino);
|
||||
}
|
||||
@ -535,6 +537,7 @@ impl FileDescriptorVec {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn iter(&self) -> FileDescriptorIterator {
|
||||
return FileDescriptorIterator::new(self);
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub mod core;
|
||||
pub mod fcntl;
|
||||
pub mod file;
|
||||
@ -50,6 +48,7 @@ pub enum FileType {
|
||||
Socket,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SpecialNodeData {
|
||||
/// 管道文件
|
||||
@ -62,6 +61,7 @@ pub enum SpecialNodeData {
|
||||
|
||||
/* these are defined by POSIX and also present in glibc's dirent.h */
|
||||
/// 完整含义请见 http://www.gnu.org/software/libc/manual/html_node/Directory-Entries.html
|
||||
#[allow(dead_code)]
|
||||
pub const DT_UNKNOWN: u16 = 0;
|
||||
/// 命名管道,或者FIFO
|
||||
pub const DT_FIFO: u16 = 1;
|
||||
@ -78,7 +78,9 @@ pub const DT_LNK: u16 = 10;
|
||||
// 是一个socket
|
||||
pub const DT_SOCK: u16 = 12;
|
||||
// 这个是抄Linux的,还不知道含义
|
||||
#[allow(dead_code)]
|
||||
pub const DT_WHT: u16 = 14;
|
||||
#[allow(dead_code)]
|
||||
pub const DT_MAX: u16 = 16;
|
||||
|
||||
/// vfs容许的最大的符号链接跳转次数
|
||||
|
@ -1,14 +1,20 @@
|
||||
use crate::syscall::SystemError;
|
||||
use crate::{
|
||||
process::ProcessManager,
|
||||
syscall::{user_access::check_and_clone_cstr, SystemError},
|
||||
};
|
||||
|
||||
use super::{fcntl::AtFlags, syscall::ModeType};
|
||||
use super::{
|
||||
fcntl::AtFlags, syscall::ModeType, utils::user_path_at, MAX_PATHLEN,
|
||||
VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
||||
};
|
||||
|
||||
pub(super) fn do_faccessat(
|
||||
_dirfd: i32,
|
||||
_pathname: *const u8,
|
||||
dirfd: i32,
|
||||
path: *const u8,
|
||||
mode: ModeType,
|
||||
flags: u32,
|
||||
) -> Result<usize, SystemError> {
|
||||
if (mode.bits() & (!ModeType::S_IXUGO.bits())) != 0 {
|
||||
if (mode.bits() & (!ModeType::S_IRWXO.bits())) != 0 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
@ -22,6 +28,35 @@ pub(super) fn do_faccessat(
|
||||
|
||||
// let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0;
|
||||
|
||||
let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
|
||||
|
||||
if path.len() == 0 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
|
||||
|
||||
// 如果找不到文件,则返回错误码ENOENT
|
||||
let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
|
||||
|
||||
// todo: 接着完善(可以借鉴linux 6.1.9的do_faccessat)
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize, SystemError> {
|
||||
let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
|
||||
|
||||
if path.len() == 0 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
|
||||
|
||||
// 如果找不到文件,则返回错误码ENOENT
|
||||
let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
|
||||
|
||||
kwarn!("do_fchmodat: not implemented yet\n");
|
||||
// todo: 真正去改变文件的权限
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use alloc::{
|
||||
use crate::{
|
||||
driver::base::{block::SeekFrom, device::DeviceNumber},
|
||||
filesystem::vfs::file::FileDescriptorVec,
|
||||
include::bindings::bindings::{verify_area, AT_REMOVEDIR, PROC_MAX_FD_NUM},
|
||||
include::bindings::bindings::{verify_area, PROC_MAX_FD_NUM},
|
||||
kerror,
|
||||
libs::rwlock::RwLockWriteGuard,
|
||||
mm::VirtAddr,
|
||||
@ -25,7 +25,7 @@ use super::{
|
||||
core::{do_mkdir, do_remove_dir, do_unlink_at},
|
||||
fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC},
|
||||
file::{File, FileMode},
|
||||
open::do_faccessat,
|
||||
open::{do_faccessat, do_fchmodat},
|
||||
utils::{rsplit_path, user_path_at},
|
||||
Dirent, FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
||||
};
|
||||
@ -153,15 +153,21 @@ impl Syscall {
|
||||
/// @param o_flags 打开文件的标志位
|
||||
///
|
||||
/// @return 文件描述符编号,或者是错误码
|
||||
pub fn open(path: &str, mode: FileMode) -> Result<usize, SystemError> {
|
||||
pub fn open(path: &str, mode: FileMode, follow_symlink: bool) -> Result<usize, SystemError> {
|
||||
// kdebug!("open: path: {}, mode: {:?}", path, mode);
|
||||
// 文件名过长
|
||||
if path.len() > MAX_PATHLEN as usize {
|
||||
return Err(SystemError::ENAMETOOLONG);
|
||||
}
|
||||
|
||||
let inode: Result<Arc<dyn IndexNode>, SystemError> =
|
||||
ROOT_INODE().lookup_follow_symlink(path, VFS_MAX_FOLLOW_SYMLINK_TIMES);
|
||||
let inode: Result<Arc<dyn IndexNode>, SystemError> = ROOT_INODE().lookup_follow_symlink(
|
||||
path,
|
||||
if follow_symlink {
|
||||
VFS_MAX_FOLLOW_SYMLINK_TIMES
|
||||
} else {
|
||||
0
|
||||
},
|
||||
);
|
||||
|
||||
let inode: Arc<dyn IndexNode> = if inode.is_err() {
|
||||
let errno = inode.unwrap_err();
|
||||
@ -457,15 +463,12 @@ impl Syscall {
|
||||
/// - `flags`:标志位
|
||||
///
|
||||
///
|
||||
pub fn unlinkat(_dirfd: i32, pathname: &str, flags: u32) -> Result<usize, SystemError> {
|
||||
// kdebug!("sys_unlink_at={path:?}");
|
||||
if (flags & (!AT_REMOVEDIR)) != 0 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
pub fn unlinkat(dirfd: i32, pathname: &str, flags: u32) -> Result<usize, SystemError> {
|
||||
let flags = AtFlags::from_bits(flags as i32).ok_or(SystemError::EINVAL)?;
|
||||
|
||||
if (flags & AT_REMOVEDIR) > 0 {
|
||||
if flags.contains(AtFlags::AT_REMOVEDIR) {
|
||||
// kdebug!("rmdir");
|
||||
match do_remove_dir(&pathname) {
|
||||
match do_remove_dir(dirfd, &pathname) {
|
||||
Err(err) => {
|
||||
kerror!("Failed to Remove Directory, Error Code = {:?}", err);
|
||||
return Err(err);
|
||||
@ -476,7 +479,7 @@ impl Syscall {
|
||||
}
|
||||
}
|
||||
|
||||
match do_unlink_at(&pathname, FileMode::from_bits_truncate(flags as u32)) {
|
||||
match do_unlink_at(dirfd, &pathname) {
|
||||
Err(err) => {
|
||||
kerror!("Failed to Remove Directory, Error Code = {:?}", err);
|
||||
return Err(err);
|
||||
@ -487,6 +490,25 @@ impl Syscall {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unlink(pathname: *const u8) -> Result<usize, SystemError> {
|
||||
if pathname.is_null() {
|
||||
return Err(SystemError::EFAULT);
|
||||
}
|
||||
let ureader = UserBufferReader::new(pathname, MAX_PATHLEN, true)?;
|
||||
|
||||
let buf: &[u8] = ureader.buffer(0).unwrap();
|
||||
|
||||
let pathname: &CStr = CStr::from_bytes_until_nul(buf).map_err(|_| SystemError::EINVAL)?;
|
||||
|
||||
let pathname: &str = pathname.to_str().map_err(|_| SystemError::EINVAL)?;
|
||||
if pathname.len() >= MAX_PATHLEN {
|
||||
return Err(SystemError::ENAMETOOLONG);
|
||||
}
|
||||
let pathname = pathname.trim();
|
||||
|
||||
return do_unlink_at(AtFlags::AT_FDCWD.bits(), pathname).map(|v| v as usize);
|
||||
}
|
||||
|
||||
/// @brief 根据提供的文件描述符的fd,复制对应的文件结构体,并返回新复制的文件结构体对应的fd
|
||||
pub fn dup(oldfd: i32) -> Result<usize, SystemError> {
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
@ -730,13 +752,6 @@ impl Syscall {
|
||||
return Ok(kstat);
|
||||
}
|
||||
|
||||
fn do_stat(path: &str) -> Result<PosixKstat, SystemError> {
|
||||
let fd = Self::open(path, FileMode::O_RDONLY)?;
|
||||
let ret = Self::do_fstat(fd as i32);
|
||||
Self::close(fd)?;
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn fstat(fd: i32, usr_kstat: *mut PosixKstat) -> Result<usize, SystemError> {
|
||||
let kstat = Self::do_fstat(fd)?;
|
||||
if usr_kstat.is_null() {
|
||||
@ -749,11 +764,17 @@ impl Syscall {
|
||||
}
|
||||
|
||||
pub fn stat(path: &str, user_kstat: *mut PosixKstat) -> Result<usize, SystemError> {
|
||||
let fd = Self::open(path, FileMode::O_RDONLY)?;
|
||||
Self::fstat(fd as i32, user_kstat).map_err(|e| {
|
||||
Self::close(fd).ok();
|
||||
e
|
||||
})
|
||||
let fd = Self::open(path, FileMode::O_RDONLY, true)?;
|
||||
let r = Self::fstat(fd as i32, user_kstat);
|
||||
Self::close(fd).ok();
|
||||
return r;
|
||||
}
|
||||
|
||||
pub fn lstat(path: &str, user_kstat: *mut PosixKstat) -> Result<usize, SystemError> {
|
||||
let fd = Self::open(path, FileMode::O_RDONLY, false)?;
|
||||
let r = Self::fstat(fd as i32, user_kstat);
|
||||
Self::close(fd).ok();
|
||||
return r;
|
||||
}
|
||||
|
||||
pub fn mknod(
|
||||
@ -799,6 +820,20 @@ impl Syscall {
|
||||
Self::write(fd, &data)
|
||||
}
|
||||
|
||||
pub fn readv(fd: i32, iov: usize, count: usize) -> Result<usize, SystemError> {
|
||||
// IoVecs会进行用户态检验
|
||||
let mut iovecs = unsafe { IoVecs::from_user(iov as *const IoVec, count, true) }?;
|
||||
|
||||
let mut data = Vec::new();
|
||||
data.resize(iovecs.0.iter().map(|x| x.len()).sum(), 0);
|
||||
|
||||
let len = Self::read(fd, &mut data)?;
|
||||
|
||||
iovecs.scatter(&data[..len]);
|
||||
|
||||
return Ok(len);
|
||||
}
|
||||
|
||||
pub fn readlink_at(
|
||||
dirfd: i32,
|
||||
path: *const u8,
|
||||
@ -840,7 +875,7 @@ impl Syscall {
|
||||
return do_faccessat(
|
||||
AtFlags::AT_FDCWD.bits(),
|
||||
pathname,
|
||||
ModeType::from_bits_truncate(mode),
|
||||
ModeType::from_bits(mode).ok_or(SystemError::EINVAL)?,
|
||||
0,
|
||||
);
|
||||
}
|
||||
@ -851,7 +886,42 @@ impl Syscall {
|
||||
mode: u32,
|
||||
flags: u32,
|
||||
) -> Result<usize, SystemError> {
|
||||
return do_faccessat(dirfd, pathname, ModeType::from_bits_truncate(mode), flags);
|
||||
return do_faccessat(
|
||||
dirfd,
|
||||
pathname,
|
||||
ModeType::from_bits(mode).ok_or(SystemError::EINVAL)?,
|
||||
flags,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn chmod(pathname: *const u8, mode: u32) -> Result<usize, SystemError> {
|
||||
return do_fchmodat(
|
||||
AtFlags::AT_FDCWD.bits(),
|
||||
pathname,
|
||||
ModeType::from_bits(mode).ok_or(SystemError::EINVAL)?,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn fchmodat(dirfd: i32, pathname: *const u8, mode: u32) -> Result<usize, SystemError> {
|
||||
return do_fchmodat(
|
||||
dirfd,
|
||||
pathname,
|
||||
ModeType::from_bits(mode).ok_or(SystemError::EINVAL)?,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn fchmod(fd: i32, mode: u32) -> Result<usize, SystemError> {
|
||||
let _mode = ModeType::from_bits(mode).ok_or(SystemError::EINVAL)?;
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
let fd_table_guard = binding.read();
|
||||
let _file = fd_table_guard
|
||||
.get_file_by_fd(fd)
|
||||
.ok_or(SystemError::EBADF)?;
|
||||
|
||||
// fchmod没完全实现,因此不修改文件的权限
|
||||
// todo: 实现fchmod
|
||||
kwarn!("fchmod not fully implemented");
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ use super::{fcntl::AtFlags, FileType, IndexNode, ROOT_INODE};
|
||||
/// @brief 切分路径字符串,返回最左侧那一级的目录名和剩余的部分。
|
||||
///
|
||||
/// 举例:对于 /123/456/789/ 本函数返回的第一个值为123, 第二个值为456/789
|
||||
#[allow(dead_code)]
|
||||
pub fn split_path(path: &str) -> (&str, Option<&str>) {
|
||||
let mut path_split: core::str::SplitN<&str> = path.trim_matches('/').splitn(2, "/");
|
||||
let comp = path_split.next().unwrap_or("");
|
||||
@ -30,7 +31,7 @@ pub fn rsplit_path(path: &str) -> (&str, Option<&str>) {
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// 返回值为(需要lookup的inode, 剩余的path)
|
||||
/// 返回值为(需要执行lookup的inode, 剩余的path)
|
||||
pub fn user_path_at(
|
||||
pcb: &Arc<ProcessControlBlock>,
|
||||
dirfd: i32,
|
||||
|
@ -128,6 +128,7 @@ impl IndexNode for LockedPipeInode {
|
||||
// 否则在读等待队列中睡眠,并释放锁
|
||||
unsafe {
|
||||
let irq_guard = CurrentIrqArch::save_and_disable_irq();
|
||||
|
||||
inode.read_wait_queue.sleep_without_schedule();
|
||||
drop(inode);
|
||||
|
||||
|
@ -335,6 +335,11 @@ impl Default for SigPending {
|
||||
}
|
||||
|
||||
impl SigPending {
|
||||
/// 判断是否有待处理的信号
|
||||
pub fn has_pending(&self) -> bool {
|
||||
return !self.signal.is_empty();
|
||||
}
|
||||
|
||||
pub fn signal(&self) -> SigSet {
|
||||
self.signal
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_refs_to_cell)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(cstr_from_bytes_until_nul)]
|
||||
#![feature(c_void_variant)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(inline_const)]
|
||||
|
253
kernel/src/process/exit.rs
Normal file
253
kernel/src/process/exit.rs
Normal file
@ -0,0 +1,253 @@
|
||||
use core::intrinsics::likely;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
ipc::signal::{SigChildCode, Signal},
|
||||
sched::sched,
|
||||
CurrentIrqArch,
|
||||
},
|
||||
exception::InterruptArch,
|
||||
syscall::{user_access::UserBufferWriter, SystemError},
|
||||
};
|
||||
|
||||
use super::{
|
||||
abi::WaitOption, pid::PidType, resource::RUsage, Pid, ProcessControlBlock, ProcessManager,
|
||||
ProcessState,
|
||||
};
|
||||
|
||||
/// 内核wait4时的参数
|
||||
#[derive(Debug)]
|
||||
pub struct KernelWaitOption<'a> {
|
||||
pub pid_type: PidType,
|
||||
pub pid: Pid,
|
||||
pub options: WaitOption,
|
||||
pub ret_status: i32,
|
||||
pub ret_info: Option<WaitIdInfo>,
|
||||
pub ret_rusage: Option<&'a mut RUsage>,
|
||||
pub no_task_error: Option<SystemError>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WaitIdInfo {
|
||||
pub pid: Pid,
|
||||
pub status: i32,
|
||||
pub cause: i32,
|
||||
}
|
||||
|
||||
impl<'a> KernelWaitOption<'a> {
|
||||
pub fn new(pid_type: PidType, pid: Pid, options: WaitOption) -> Self {
|
||||
Self {
|
||||
pid_type,
|
||||
pid,
|
||||
options,
|
||||
ret_status: 0,
|
||||
ret_info: None,
|
||||
ret_rusage: None,
|
||||
no_task_error: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kernel_wait4(
|
||||
mut pid: i64,
|
||||
wstatus_buf: Option<UserBufferWriter<'_>>,
|
||||
options: WaitOption,
|
||||
rusage_buf: Option<&mut RUsage>,
|
||||
) -> Result<usize, SystemError> {
|
||||
// i64::MIN is not defined
|
||||
if pid == i64::MIN {
|
||||
return Err(SystemError::ESRCH);
|
||||
}
|
||||
|
||||
// 判断pid类型
|
||||
let pidtype: PidType;
|
||||
|
||||
if pid == -1 {
|
||||
pidtype = PidType::MAX;
|
||||
} else if pid < 0 {
|
||||
pidtype = PidType::PGID;
|
||||
kwarn!("kernel_wait4: currently not support pgid, default to wait for pid\n");
|
||||
pid = -pid;
|
||||
} else if pid == 0 {
|
||||
pidtype = PidType::PGID;
|
||||
kwarn!("kernel_wait4: currently not support pgid, default to wait for pid\n");
|
||||
pid = ProcessManager::current_pcb().pid().data() as i64;
|
||||
} else {
|
||||
pidtype = PidType::PID;
|
||||
}
|
||||
|
||||
let pid = Pid(pid as usize);
|
||||
|
||||
// 构造参数
|
||||
let mut kwo = KernelWaitOption::new(pidtype, pid, options);
|
||||
|
||||
kwo.options.insert(WaitOption::WEXITED);
|
||||
kwo.ret_rusage = rusage_buf;
|
||||
|
||||
// 调用do_wait,执行等待
|
||||
let r = do_wait(&mut kwo)?;
|
||||
|
||||
// 如果有wstatus_buf,则将wstatus写入用户空间
|
||||
if let Some(mut wstatus_buf) = wstatus_buf {
|
||||
let wstatus = if let Some(ret_info) = &kwo.ret_info {
|
||||
ret_info.status
|
||||
} else {
|
||||
kwo.ret_status
|
||||
};
|
||||
wstatus_buf.copy_one_to_user(&wstatus, 0)?;
|
||||
}
|
||||
|
||||
return Ok(r);
|
||||
}
|
||||
|
||||
/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/kernel/exit.c#1573
|
||||
fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
|
||||
let mut retval: Result<usize, SystemError>;
|
||||
// todo: 在signal struct里面增加等待队列,并在这里初始化子进程退出的回调,使得子进程退出时,能唤醒当前进程。
|
||||
|
||||
loop {
|
||||
kwo.no_task_error = Some(SystemError::ECHILD);
|
||||
let child_pcb = ProcessManager::find(kwo.pid).ok_or(SystemError::ECHILD);
|
||||
if kwo.pid_type != PidType::MAX && child_pcb.is_err() {
|
||||
if let Some(err) = &kwo.no_task_error {
|
||||
retval = Err(err.clone());
|
||||
} else {
|
||||
retval = Ok(0);
|
||||
}
|
||||
|
||||
if !kwo.options.contains(WaitOption::WNOHANG) {
|
||||
retval = Err(SystemError::ERESTARTSYS);
|
||||
if ProcessManager::current_pcb()
|
||||
.sig_info_irqsave()
|
||||
.sig_pending()
|
||||
.has_pending()
|
||||
== false
|
||||
{
|
||||
// todo: 增加子进程退出的回调后,这里可以直接等待在自身的child_wait等待队列上。
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if kwo.pid_type == PidType::PID {
|
||||
let child_pcb = child_pcb.unwrap();
|
||||
// 获取weak引用,以便于在do_waitpid中能正常drop pcb
|
||||
let child_weak = Arc::downgrade(&child_pcb);
|
||||
let r = do_waitpid(child_pcb, kwo);
|
||||
if r.is_some() {
|
||||
return r.unwrap();
|
||||
} else {
|
||||
child_weak.upgrade().unwrap().wait_queue.sleep();
|
||||
}
|
||||
} else if kwo.pid_type == PidType::MAX {
|
||||
// 等待任意子进程
|
||||
// todo: 这里有问题!如果正在for循环的过程中,子进程退出了,可能会导致父进程永远等待。
|
||||
let current_pcb = ProcessManager::current_pcb();
|
||||
let rd_childen = current_pcb.children.read();
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
for pid in rd_childen.iter() {
|
||||
let pcb = ProcessManager::find(*pid).ok_or(SystemError::ECHILD)?;
|
||||
if pcb.sched_info().state().is_exited() {
|
||||
kwo.ret_status = pcb.sched_info().state().exit_code().unwrap() as i32;
|
||||
drop(pcb);
|
||||
unsafe { ProcessManager::release(pid.clone()) };
|
||||
return Ok(pid.clone().into());
|
||||
} else {
|
||||
unsafe { pcb.wait_queue.sleep_without_schedule() };
|
||||
}
|
||||
}
|
||||
drop(irq_guard);
|
||||
sched();
|
||||
} else {
|
||||
// todo: 对于pgid的处理
|
||||
kwarn!("kernel_wait4: currently not support {:?}", kwo.pid_type);
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
fn do_waitpid(
|
||||
child_pcb: Arc<ProcessControlBlock>,
|
||||
kwo: &mut KernelWaitOption,
|
||||
) -> Option<Result<usize, SystemError>> {
|
||||
let state = child_pcb.sched_info().state();
|
||||
// 获取退出码
|
||||
match state {
|
||||
ProcessState::Runnable => {
|
||||
if kwo.options.contains(WaitOption::WNOHANG)
|
||||
|| kwo.options.contains(WaitOption::WNOWAIT)
|
||||
{
|
||||
if let Some(info) = &mut kwo.ret_info {
|
||||
*info = WaitIdInfo {
|
||||
pid: child_pcb.pid(),
|
||||
status: Signal::SIGCONT as i32,
|
||||
cause: SigChildCode::Continued.into(),
|
||||
};
|
||||
} else {
|
||||
kwo.ret_status = 0xffff;
|
||||
}
|
||||
|
||||
return Some(Ok(0));
|
||||
}
|
||||
}
|
||||
ProcessState::Blocked(_) | ProcessState::Stopped => {
|
||||
// todo: 在stopped里面,添加code字段,表示停止的原因
|
||||
let exitcode = 0;
|
||||
// 由于目前不支持ptrace,因此这个值为false
|
||||
let ptrace = false;
|
||||
|
||||
if (!ptrace) && (!kwo.options.contains(WaitOption::WUNTRACED)) {
|
||||
kwo.ret_status = 0;
|
||||
return Some(Ok(0));
|
||||
}
|
||||
|
||||
if likely(!(kwo.options.contains(WaitOption::WNOWAIT))) {
|
||||
kwo.ret_status = (exitcode << 8) | 0x7f;
|
||||
}
|
||||
if let Some(infop) = &mut kwo.ret_info {
|
||||
*infop = WaitIdInfo {
|
||||
pid: child_pcb.pid(),
|
||||
status: exitcode,
|
||||
cause: SigChildCode::Stopped.into(),
|
||||
};
|
||||
}
|
||||
|
||||
return Some(Ok(child_pcb.pid().data()));
|
||||
}
|
||||
ProcessState::Exited(status) => {
|
||||
let pid = child_pcb.pid();
|
||||
// kdebug!("wait4: child exited, pid: {:?}, status: {status}\n", pid);
|
||||
|
||||
if likely(!kwo.options.contains(WaitOption::WEXITED)) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// todo: 增加对线程组的group leader的处理
|
||||
|
||||
if let Some(infop) = &mut kwo.ret_info {
|
||||
*infop = WaitIdInfo {
|
||||
pid,
|
||||
status: status as i32,
|
||||
cause: SigChildCode::Exited.into(),
|
||||
};
|
||||
}
|
||||
|
||||
kwo.ret_status = status as i32;
|
||||
|
||||
drop(child_pcb);
|
||||
// kdebug!("wait4: to release {pid:?}");
|
||||
unsafe { ProcessManager::release(pid) };
|
||||
return Some(Ok(pid.into()));
|
||||
}
|
||||
};
|
||||
|
||||
return None;
|
||||
}
|
@ -55,6 +55,7 @@ use self::kthread::WorkerPrivate;
|
||||
pub mod abi;
|
||||
pub mod c_adapter;
|
||||
pub mod exec;
|
||||
pub mod exit;
|
||||
pub mod fork;
|
||||
pub mod idle;
|
||||
pub mod init;
|
||||
@ -473,6 +474,7 @@ impl ProcessState {
|
||||
return matches!(self, ProcessState::Blocked(true));
|
||||
}
|
||||
|
||||
/// Returns `true` if the process state is [`Exited`].
|
||||
#[inline(always)]
|
||||
pub fn is_exited(&self) -> bool {
|
||||
return matches!(self, ProcessState::Exited(_));
|
||||
@ -485,6 +487,15 @@ impl ProcessState {
|
||||
pub fn is_stopped(&self) -> bool {
|
||||
matches!(self, ProcessState::Stopped)
|
||||
}
|
||||
|
||||
/// Returns exit code if the process state is [`Exited`].
|
||||
#[inline(always)]
|
||||
pub fn exit_code(&self) -> Option<usize> {
|
||||
match self {
|
||||
ProcessState::Exited(code) => Some(*code),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
@ -848,6 +859,10 @@ impl ProcessControlBlock {
|
||||
self.sig_info.read()
|
||||
}
|
||||
|
||||
pub fn sig_info_irqsave(&self) -> RwLockReadGuard<ProcessSignalInfo> {
|
||||
self.sig_info.read_irqsave()
|
||||
}
|
||||
|
||||
pub fn try_siginfo(&self, times: u8) -> Option<RwLockReadGuard<ProcessSignalInfo>> {
|
||||
for _ in 0..times {
|
||||
if let Some(r) = self.sig_info.try_read() {
|
||||
|
@ -8,13 +8,13 @@ use alloc::{
|
||||
|
||||
use super::{
|
||||
abi::WaitOption,
|
||||
exit::kernel_wait4,
|
||||
fork::{CloneFlags, KernelCloneArgs},
|
||||
resource::{RLimit64, RLimitID, RUsage, RUsageWho},
|
||||
KernelStack, Pid, ProcessManager, ProcessState,
|
||||
KernelStack, Pid, ProcessManager,
|
||||
};
|
||||
use crate::{
|
||||
arch::{interrupt::TrapFrame, sched::sched, CurrentIrqArch, MMArch},
|
||||
exception::InterruptArch,
|
||||
arch::{interrupt::TrapFrame, MMArch},
|
||||
filesystem::{
|
||||
procfs::procfs_register_pid,
|
||||
vfs::{file::FileDescriptorVec, MAX_PATHLEN},
|
||||
@ -24,9 +24,7 @@ use crate::{
|
||||
process::ProcessControlBlock,
|
||||
sched::completion::Completion,
|
||||
syscall::{
|
||||
user_access::{
|
||||
check_and_clone_cstr, check_and_clone_cstr_array, UserBufferReader, UserBufferWriter,
|
||||
},
|
||||
user_access::{check_and_clone_cstr, check_and_clone_cstr_array, UserBufferWriter},
|
||||
Syscall, SystemError,
|
||||
},
|
||||
};
|
||||
@ -38,11 +36,16 @@ impl Syscall {
|
||||
}
|
||||
|
||||
pub fn vfork(frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||
ProcessManager::fork(
|
||||
frame,
|
||||
CloneFlags::CLONE_VM | CloneFlags::CLONE_FS | CloneFlags::CLONE_SIGNAL,
|
||||
)
|
||||
.map(|pid| pid.into())
|
||||
// 由于Linux vfork需要保证子进程先运行(除非子进程调用execve或者exit),
|
||||
// 而我们目前没有实现这个特性,所以暂时使用fork代替vfork(linux文档表示这样也是也可以的)
|
||||
Self::fork(frame)
|
||||
|
||||
// 下面是以前的实现,除非我们实现了子进程先运行的特性,否则不要使用,不然会导致父进程数据损坏
|
||||
// ProcessManager::fork(
|
||||
// frame,
|
||||
// CloneFlags::CLONE_VM | CloneFlags::CLONE_FS | CloneFlags::CLONE_SIGNAL,
|
||||
// )
|
||||
// .map(|pid| pid.into())
|
||||
}
|
||||
|
||||
pub fn execve(
|
||||
@ -100,98 +103,35 @@ impl Syscall {
|
||||
options: i32,
|
||||
rusage: *mut c_void,
|
||||
) -> Result<usize, SystemError> {
|
||||
let ret = WaitOption::from_bits(options as u32);
|
||||
let options = match ret {
|
||||
Some(options) => options,
|
||||
None => {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
let options = WaitOption::from_bits(options as u32).ok_or(SystemError::EINVAL)?;
|
||||
|
||||
let wstatus_buf = if wstatus.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(UserBufferWriter::new(
|
||||
wstatus,
|
||||
core::mem::size_of::<i32>(),
|
||||
true,
|
||||
)?)
|
||||
};
|
||||
|
||||
let mut _rusage_buf =
|
||||
UserBufferReader::new::<c_void>(rusage, core::mem::size_of::<c_void>(), true)?;
|
||||
|
||||
let mut wstatus_buf =
|
||||
UserBufferWriter::new::<i32>(wstatus, core::mem::size_of::<i32>(), true)?;
|
||||
|
||||
let cur_pcb = ProcessManager::current_pcb();
|
||||
let rd_childen = cur_pcb.children.read();
|
||||
|
||||
if pid > 0 {
|
||||
let pid = Pid(pid as usize);
|
||||
let child_pcb = ProcessManager::find(pid).ok_or(SystemError::ECHILD)?;
|
||||
drop(rd_childen);
|
||||
|
||||
loop {
|
||||
let state = child_pcb.sched_info().state();
|
||||
// 获取退出码
|
||||
match state {
|
||||
ProcessState::Runnable => {
|
||||
if options.contains(WaitOption::WNOHANG)
|
||||
|| options.contains(WaitOption::WNOWAIT)
|
||||
{
|
||||
if !wstatus.is_null() {
|
||||
wstatus_buf.copy_one_to_user(&WaitOption::WCONTINUED.bits(), 0)?;
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
ProcessState::Blocked(_) | ProcessState::Stopped => {
|
||||
// 指定WUNTRACED则等待暂停的进程,不指定则返回0
|
||||
if !options.contains(WaitOption::WUNTRACED)
|
||||
|| options.contains(WaitOption::WNOWAIT)
|
||||
{
|
||||
if !wstatus.is_null() {
|
||||
wstatus_buf.copy_one_to_user(&WaitOption::WSTOPPED.bits(), 0)?;
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
ProcessState::Exited(status) => {
|
||||
// kdebug!("wait4: child exited, pid: {:?}, status: {status}\n", pid);
|
||||
if !wstatus.is_null() {
|
||||
wstatus_buf.copy_one_to_user(
|
||||
&(status as u32 | WaitOption::WEXITED.bits()),
|
||||
0,
|
||||
)?;
|
||||
}
|
||||
drop(child_pcb);
|
||||
// kdebug!("wait4: to release {pid:?}");
|
||||
unsafe { ProcessManager::release(pid) };
|
||||
return Ok(pid.into());
|
||||
}
|
||||
};
|
||||
|
||||
// 等待指定进程
|
||||
child_pcb.wait_queue.sleep();
|
||||
}
|
||||
} else if pid < -1 {
|
||||
// TODO 判断是否pgid == -pid(等待指定组任意进程)
|
||||
// 暂时不支持
|
||||
return Err(SystemError::EINVAL);
|
||||
} else if pid == 0 {
|
||||
// TODO 判断是否pgid == current_pgid(等待当前组任意进程)
|
||||
// 暂时不支持
|
||||
return Err(SystemError::EINVAL);
|
||||
let mut tmp_rusage = if rusage.is_null() {
|
||||
None
|
||||
} else {
|
||||
// 等待任意子进程(这两)
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
for pid in rd_childen.iter() {
|
||||
let pcb = ProcessManager::find(*pid).ok_or(SystemError::ECHILD)?;
|
||||
if pcb.sched_info().state().is_exited() {
|
||||
if !wstatus.is_null() {
|
||||
wstatus_buf.copy_one_to_user(&0, 0)?;
|
||||
}
|
||||
return Ok(pid.clone().into());
|
||||
} else {
|
||||
unsafe { pcb.wait_queue.sleep_without_schedule() };
|
||||
}
|
||||
}
|
||||
drop(irq_guard);
|
||||
sched();
|
||||
}
|
||||
Some(RUsage::default())
|
||||
};
|
||||
|
||||
return Ok(0);
|
||||
let r = kernel_wait4(pid, wstatus_buf, options, tmp_rusage.as_mut())?;
|
||||
|
||||
if !rusage.is_null() {
|
||||
let mut rusage_buf = UserBufferWriter::new::<RUsage>(
|
||||
rusage as *mut RUsage,
|
||||
core::mem::size_of::<RUsage>(),
|
||||
true,
|
||||
)?;
|
||||
rusage_buf.copy_one_to_user(&tmp_rusage.unwrap(), 0)?;
|
||||
}
|
||||
return Ok(r);
|
||||
}
|
||||
|
||||
/// # 退出进程
|
||||
@ -356,16 +296,12 @@ impl Syscall {
|
||||
pub fn prlimit64(
|
||||
_pid: Pid,
|
||||
resource: usize,
|
||||
new_limit: *const RLimit64,
|
||||
_new_limit: *const RLimit64,
|
||||
old_limit: *mut RLimit64,
|
||||
) -> Result<usize, SystemError> {
|
||||
let resource = RLimitID::try_from(resource)?;
|
||||
let mut writer = None;
|
||||
|
||||
if new_limit.is_null() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
if !old_limit.is_null() {
|
||||
writer = Some(UserBufferWriter::new(
|
||||
old_limit,
|
||||
@ -374,8 +310,6 @@ impl Syscall {
|
||||
)?);
|
||||
}
|
||||
|
||||
let _reader = UserBufferReader::new(new_limit, core::mem::size_of::<RLimit64>(), true)?;
|
||||
|
||||
match resource {
|
||||
RLimitID::Stack => {
|
||||
if let Some(mut writer) = writer {
|
||||
|
57
kernel/src/syscall/misc.rs
Normal file
57
kernel/src/syscall/misc.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use crate::arch::mm::LockedFrameAllocator;
|
||||
|
||||
use super::{user_access::UserBufferWriter, Syscall, SystemError};
|
||||
|
||||
#[repr(C)]
|
||||
|
||||
/// 系统信息
|
||||
///
|
||||
/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/include/uapi/linux/sysinfo.h#8
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct SysInfo {
|
||||
uptime: u64,
|
||||
loads: [u64; 3],
|
||||
totalram: u64,
|
||||
freeram: u64,
|
||||
sharedram: u64,
|
||||
bufferram: u64,
|
||||
totalswap: u64,
|
||||
freeswap: u64,
|
||||
procs: u16,
|
||||
pad: u16,
|
||||
totalhigh: u64,
|
||||
freehigh: u64,
|
||||
mem_unit: u32,
|
||||
// 这后面还有一小段,但是我们不需要
|
||||
}
|
||||
|
||||
impl Syscall {
|
||||
pub fn sysinfo(info: *mut SysInfo) -> Result<usize, SystemError> {
|
||||
let mut writer = UserBufferWriter::new(info, core::mem::size_of::<SysInfo>(), true)?;
|
||||
let mut sysinfo = SysInfo::default();
|
||||
|
||||
let mem = LockedFrameAllocator.get_usage();
|
||||
sysinfo.uptime = 0;
|
||||
sysinfo.loads = [0; 3];
|
||||
sysinfo.totalram = mem.total().bytes() as u64;
|
||||
sysinfo.freeram = mem.free().bytes() as u64;
|
||||
sysinfo.sharedram = 0;
|
||||
sysinfo.bufferram = 0;
|
||||
sysinfo.totalswap = 0;
|
||||
sysinfo.freeswap = 0;
|
||||
sysinfo.procs = 0;
|
||||
sysinfo.pad = 0;
|
||||
sysinfo.totalhigh = 0;
|
||||
sysinfo.freehigh = 0;
|
||||
sysinfo.mem_unit = 0;
|
||||
|
||||
writer.copy_one_to_user(&sysinfo, 0)?;
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
pub fn umask(_mask: u32) -> Result<usize, SystemError> {
|
||||
kwarn!("SYS_UMASK has not yet been implemented\n");
|
||||
return Ok(0o777);
|
||||
}
|
||||
}
|
@ -4,7 +4,10 @@ use core::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
arch::syscall::{SYS_ACCESS, SYS_FACCESSAT, SYS_FACCESSAT2, SYS_PRLIMIT64},
|
||||
arch::syscall::{
|
||||
SYS_ACCESS, SYS_CHMOD, SYS_CLOCK_GETTIME, SYS_FACCESSAT, SYS_FACCESSAT2, SYS_FCHMOD,
|
||||
SYS_FCHMODAT, SYS_LSTAT, SYS_PRLIMIT64, SYS_READV, SYS_SYSINFO, SYS_UMASK, SYS_UNLINK,
|
||||
},
|
||||
libs::{futex::constant::FutexFlag, rand::GRandFlags},
|
||||
process::{
|
||||
fork::KernelCloneArgs,
|
||||
@ -35,8 +38,12 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use self::user_access::{UserBufferReader, UserBufferWriter};
|
||||
use self::{
|
||||
misc::SysInfo,
|
||||
user_access::{UserBufferReader, UserBufferWriter},
|
||||
};
|
||||
|
||||
pub mod misc;
|
||||
pub mod user_access;
|
||||
|
||||
#[repr(i32)]
|
||||
@ -317,6 +324,9 @@ pub enum SystemError {
|
||||
EVMPRTLDFailed = 135,
|
||||
EVMLAUNCHFailed = 136,
|
||||
KVM_HVA_ERR_BAD = 137,
|
||||
|
||||
// === 以下错误码不应该被用户态程序使用 ===
|
||||
ERESTARTSYS = 512,
|
||||
}
|
||||
|
||||
impl SystemError {
|
||||
@ -383,7 +393,6 @@ pub const SYS_SOCKET_PAIR: usize = 53;
|
||||
pub const SYS_SETSOCKOPT: usize = 54;
|
||||
pub const SYS_GETSOCKOPT: usize = 55;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const SYS_CLONE: usize = 56;
|
||||
pub const SYS_FORK: usize = 57;
|
||||
pub const SYS_VFORK: usize = 58;
|
||||
@ -507,7 +516,7 @@ impl Syscall {
|
||||
|
||||
let flags = args[1];
|
||||
let open_flags: FileMode = FileMode::from_bits_truncate(flags as u32);
|
||||
Self::open(path, open_flags)
|
||||
Self::open(path, open_flags, true)
|
||||
};
|
||||
res
|
||||
}
|
||||
@ -657,13 +666,13 @@ impl Syscall {
|
||||
}
|
||||
}
|
||||
SYS_WAIT4 => {
|
||||
let pid = args[0] as i64;
|
||||
let pid = args[0] as i32;
|
||||
let wstatus = args[1] as *mut i32;
|
||||
let options = args[2] as c_int;
|
||||
let rusage = args[3] as *mut c_void;
|
||||
// 权限校验
|
||||
// todo: 引入rusage之后,更正以下权限校验代码中,rusage的大小
|
||||
Self::wait4(pid, wstatus, options, rusage)
|
||||
Self::wait4(pid.into(), wstatus, options, rusage)
|
||||
}
|
||||
|
||||
SYS_EXIT => {
|
||||
@ -754,6 +763,11 @@ impl Syscall {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SYS_UNLINK => {
|
||||
let pathname = args[0] as *const u8;
|
||||
Self::unlink(pathname)
|
||||
}
|
||||
SYS_KILL => {
|
||||
let pid = Pid::new(args[0]);
|
||||
let sig = args[1] as c_int;
|
||||
@ -1093,13 +1107,14 @@ impl Syscall {
|
||||
Self::do_futex(uaddr, operation, val, timespec, uaddr2, utime as u32, val3)
|
||||
}
|
||||
|
||||
SYS_READV => Self::readv(args[0] as i32, args[1], args[2]),
|
||||
SYS_WRITEV => Self::writev(args[0] as i32, args[1], args[2]),
|
||||
|
||||
SYS_ARCH_PRCTL => Self::arch_prctl(args[0], args[1]),
|
||||
|
||||
SYS_SET_TID_ADDR => Self::set_tid_address(args[0]),
|
||||
|
||||
SYS_STAT => {
|
||||
SYS_STAT | SYS_LSTAT => {
|
||||
let path: &CStr = unsafe { CStr::from_ptr(args[0] as *const c_char) };
|
||||
let path: Result<&str, core::str::Utf8Error> = path.to_str();
|
||||
let res = if path.is_err() {
|
||||
@ -1109,7 +1124,13 @@ impl Syscall {
|
||||
let kstat = args[1] as *mut PosixKstat;
|
||||
let vaddr = VirtAddr::new(kstat as usize);
|
||||
match verify_area(vaddr, core::mem::size_of::<PosixKstat>()) {
|
||||
Ok(_) => Self::stat(path, kstat),
|
||||
Ok(_) => {
|
||||
if syscall_num == SYS_STAT {
|
||||
Self::stat(path, kstat)
|
||||
} else {
|
||||
Self::lstat(path, kstat)
|
||||
}
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
};
|
||||
@ -1225,6 +1246,39 @@ impl Syscall {
|
||||
Self::faccessat2(dirfd, pathname, mode, flags)
|
||||
}
|
||||
|
||||
SYS_CLOCK_GETTIME => {
|
||||
let clockid = args[0] as i32;
|
||||
let timespec = args[1] as *mut TimeSpec;
|
||||
Self::clock_gettime(clockid, timespec)
|
||||
}
|
||||
|
||||
SYS_SYSINFO => {
|
||||
let info = args[0] as *mut SysInfo;
|
||||
Self::sysinfo(info)
|
||||
}
|
||||
|
||||
SYS_UMASK => {
|
||||
let mask = args[0] as u32;
|
||||
Self::umask(mask)
|
||||
}
|
||||
|
||||
SYS_CHMOD => {
|
||||
let pathname = args[0] as *const u8;
|
||||
let mode = args[1] as u32;
|
||||
Self::chmod(pathname, mode)
|
||||
}
|
||||
SYS_FCHMOD => {
|
||||
let fd = args[0] as i32;
|
||||
let mode = args[1] as u32;
|
||||
Self::fchmod(fd, mode)
|
||||
}
|
||||
SYS_FCHMODAT => {
|
||||
let dirfd = args[0] as i32;
|
||||
let pathname = args[1] as *const u8;
|
||||
let mode = args[2] as u32;
|
||||
Self::fchmodat(dirfd, pathname, mode)
|
||||
}
|
||||
|
||||
_ => panic!("Unsupported syscall ID: {}", syscall_num),
|
||||
};
|
||||
return r;
|
||||
|
@ -223,6 +223,17 @@ impl<'a> UserBufferReader<'a> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 把用户空间的数据转换成指定类型的切片
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `offset`:字节偏移量
|
||||
pub fn buffer<T>(&self, offset: usize) -> Result<&[T], SystemError> {
|
||||
Ok(self
|
||||
.convert_with_offset::<T>(self.buffer, offset)
|
||||
.map_err(|_| SystemError::EINVAL)?)
|
||||
}
|
||||
|
||||
fn convert_with_offset<T>(&self, src: &[u8], offset: usize) -> Result<&[T], SystemError> {
|
||||
if offset >= src.len() {
|
||||
return Err(SystemError::EINVAL);
|
||||
|
@ -3,6 +3,8 @@ use core::{
|
||||
ptr::null_mut,
|
||||
};
|
||||
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use crate::{
|
||||
syscall::{user_access::UserBufferWriter, Syscall, SystemError},
|
||||
time::{sleep::nanosleep, TimeSpec},
|
||||
@ -36,6 +38,29 @@ pub const SYS_TIMEZONE: PosixTimeZone = PosixTimeZone {
|
||||
tz_dsttime: 0,
|
||||
};
|
||||
|
||||
/// The IDs of the various system clocks (for POSIX.1b interval timers):
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive)]
|
||||
pub enum PosixClockID {
|
||||
Realtime = 0,
|
||||
Monotonic = 1,
|
||||
ProcessCPUTimeID = 2,
|
||||
ThreadCPUTimeID = 3,
|
||||
MonotonicRaw = 4,
|
||||
RealtimeCoarse = 5,
|
||||
MonotonicCoarse = 6,
|
||||
Boottime = 7,
|
||||
RealtimeAlarm = 8,
|
||||
BoottimeAlarm = 9,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for PosixClockID {
|
||||
type Error = SystemError;
|
||||
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
<Self as FromPrimitive>::from_i32(value).ok_or(SystemError::EINVAL)
|
||||
}
|
||||
}
|
||||
|
||||
impl Syscall {
|
||||
/// @brief 休眠指定时间(单位:纳秒)(提供给C的接口)
|
||||
///
|
||||
@ -107,4 +132,22 @@ impl Syscall {
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
pub fn clock_gettime(clock_id: c_int, tp: *mut TimeSpec) -> Result<usize, SystemError> {
|
||||
let clock_id = PosixClockID::try_from(clock_id)?;
|
||||
if clock_id != PosixClockID::Realtime {
|
||||
kwarn!("clock_gettime: currently only support Realtime clock, but got {:?}. Defaultly return realtime!!!\n", clock_id);
|
||||
}
|
||||
if tp.is_null() {
|
||||
return Err(SystemError::EFAULT);
|
||||
}
|
||||
let mut tp_buf =
|
||||
UserBufferWriter::new::<TimeSpec>(tp, core::mem::size_of::<TimeSpec>(), true)?;
|
||||
|
||||
let posix_time = do_gettimeofday();
|
||||
|
||||
tp_buf.copy_one_to_user(&posix_time, 0)?;
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user