From b53f99b169a031eec9804408f947f4761f94a0d1 Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Wed, 9 Nov 2022 15:14:12 +0800 Subject: [PATCH] refactor the implementation of wait --- src/kxos-frame/src/config.rs | 2 +- src/kxos-frame/src/error.rs | 1 + src/kxos-frame/src/sync/rcu/mod.rs | 4 +- src/kxos-frame/src/sync/wait.rs | 315 ++++++++++++--------- src/kxos-frame/src/task/mod.rs | 2 +- src/kxos-frame/src/user.rs | 9 +- src/kxos-frame/src/x86_64_util.rs | 4 - src/kxos-std/src/error.rs | 7 + src/kxos-std/src/lib.rs | 26 +- src/kxos-std/src/memory/mod.rs | 17 +- src/kxos-std/src/process/clone.rs | 4 +- src/kxos-std/src/process/elf/elf.rs | 9 +- src/kxos-std/src/process/elf/init_stack.rs | 135 +++++---- src/kxos-std/src/process/elf/mod.rs | 4 +- src/kxos-std/src/process/mod.rs | 86 +++--- src/kxos-std/src/process/task.rs | 8 +- src/kxos-std/src/process/wait.rs | 57 ++-- src/kxos-std/src/syscall/access.rs | 10 +- src/kxos-std/src/syscall/arch_prctl.rs | 6 +- src/kxos-std/src/syscall/brk.rs | 6 +- src/kxos-std/src/syscall/clone.rs | 7 +- src/kxos-std/src/syscall/constants.rs | 5 + src/kxos-std/src/syscall/execve.rs | 47 ++- src/kxos-std/src/syscall/fstat.rs | 13 +- src/kxos-std/src/syscall/futex.rs | 197 +++++++++---- src/kxos-std/src/syscall/getegid.rs | 2 +- src/kxos-std/src/syscall/geteuid.rs | 2 +- src/kxos-std/src/syscall/getgid.rs | 2 +- src/kxos-std/src/syscall/getpid.rs | 6 +- src/kxos-std/src/syscall/gettid.rs | 4 +- src/kxos-std/src/syscall/getuid.rs | 2 +- src/kxos-std/src/syscall/kill.rs | 4 + src/kxos-std/src/syscall/mmap.rs | 14 +- src/kxos-std/src/syscall/mprotect.rs | 9 +- src/kxos-std/src/syscall/readlink.rs | 10 +- src/kxos-std/src/syscall/rt_sigaction.rs | 10 +- src/kxos-std/src/syscall/rt_sigprocmask.rs | 10 +- src/kxos-std/src/syscall/rt_sigreturn.rs | 3 +- src/kxos-std/src/syscall/tgkill.rs | 4 +- src/kxos-std/src/syscall/uname.rs | 14 +- src/kxos-std/src/syscall/wait4.rs | 13 +- src/kxos-std/src/syscall/waitid.rs | 2 +- src/kxos-std/src/syscall/write.rs | 4 + src/kxos-std/src/syscall/writev.rs | 13 +- src/kxos-user/execve/execve | 2 +- src/kxos-user/execve/execve.c | 4 +- src/kxos-user/execve/hello | 4 +- src/kxos-user/execve/hello.c | 12 +- 48 files changed, 664 insertions(+), 467 deletions(-) diff --git a/src/kxos-frame/src/config.rs b/src/kxos-frame/src/config.rs index f62b6c64a..99cb14c4a 100644 --- a/src/kxos-frame/src/config.rs +++ b/src/kxos-frame/src/config.rs @@ -15,4 +15,4 @@ pub const PAGE_SIZE_BITS: usize = 0xc; pub const KVA_START: usize = (usize::MAX) << PAGE_SIZE_BITS; -pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Close; +pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Info; diff --git a/src/kxos-frame/src/error.rs b/src/kxos-frame/src/error.rs index a38e28332..dad88c604 100644 --- a/src/kxos-frame/src/error.rs +++ b/src/kxos-frame/src/error.rs @@ -8,4 +8,5 @@ pub enum Error { IoError, InvalidVmpermBits, NotEnoughResources, + NoChild, } diff --git a/src/kxos-frame/src/sync/rcu/mod.rs b/src/kxos-frame/src/sync/rcu/mod.rs index 09f3d97c1..d6dccfeac 100644 --- a/src/kxos-frame/src/sync/rcu/mod.rs +++ b/src/kxos-frame/src/sync/rcu/mod.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use core::ops::Deref; use core::sync::atomic::{ AtomicPtr, - Ordering::{AcqRel, Acquire, Release}, + Ordering::{AcqRel, Acquire}, }; use self::monitor::RcuMonitor; @@ -89,7 +89,7 @@ impl

Drop for RcuReclaimer

{ wq.wake_one(); } }); - wq.wait_until(None::, || Some(0)); + wq.wait_until(|| Ok(Some(0u8))).unwrap(); } } diff --git a/src/kxos-frame/src/sync/wait.rs b/src/kxos-frame/src/sync/wait.rs index ef3fd0311..c7f23d1bf 100644 --- a/src/kxos-frame/src/sync/wait.rs +++ b/src/kxos-frame/src/sync/wait.rs @@ -1,9 +1,11 @@ use core::sync::atomic::{AtomicBool, Ordering}; -use alloc::{collections::VecDeque, sync::Arc, vec::Vec}; +use crate::prelude::*; +use alloc::{collections::VecDeque, sync::Arc}; +use bitflags::bitflags; use spin::mutex::Mutex; -use crate::task::Task; +use crate::task::schedule; /// A wait queue. /// @@ -11,11 +13,11 @@ use crate::task::Task; /// Multiple threads may be the waiters of a wait queue. /// Other threads may invoke the `wake`-family methods of a wait queue to /// wake up one or many waiter threads. -pub struct WaitQueue { - waiters: Mutex>>, +pub struct WaitQueue { + waiters: Mutex>>, } -impl WaitQueue { +impl WaitQueue { /// Creates a new instance. pub fn new() -> Self { WaitQueue { @@ -33,16 +35,22 @@ impl WaitQueue { /// /// By taking a condition closure, his wait-wakeup mechanism becomes /// more efficient and robust. - pub fn wait_until(&self, data: D, mut cond: F) -> R + pub fn wait_until(&self, mut cond: F) -> Result where - F: FnMut() -> Option, + F: FnMut() -> Result>, { - let waiter = Arc::new(Waiter::new(data)); - self.enqueue_waiter(&waiter); + let waiter = Arc::new(Waiter::new()); + self.enqueue(&waiter); loop { - if let Some(r) = cond() { - self.dequeue_waiter(&waiter); - return r; + let ret_value = match cond() { + Ok(Some(ret_value)) => Some(Ok(ret_value)), + Ok(None) => None, + Err(err) => Some(Err(err)), + }; + if let Some(ret_value) = ret_value { + waiter.set_finished(); + self.finish_wait(); + return ret_value; } waiter.wait(); } @@ -52,17 +60,17 @@ impl WaitQueue { /// Note this func cannot be implemented with wait_until. This func always requires the waiter become woken. /// While wait_until does not check the waiter if cond is true. /// TODO: This function can take a timeout param further. - pub fn wait_on(&self, data: D) { - let index = self - .waiters - .lock() - .iter() - .position(|waiter| *waiter.data() == data); - if let Some(index) = index { - let waiter = self.waiters.lock().iter().nth(index).unwrap().clone(); - waiter.wait(); - } - } + // pub fn wait_on(&self, data: D) { + // let index = self + // .waiters + // .lock() + // .iter() + // .position(|waiter| *waiter.data() == data); + // if let Some(index) = index { + // let waiter = self.waiters.lock().iter().nth(index).unwrap().clone(); + // waiter.wait(); + // } + // } /// Wake one waiter thread, if there is one. pub fn wake_one(&self) { @@ -71,163 +79,196 @@ impl WaitQueue { } } - /// Wake all waiter threads. + /// Wake all not-exclusive waiter threads and at most one exclusive waiter. pub fn wake_all(&self) { - self.waiters.lock().iter().for_each(|waiter| { + for waiter in self.waiters.lock().iter() { waiter.wake_up(); - }); + if waiter.is_exclusive() { + break; + } + } } /// Wake all waiters if given condition returns true. /// The condition will check the data carried by waiter if it satisfy some relation with cond_data - pub fn wake_all_on_condition(&self, cond_data: &C, cond: F) - where - F: Fn(&D, &C) -> bool, - { - self.waiters.lock().iter().for_each(|waiter| { - if cond(waiter.data(), cond_data) { - waiter.wake_up() - } - }) - } + // pub fn wake_all_on_condition(&self, cond_data: &C, cond: F) + // where + // F: Fn(&D, &C) -> bool, + // { + // self.waiters.lock().iter().for_each(|waiter| { + // if cond(waiter.data(), cond_data) { + // waiter.wake_up() + // } + // }) + // } /// Wake at most max_count waiters if given condition is true. /// returns the number of woken waiters - pub fn batch_wake_and_deque(&self, max_count: usize, cond_data: &C, cond: F) -> usize - where - F: Fn(&D, &C) -> bool, - { - let mut count = 0; - let mut waiters_to_wake = Vec::new(); - self.waiters.lock().retain(|waiter| { - if count >= max_count || waiter.is_woken_up() || !cond(waiter.data(), cond_data) { - true - } else { - waiters_to_wake.push(waiter.clone()); - count += 1; - false - } - }); - waiters_to_wake.into_iter().for_each(|waiter| { - waiter.wake_up(); - }); - return count; - } + // pub fn batch_wake_and_deque(&self, max_count: usize, cond_data: &C, cond: F) -> usize + // where + // F: Fn(&D, &C) -> bool, + // { + // let mut count = 0; + // let mut waiters_to_wake = Vec::new(); + // self.waiters.lock().retain(|waiter| { + // if count >= max_count || waiter.is_woken_up() || !cond(waiter.data(), cond_data) { + // true + // } else { + // waiters_to_wake.push(waiter.clone()); + // count += 1; + // false + // } + // }); + // waiters_to_wake.into_iter().for_each(|waiter| { + // waiter.wake_up(); + // }); + // return count; + // } /// create a waiter with given data, and enqueue - pub fn enqueue(&self, data: D) { - let waiter = Arc::new(Waiter::new(data)); - self.enqueue_waiter(&waiter); - } + // pub fn enqueue(&self) { + // let waiter = Arc::new(Waiter::new(data)); + // self.enqueue_waiter(&waiter); + // } /// dequeue a waiter with given data - pub fn dequeue(&self, data: D) { - let waiter = Arc::new(Waiter::new(data)); - self.dequeue_waiter(&waiter); - } + // pub fn dequeue(&self, data: D) { + // let waiter = Arc::new(Waiter::new(data)); + // self.dequeue_waiter(&waiter); + // } /// update the waiters data /// if cond(old_data, old_value) is true. /// The new data should be calculated by get_new_data(old_data, new_value). - pub fn update_waiters_data( - &self, - cond: F1, - old_value: &C, - new_value: &C, - get_new_data: F2, - max_count: usize, - ) where - F1: Fn(&C, &D) -> bool, - F2: Fn(&D, &C) -> D, - { - let mut waiters = self.waiters.lock(); - let len = waiters.len(); - let mut count = 0; - for index in 0..len { - let waiter = &waiters[index]; - let old_data = waiter.data(); - if cond(old_value, waiter.data()) { - let new_data = get_new_data(old_data, new_value); - let new_waiter = Arc::new(Waiter::new(new_data)); - waiters[index] = new_waiter; - count += 1; - if count >= max_count { - break; - } - } - } - } + // pub fn update_waiters_data( + // &self, + // cond: F1, + // old_value: &C, + // new_value: &C, + // get_new_data: F2, + // max_count: usize, + // ) where + // F1: Fn(&C, &D) -> bool, + // F2: Fn(&D, &C) -> D, + // { + // let mut waiters = self.waiters.lock(); + // let len = waiters.len(); + // let mut count = 0; + // for index in 0..len { + // let waiter = &waiters[index]; + // let old_data = waiter.data(); + // if cond(old_value, waiter.data()) { + // let new_data = get_new_data(old_data, new_value); + // let new_waiter = Arc::new(Waiter::new(new_data)); + // waiters[index] = new_waiter; + // count += 1; + // if count >= max_count { + // break; + // } + // } + // } + // } /// remove waiters for which the cond returns true - pub fn remove_waiters(&self, cond: F, cond_data: &C, max_count: usize) -> Vec - where - F: Fn(&D, &C) -> bool, - { - let mut removed_waiters = Vec::new(); - let mut count = 0; - self.waiters.lock().retain(|waiter| { - let data = waiter.data(); - if count >= max_count || !cond(data, cond_data) { - true - } else { - count += 1; - removed_waiters.push(data.clone()); - false - } - }); + // pub fn remove_waiters(&self, cond: F, cond_data: &C, max_count: usize) -> Vec + // where + // F: Fn(&D, &C) -> bool, + // { + // let mut removed_waiters = Vec::new(); + // let mut count = 0; + // self.waiters.lock().retain(|waiter| { + // let data = waiter.data(); + // if count >= max_count || !cond(data, cond_data) { + // true + // } else { + // count += 1; + // removed_waiters.push(data.clone()); + // false + // } + // }); - removed_waiters - } + // removed_waiters + // } - fn enqueue_waiter(&self, waiter_ref: &WaiterRef) { - self.waiters.lock().push_back(waiter_ref.clone()); - } - - fn dequeue_waiter(&self, waiter_ref: &WaiterRef) { - let mut waiters_lock = self.waiters.lock(); - let index = waiters_lock - .iter() - .position(|waiter_| *waiter_ref.data() == *waiter_.data()); - if let Some(index) = index { - waiters_lock.remove(index); + // enqueue a waiter into current waitqueue. If waiter is exclusive, add to the back of waitqueue. + // Otherwise, add to the front of waitqueue + fn enqueue(&self, waiter: &Arc) { + if waiter.is_exclusive() { + self.waiters.lock().push_back(waiter.clone()) + } else { + self.waiters.lock().push_front(waiter.clone()); } - drop(waiters_lock); } -} -type WaiterRef = Arc>; + /// removes all waiters that have finished wait + fn finish_wait(&self) { + self.waiters.lock().retain(|waiter| !waiter.is_finished()) + } + + // fn dequeue_waiter(&self, waiter_ref: &WaiterRef) { + // let mut waiters_lock = self.waiters.lock(); + // let index = waiters_lock + // .iter() + // .position(|waiter_| *waiter_ref.data() == *waiter_.data()); + // if let Some(index) = index { + // waiters_lock.remove(index); + // } + // drop(waiters_lock); + // } +} #[derive(Debug)] -struct Waiter { +struct Waiter { + /// Whether the is_woken_up: AtomicBool, - data: D, + /// To respect different wait condition + flag: WaiterFlag, + /// if the wait condition is ture, then the waiter is finished and can be removed from waitqueue + wait_finished: AtomicBool, } -impl Waiter { - pub fn new(data: D) -> Self { +impl Waiter { + pub fn new() -> Self { Waiter { is_woken_up: AtomicBool::new(false), - data, + flag: WaiterFlag::empty(), + wait_finished: AtomicBool::new(false), } } + /// make self into wait status until be called wake up pub fn wait(&self) { - while !self.is_woken_up.load(Ordering::Relaxed) { - // yield the execution, to allow other task to contine - // debug!("Waiter: wait"); - Task::yield_now(); + self.is_woken_up.store(false, Ordering::SeqCst); + while !self.is_woken_up.load(Ordering::SeqCst) { + // yield the execution, to allow other task to continue + schedule(); } } pub fn is_woken_up(&self) -> bool { - self.is_woken_up.load(Ordering::Relaxed) + self.is_woken_up.load(Ordering::SeqCst) } pub fn wake_up(&self) { - self.is_woken_up.store(true, Ordering::Relaxed); + self.is_woken_up.store(true, Ordering::SeqCst); } - pub fn data(&self) -> &D { - &self.data + pub fn set_finished(&self) { + self.wait_finished.store(true, Ordering::SeqCst); + } + + pub fn is_finished(&self) -> bool { + self.wait_finished.load(Ordering::SeqCst) + } + + pub fn is_exclusive(&self) -> bool { + self.flag.contains(WaiterFlag::EXCLUSIVE) + } +} + +bitflags! { + pub struct WaiterFlag: u32 { + const EXCLUSIVE = 0x1; + const INTERRUPTIABLE = 0x10; } } diff --git a/src/kxos-frame/src/task/mod.rs b/src/kxos-frame/src/task/mod.rs index 8bb868ed3..57b64a2a5 100644 --- a/src/kxos-frame/src/task/mod.rs +++ b/src/kxos-frame/src/task/mod.rs @@ -5,7 +5,7 @@ mod scheduler; #[allow(clippy::module_inception)] mod task; -pub(crate) use self::processor::get_idle_task_cx_ptr; +pub(crate) use self::processor::{get_idle_task_cx_ptr, schedule}; pub use self::scheduler::{set_scheduler, Scheduler}; pub(crate) use self::task::context_switch; pub(crate) use self::task::TaskContext; diff --git a/src/kxos-frame/src/user.rs b/src/kxos-frame/src/user.rs index b4afd1537..9f810c03c 100644 --- a/src/kxos-frame/src/user.rs +++ b/src/kxos-frame/src/user.rs @@ -118,7 +118,6 @@ impl<'a> UserMode<'a> { *self.current.syscall_frame() = self.user_space.cpu_ctx.into(); self.current.syscall_frame().caller.rcx = self.user_space.cpu_ctx.gp_regs.rip; // write fsbase - debug!("write fs_fsbase: 0x{:x}", self.user_space.cpu_ctx.fs_base); wrfsbase(self.user_space.cpu_ctx.fs_base); self.executed = true; @@ -157,10 +156,10 @@ impl<'a> UserMode<'a> { } else { self.context = CpuContext::from(*self.current.syscall_frame()); self.context.fs_base = rdfsbase(); - debug!("[kernel] syscall id:{}", self.context.gp_regs.rax); - debug!("[kernel] rsp: 0x{:x}", self.context.gp_regs.rsp); - debug!("[kernel] rcx: 0x{:x}", self.context.gp_regs.rcx); - debug!("[kernel] rip: 0x{:x}", self.context.gp_regs.rip); + // debug!("[kernel] syscall id:{}", self.context.gp_regs.rax); + // debug!("[kernel] rsp: 0x{:x}", self.context.gp_regs.rsp); + // debug!("[kernel] rcx: 0x{:x}", self.context.gp_regs.rcx); + // debug!("[kernel] rip: 0x{:x}", self.context.gp_regs.rip); UserEvent::Syscall } } diff --git a/src/kxos-frame/src/x86_64_util.rs b/src/kxos-frame/src/x86_64_util.rs index 732330196..1ad85820d 100644 --- a/src/kxos-frame/src/x86_64_util.rs +++ b/src/kxos-frame/src/x86_64_util.rs @@ -3,8 +3,6 @@ use core::arch::asm; use x86_64::registers::{control::Cr4Flags, segmentation::Segment64, xcontrol::XCr0Flags}; -use crate::debug; - #[inline(always)] pub fn read_rsp() -> usize { let val: usize; @@ -221,14 +219,12 @@ pub fn enable_common_cpu_features() { unsafe { x86_64::registers::control::Cr4::write(cr4); } - debug!("cr4: {:?}", cr4); let mut xcr0 = x86_64::registers::xcontrol::XCr0::read(); xcr0 |= XCr0Flags::AVX | XCr0Flags::SSE; unsafe { x86_64::registers::xcontrol::XCr0::write(xcr0); } - debug!("xcr0: {:?}", xcr0); } pub fn flush_tlb() { diff --git a/src/kxos-std/src/error.rs b/src/kxos-std/src/error.rs index e0ee52cfc..63c819ba0 100644 --- a/src/kxos-std/src/error.rs +++ b/src/kxos-std/src/error.rs @@ -188,6 +188,7 @@ impl From for Error { kxos_frame::Error::NotEnoughResources => Error::new(Errno::EBUSY), kxos_frame::Error::PageFault => Error::new(Errno::EFAULT), kxos_frame::Error::InvalidVmpermBits => Error::new(Errno::EINVAL), + kxos_frame::Error::NoChild => Error::new(Errno::ECHILD), } } } @@ -198,6 +199,12 @@ impl From for Error { } } +impl From for Error { + fn from(_: core::ffi::FromBytesUntilNulError) -> Self { + Error::with_message(Errno::E2BIG, "Cannot find null in cstring") + } +} + #[macro_export] macro_rules! return_errno { ($errno: expr) => { diff --git a/src/kxos-std/src/lib.rs b/src/kxos-std/src/lib.rs index dd1f109da..19ae2ecfb 100644 --- a/src/kxos-std/src/lib.rs +++ b/src/kxos-std/src/lib.rs @@ -10,10 +10,17 @@ #![feature(btree_drain_filter)] #![feature(const_option)] -use kxos_frame::{debug, info, println}; +use crate::prelude::*; +use kxos_frame::{info, println}; use process::Process; -use crate::user_apps::get_all_apps; +use crate::{ + process::{ + process_filter::ProcessFilter, + wait::{wait_child_exit, WaitOptions}, + }, + user_apps::get_all_apps, +}; extern crate alloc; @@ -37,12 +44,15 @@ pub fn init() { } pub fn init_process() { - println!("[kernel] Spawn init process!"); + println!("[kernel] Spawn init process!, pid = {}", current!().pid()); driver::pci::virtio::block::block_device_test(); let process = Process::spawn_kernel_process(|| { println!("[kernel] Hello world from kernel!"); - let pid = Process::current().pid(); - debug!("current pid = {}", pid); + let current = current!(); + let pid = current.pid(); + info!("current pid = {}", pid); + let ppid = current.parent().unwrap().pid(); + info!("current ppid = {}", ppid); }); info!( "[kxos-std/lib.rs] spawn kernel process, pid = {}", @@ -52,7 +62,8 @@ pub fn init_process() { for app in get_all_apps() { let app_name = app.app_name(); info!("[kxos-std/lib.rs] spwan {:?} process", app.app_name()); - let process = Process::spawn_user_process(app_name, app.app_content()); + let argv = vec![app_name.clone()]; + let process = Process::spawn_user_process(app_name, app.app_content(), argv, Vec::new()); info!( "[kxos-std/lib.rs] {:?} process exits, pid = {}", app.app_name(), @@ -63,7 +74,8 @@ pub fn init_process() { loop { // We don't have preemptive scheduler now. // The long running init process should yield its own execution to allow other tasks to go on. - Process::yield_now(); + // The init process should wait and reap all children. + let _ = wait_child_exit(ProcessFilter::Any, WaitOptions::empty()); } } diff --git a/src/kxos-std/src/memory/mod.rs b/src/kxos-std/src/memory/mod.rs index 496fc467f..3849085ee 100644 --- a/src/kxos-std/src/memory/mod.rs +++ b/src/kxos-std/src/memory/mod.rs @@ -3,11 +3,9 @@ use kxos_frame::vm::{Pod, VmIo}; pub mod vm_page; -use crate::process::Process; - /// copy bytes from user space of current process. The bytes len is the len of dest. pub fn read_bytes_from_user(src: Vaddr, dest: &mut [u8]) -> Result<()> { - let current = Process::current(); + let current = current!(); let vm_space = current.vm_space().ok_or(Error::with_message( Errno::ESRCH, "[Internal error]Current should have vm space to copy bytes from user", @@ -18,7 +16,7 @@ pub fn read_bytes_from_user(src: Vaddr, dest: &mut [u8]) -> Result<()> { /// copy val (Plain of Data type) from user space of current process. pub fn read_val_from_user(src: Vaddr) -> Result { - let current = Process::current(); + let current = current!(); let vm_space = current.vm_space().ok_or(Error::with_message( Errno::ESRCH, "[Internal error]Current should have vm space to copy val from user", @@ -28,7 +26,7 @@ pub fn read_val_from_user(src: Vaddr) -> Result { /// write bytes from user space of current process. The bytes len is the len of src. pub fn write_bytes_to_user(dest: Vaddr, src: &[u8]) -> Result<()> { - let current = Process::current(); + let current = current!(); let vm_space = current.vm_space().ok_or(Error::with_message( Errno::ESRCH, "[Internal error]Current should have vm space to write bytes to user", @@ -39,7 +37,7 @@ pub fn write_bytes_to_user(dest: Vaddr, src: &[u8]) -> Result<()> { /// write val (Plain of Data type) to user space of current process. pub fn write_val_to_user(dest: Vaddr, val: &T) -> Result<()> { - let current = Process::current(); + let current = current!(); let vm_space = current.vm_space().ok_or(Error::with_message( Errno::ESRCH, "[Internal error]Current should have vm space to write val to user", @@ -47,3 +45,10 @@ pub fn write_val_to_user(dest: Vaddr, val: &T) -> Result<()> { vm_space.write_val(dest, val)?; Ok(()) } + +/// read a cstring from user, the length of cstring should not exceed max_len(include null byte) +pub fn read_cstring_from_user(addr: Vaddr, max_len: usize) -> Result { + let mut buffer = vec![0u8; max_len]; + read_bytes_from_user(addr, &mut buffer)?; + Ok(CString::from(CStr::from_bytes_until_nul(&buffer)?)) +} diff --git a/src/kxos-std/src/process/clone.rs b/src/kxos-std/src/process/clone.rs index cfaa97d31..df50b660f 100644 --- a/src/kxos-std/src/process/clone.rs +++ b/src/kxos-std/src/process/clone.rs @@ -160,7 +160,7 @@ pub fn clone_child(parent_context: CpuContext, clone_args: CloneArgs) -> Result< parent_process_group.add_process(child.clone()); child.set_process_group(Arc::downgrade(&parent_process_group)); - Process::current().add_child(child.clone()); + current!().add_child(child.clone()); table::add_process(child_pid, child.clone()); deal_with_clone_args(clone_args, &child)?; Ok(child) @@ -181,7 +181,7 @@ fn deal_with_clone_args(clone_args: CloneArgs, child_process: &Arc) -> } fn clone_child_clear_tid(child_process: &Arc) -> Result<()> { - warn!("clone_child_clear_tid does nothing now"); + // TODO: clone_child_clear_tid does nothing now Ok(()) } diff --git a/src/kxos-std/src/process/elf/elf.rs b/src/kxos-std/src/process/elf/elf.rs index d39680600..1f6d215aa 100644 --- a/src/kxos-std/src/process/elf/elf.rs +++ b/src/kxos-std/src/process/elf/elf.rs @@ -164,7 +164,12 @@ impl<'a> ElfLoadInfo<'a> { self.segments.push(elf_segment); } - pub fn parse_elf_data(elf_file_content: &'a [u8], filename: CString) -> Result { + pub fn parse_elf_data( + elf_file_content: &'a [u8], + filename: CString, + argv: Vec, + envp: Vec, + ) -> Result { let elf_file = match ElfFile::new(elf_file_content) { Err(error_msg) => return_errno_with_message!(Errno::ENOEXEC, error_msg), Ok(elf_file) => elf_file, @@ -174,7 +179,7 @@ impl<'a> ElfLoadInfo<'a> { let elf_header_info = ElfHeaderInfo::parse_elf_header(&elf_file); // FIXME: only contains load segment? let segments_count = elf_file.program_iter().count(); - let init_stack = InitStack::new_default_config(filename); + let init_stack = InitStack::new_default_config(filename, argv, envp); let mut elf_load_info = ElfLoadInfo::with_capacity(segments_count, init_stack, elf_header_info); diff --git a/src/kxos-std/src/process/elf/init_stack.rs b/src/kxos-std/src/process/elf/init_stack.rs index 29ad10cae..3c951085b 100644 --- a/src/kxos-std/src/process/elf/init_stack.rs +++ b/src/kxos-std/src/process/elf/init_stack.rs @@ -72,23 +72,29 @@ pub struct InitStack { impl InitStack { /// initialize user stack on base addr - pub fn new(filename: CString, init_stack_top: Vaddr, init_stack_size: usize) -> Self { - let argv = vec![filename]; + pub fn new( + // filename: CString, + init_stack_top: Vaddr, + init_stack_size: usize, + argv: Vec, + envp: Vec, + ) -> Self { Self { init_stack_top, init_stack_size, pos: init_stack_top, argv, - envp: Vec::new(), + envp, aux_vec: AuxVec::new(), } } /// This function only work for first process - pub fn new_default_config(filename: CString) -> Self { + pub fn new_default_config(filename: CString, argv: Vec, envp: Vec) -> Self { let init_stack_top = INIT_STACK_BASE - PAGE_SIZE; let init_stack_size = INIT_STACK_SIZE; - InitStack::new(filename, init_stack_top, init_stack_size) + // InitStack::new(filename, init_stack_top, init_stack_size, argv, envp) + InitStack::new(init_stack_top, init_stack_size, argv, envp) } /// the user stack top(high address), used to setup rsp @@ -107,7 +113,7 @@ impl InitStack { pub fn init(&mut self, vm_space: &VmSpace, elf_header_info: &ElfHeaderInfo) -> Result<()> { self.map_and_zeroed(vm_space); self.write_zero_page(vm_space); // This page is used to store page header table - self.write_stack_content(vm_space, elf_header_info); + self.write_stack_content(vm_space, elf_header_info)?; self.debug_print_stack_content(vm_space); Ok(()) } @@ -126,59 +132,57 @@ impl InitStack { vm_space: &VmSpace, envp_pointers: &Vec, argv_pointers: &Vec, - ) { + ) -> Result<()> { // ensure 8-byte alignment - self.write_u64(0, vm_space); + self.write_u64(0, vm_space)?; let auxvec_size = (self.aux_vec.table().len() + 1) * (mem::size_of::() * 2); let envp_pointers_size = (envp_pointers.len() + 1) * mem::size_of::(); let argv_pointers_size = (argv_pointers.len() + 1) * mem::size_of::(); let argc_size = mem::size_of::(); let to_write_size = auxvec_size + envp_pointers_size + argv_pointers_size + argc_size; if (self.pos - to_write_size) % 16 != 0 { - self.write_u64(0, vm_space); + self.write_u64(0, vm_space)?; } + Ok(()) } fn write_zero_page(&mut self, vm_space: &VmSpace) { self.pos -= PAGE_SIZE; } - fn write_stack_content(&mut self, vm_space: &VmSpace, elf_header_info: &ElfHeaderInfo) { + fn write_stack_content( + &mut self, + vm_space: &VmSpace, + elf_header_info: &ElfHeaderInfo, + ) -> Result<()> { // write envp string - let envp_pointers = self.write_envp_strings(vm_space); + let envp_pointers = self.write_envp_strings(vm_space)?; // write argv string - let argv_pointers = self.write_argv_strings(vm_space); + let argv_pointers = self.write_argv_strings(vm_space)?; // write random value let random_value = generate_random_for_aux_vec(); - let random_value_pointer = self.write_bytes(&random_value, vm_space); + let random_value_pointer = self.write_bytes(&random_value, vm_space)?; + self.aux_vec.set(AuxKey::AT_RANDOM, random_value_pointer)?; + self.aux_vec.set(AuxKey::AT_PAGESZ, PAGE_SIZE as _)?; + self.aux_vec.set( + AuxKey::AT_PHDR, + self.init_stack_top as u64 - PAGE_SIZE as u64 + elf_header_info.ph_off, + )?; self.aux_vec - .set(AuxKey::AT_RANDOM, random_value_pointer) - .expect("Set random value failed"); + .set(AuxKey::AT_PHNUM, elf_header_info.ph_num as u64)?; self.aux_vec - .set(AuxKey::AT_PAGESZ, PAGE_SIZE as _) - .expect("Set Page Size failed"); - self.aux_vec - .set( - AuxKey::AT_PHDR, - self.init_stack_top as u64 - PAGE_SIZE as u64 + elf_header_info.ph_off, - ) - .unwrap(); - self.aux_vec - .set(AuxKey::AT_PHNUM, elf_header_info.ph_num as u64) - .unwrap(); - self.aux_vec - .set(AuxKey::AT_PHENT, elf_header_info.ph_ent as u64) - .unwrap(); - self.adjust_stack_alignment(vm_space, &envp_pointers, &argv_pointers); - self.write_aux_vec(vm_space); - self.write_envp_pointers(vm_space, envp_pointers); - self.write_argv_pointers(vm_space, argv_pointers); + .set(AuxKey::AT_PHENT, elf_header_info.ph_ent as u64)?; + self.adjust_stack_alignment(vm_space, &envp_pointers, &argv_pointers)?; + self.write_aux_vec(vm_space)?; + self.write_envp_pointers(vm_space, envp_pointers)?; + self.write_argv_pointers(vm_space, argv_pointers)?; // write argc let argc = self.argc(); - self.write_u64(argc, vm_space); + self.write_u64(argc, vm_space)?; + Ok(()) } - fn write_envp_strings(&mut self, vm_space: &VmSpace) -> Vec { + fn write_envp_strings(&mut self, vm_space: &VmSpace) -> Result> { let envp = self .envp .iter() @@ -186,13 +190,13 @@ impl InitStack { .collect::>(); let mut envp_pointers = Vec::with_capacity(envp.len()); for envp in envp.iter() { - let pointer = self.write_cstring(envp, vm_space); + let pointer = self.write_cstring(envp, vm_space)?; envp_pointers.push(pointer); } - envp_pointers + Ok(envp_pointers) } - fn write_argv_strings(&mut self, vm_space: &VmSpace) -> Vec { + fn write_argv_strings(&mut self, vm_space: &VmSpace) -> Result> { let argv = self .argv .iter() @@ -200,17 +204,17 @@ impl InitStack { .collect::>(); let mut argv_pointers = Vec::with_capacity(argv.len()); for argv in argv.iter().rev() { - let pointer = self.write_cstring(argv, vm_space); + let pointer = self.write_cstring(argv, vm_space)?; argv_pointers.push(pointer); } argv_pointers.reverse(); - argv_pointers + Ok(argv_pointers) } - fn write_aux_vec(&mut self, vm_space: &VmSpace) { + fn write_aux_vec(&mut self, vm_space: &VmSpace) -> Result<()> { // Write NULL auxilary - self.write_u64(0, vm_space); - self.write_u64(AuxKey::AT_NULL as u64, vm_space); + self.write_u64(0, vm_space)?; + self.write_u64(AuxKey::AT_NULL as u64, vm_space)?; // Write Auxiliary vectors let aux_vec: Vec<_> = self .aux_vec @@ -219,29 +223,40 @@ impl InitStack { .map(|(aux_key, aux_value)| (*aux_key, *aux_value)) .collect(); for (aux_key, aux_value) in aux_vec.iter() { - self.write_u64(*aux_value, vm_space); - self.write_u64(*aux_key as u64, vm_space); + self.write_u64(*aux_value, vm_space)?; + self.write_u64(*aux_key as u64, vm_space)?; } + Ok(()) } - fn write_envp_pointers(&mut self, vm_space: &VmSpace, mut envp_pointers: Vec) { + fn write_envp_pointers( + &mut self, + vm_space: &VmSpace, + mut envp_pointers: Vec, + ) -> Result<()> { // write NULL pointer - self.write_u64(0, vm_space); + self.write_u64(0, vm_space)?; // write envp pointers envp_pointers.reverse(); for envp_pointer in envp_pointers { - self.write_u64(envp_pointer, vm_space); + self.write_u64(envp_pointer, vm_space)?; } + Ok(()) } - fn write_argv_pointers(&mut self, vm_space: &VmSpace, mut argv_pointers: Vec) { + fn write_argv_pointers( + &mut self, + vm_space: &VmSpace, + mut argv_pointers: Vec, + ) -> Result<()> { // write 0 - self.write_u64(0, vm_space); + self.write_u64(0, vm_space)?; // write argv pointers argv_pointers.reverse(); for argv_pointer in argv_pointers { - self.write_u64(argv_pointer, vm_space); + self.write_u64(argv_pointer, vm_space)?; } + Ok(()) } /// Command line argument counter @@ -271,27 +286,23 @@ impl InitStack { } /// returns the u64 start address - fn write_u64(&mut self, val: u64, vm_space: &VmSpace) -> u64 { + fn write_u64(&mut self, val: u64, vm_space: &VmSpace) -> Result { let start_address = (self.pos - 8).align_down(8); self.pos = start_address; - vm_space - .write_val(start_address, &val) - .expect("Write u64 failed"); - self.pos as u64 + vm_space.write_val(start_address, &val)?; + Ok(self.pos as u64) } - fn write_bytes(&mut self, bytes: &[u8], vm_space: &VmSpace) -> u64 { + fn write_bytes(&mut self, bytes: &[u8], vm_space: &VmSpace) -> Result { let len = bytes.len(); self.pos -= len; - vm_space - .write_bytes(self.pos, bytes) - .expect("Write String failed"); - self.pos as u64 + vm_space.write_bytes(self.pos, bytes)?; + Ok(self.pos as u64) } /// returns the string start address /// cstring will with end null byte. - fn write_cstring(&mut self, val: &CString, vm_space: &VmSpace) -> u64 { + fn write_cstring(&mut self, val: &CString, vm_space: &VmSpace) -> Result { let bytes = val.as_bytes_with_nul(); self.write_bytes(bytes, vm_space) } diff --git a/src/kxos-std/src/process/elf/mod.rs b/src/kxos-std/src/process/elf/mod.rs index 226880958..0f889928c 100644 --- a/src/kxos-std/src/process/elf/mod.rs +++ b/src/kxos-std/src/process/elf/mod.rs @@ -16,8 +16,10 @@ pub fn load_elf_to_vm_space<'a>( filename: CString, elf_file_content: &'a [u8], vm_space: &VmSpace, + argv: Vec, + envp: Vec, ) -> Result> { - let mut elf_load_info = ElfLoadInfo::parse_elf_data(elf_file_content, filename)?; + let mut elf_load_info = ElfLoadInfo::parse_elf_data(elf_file_content, filename, argv, envp)?; elf_load_info.copy_and_map_segments(vm_space)?; elf_load_info.debug_check_map_result(vm_space); elf_load_info.init_stack(vm_space); diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs index c9003df73..d8231edc9 100644 --- a/src/kxos-std/src/process/mod.rs +++ b/src/kxos-std/src/process/mod.rs @@ -1,10 +1,5 @@ use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering}; -use crate::prelude::*; -use kxos_frame::sync::WaitQueue; -use kxos_frame::{task::Task, user::UserSpace, vm::VmSpace}; - -use self::process_filter::ProcessFilter; use self::process_group::ProcessGroup; use self::process_vm::mmap_area::MmapArea; use self::process_vm::user_heap::UserHeap; @@ -16,6 +11,9 @@ use self::signal::sig_queues::SigQueues; use self::signal::signals::kernel::KernelSignal; use self::status::ProcessStatus; use self::task::create_user_task_from_elf; +use crate::prelude::*; +use kxos_frame::sync::WaitQueue; +use kxos_frame::{task::Task, user::UserSpace, vm::VmSpace}; pub mod clone; pub mod elf; @@ -45,7 +43,7 @@ pub struct Process { filename: Option, user_space: Option>, user_vm: Option, - waiting_children: WaitQueue, + waiting_children: WaitQueue, // Mutable Part /// The exit code @@ -98,7 +96,7 @@ impl Process { None } else { debug!("All process except init should have parent"); - let current_process = Process::current(); + let current_process = current!(); Some(Arc::downgrade(¤t_process)) }; let children = BTreeMap::new(); @@ -122,13 +120,18 @@ impl Process { } } - pub fn waiting_children(&self) -> &WaitQueue { + pub fn waiting_children(&self) -> &WaitQueue { &self.waiting_children } /// init a user process and send the process to scheduler - pub fn spawn_user_process(filename: CString, elf_file_content: &'static [u8]) -> Arc { - let process = Process::create_user_process(filename, elf_file_content); + pub fn spawn_user_process( + filename: CString, + elf_file_content: &'static [u8], + argv: Vec, + envp: Vec, + ) -> Arc { + let process = Process::create_user_process(filename, elf_file_content, argv, envp); process.send_to_scheduler(); process } @@ -138,18 +141,28 @@ impl Process { where F: Fn() + Send + Sync + 'static, { - let process = Process::create_kernel_process(task_fn); + let process_fn = move || { + task_fn(); + current!().exit(0); + }; + let process = Process::create_kernel_process(process_fn); process.send_to_scheduler(); process } - fn create_user_process(filename: CString, elf_file_content: &'static [u8]) -> Arc { + fn create_user_process( + filename: CString, + elf_file_content: &'static [u8], + argv: Vec, + envp: Vec, + ) -> Arc { let pid = new_pid(); let user_process = Arc::new_cyclic(|weak_process_ref| { let weak_process = weak_process_ref.clone(); let cloned_filename = Some(filename.clone()); - let task = create_user_task_from_elf(filename, elf_file_content, weak_process); + let task = + create_user_task_from_elf(filename, elf_file_content, weak_process, argv, envp); let user_space = task.user_space().map(|user_space| user_space.clone()); let user_vm = UserVm::new(); let sig_dispositions = SigDispositions::new(); @@ -170,6 +183,10 @@ impl Process { // Set process group user_process.create_and_set_process_group(); table::add_process(pid, user_process.clone()); + let parent = user_process + .parent() + .expect("[Internel error] User process should always have parent"); + parent.add_child(user_process.clone()); user_process } @@ -198,6 +215,9 @@ impl Process { }); kernel_process.create_and_set_process_group(); table::add_process(pid, kernel_process.clone()); + if let Some(parent) = kernel_process.parent() { + parent.add_child(kernel_process.clone()); + } kernel_process } @@ -231,7 +251,6 @@ impl Process { /// add a child process pub fn add_child(&self, child: Arc) { - debug!("process: {}, add child: {} ", self.pid(), child.pid()); let child_pid = child.pid(); self.children.lock().insert(child_pid, child); } @@ -257,7 +276,7 @@ impl Process { table::add_process_group(pgid, process_group); } - fn parent(&self) -> Option> { + pub fn parent(&self) -> Option> { self.parent .lock() .as_ref() @@ -265,16 +284,15 @@ impl Process { .flatten() } - /// Exit current process. - /// Set the status of current process as Zombie and set exit code. + /// Exit process. + /// Set the status of the process as Zombie and set exit code. /// Move all children to init process. /// Wake up the parent wait queue if parent is waiting for self. pub fn exit(&self, exit_code: i32) { self.status.lock().set_zombie(); self.exit_code.store(exit_code, Ordering::Relaxed); // move children to the init process - let current_process = Process::current(); - if !current_process.is_init_process() { + if !self.is_init_process() { let init_process = get_init_process(); for (_, child_process) in self.children.lock().drain_filter(|_, _| true) { child_process.set_parent(Arc::downgrade(&init_process)); @@ -282,16 +300,12 @@ impl Process { } } - if let Some(parent) = current_process.parent() { + if let Some(parent) = self.parent() { // set parent sig child let signal = Box::new(KernelSignal::new(SIGCHLD)); parent.sig_queues().lock().enqueue(signal); // wake up parent waiting children, if any - parent - .waiting_children() - .wake_all_on_condition(¤t_process.pid(), |filter, pid| { - filter.contains_pid(*pid) - }); + parent.waiting_children().wake_all(); } } @@ -344,16 +358,6 @@ impl Process { } } - /// Get child process with given pid - pub fn get_child_by_pid(&self, pid: Pid) -> Option> { - for (child_pid, child_process) in self.children.lock().iter() { - if *child_pid == pid { - return Some(child_process.clone()); - } - } - None - } - /// free zombie child with pid, returns the exit code of child process. /// remove process from process group. pub fn reap_zombie_child(&self, pid: Pid) -> i32 { @@ -368,14 +372,8 @@ impl Process { child_process.exit_code() } - /// Get any zombie child - pub fn get_zombie_child(&self) -> Option> { - for (_, child_process) in self.children.lock().iter() { - if child_process.status().lock().is_zombie() { - return Some(child_process.clone()); - } - } - None + pub fn children(&self) -> &Mutex>> { + &self.children } pub fn exit_code(&self) -> i32 { @@ -410,7 +408,7 @@ impl Process { /// Get the init process pub fn get_init_process() -> Arc { - let mut current_process = Process::current(); + let mut current_process = current!(); while current_process.pid() != 0 { let process = current_process .parent diff --git a/src/kxos-std/src/process/task.rs b/src/kxos-std/src/process/task.rs index d3f975cdf..55a6da14d 100644 --- a/src/kxos-std/src/process/task.rs +++ b/src/kxos-std/src/process/task.rs @@ -22,10 +22,12 @@ pub fn create_user_task_from_elf( filename: CString, elf_file_content: &[u8], parent: Weak, + argv: Vec, + envp: Vec, ) -> Arc { let vm_space = VmSpace::new(); - let elf_load_info = - load_elf_to_vm_space(filename, elf_file_content, &vm_space).expect("Load Elf failed"); + let elf_load_info = load_elf_to_vm_space(filename, elf_file_content, &vm_space, argv, envp) + .expect("Load Elf failed"); let mut cpu_ctx = CpuContext::default(); // set entry point cpu_ctx.gp_regs.rip = elf_load_info.entry_point(); @@ -43,7 +45,7 @@ pub fn create_new_task(userspace: Arc, parent: Weak) -> Arc< let user_space = cur.user_space().expect("user task should have user space"); let mut user_mode = UserMode::new(user_space); debug!("In new task"); - debug!("[new task] pid = {}", Process::current().pid()); + debug!("[new task] pid = {}", current!().pid()); debug!("[new task] rip = 0x{:x}", user_space.cpu_ctx.gp_regs.rip); debug!("[new task] rsp = 0x{:x}", user_space.cpu_ctx.gp_regs.rsp); debug!("[new task] rax = 0x{:x}", user_space.cpu_ctx.gp_regs.rax); diff --git a/src/kxos-std/src/process/wait.rs b/src/kxos-std/src/process/wait.rs index 14b958d23..51ab13494 100644 --- a/src/kxos-std/src/process/wait.rs +++ b/src/kxos-std/src/process/wait.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -use super::{process_filter::ProcessFilter, ExitCode, Pid, Process}; +use super::{process_filter::ProcessFilter, ExitCode, Pid}; // The definition of WaitOptions is from Occlum bitflags! { @@ -22,37 +22,52 @@ impl WaitOptions { } pub fn wait_child_exit( - process_filter: ProcessFilter, + child_filter: ProcessFilter, wait_options: WaitOptions, -) -> (Pid, ExitCode) { - let current = Process::current(); +) -> Result<(Pid, ExitCode)> { + let current = current!(); + let (pid, exit_code) = current.waiting_children().wait_until(|| { + let children_lock = current.children().lock(); + let unwaited_children = children_lock + .iter() + .filter(|(pid, child)| match child_filter { + ProcessFilter::Any => true, + ProcessFilter::WithPid(pid) => child.pid() == pid, + ProcessFilter::WithPgid(pgid) => child.pgid() == pgid, + }) + .map(|(_, child)| child.clone()) + .collect::>(); + // we need to drop the lock here, since reap child process need to acquire this lock again + drop(children_lock); - let (pid, exit_code) = current.waiting_children().wait_until(process_filter, || { - let waited_child_process = match process_filter { - ProcessFilter::Any => current.get_zombie_child(), - ProcessFilter::WithPid(pid) => current.get_child_by_pid(pid as Pid), - ProcessFilter::WithPgid(pgid) => todo!(), - }; + if unwaited_children.len() == 0 { + return Err(kxos_frame::Error::NoChild); + } - // some child process is exited - if let Some(waited_child_process) = waited_child_process { - let wait_pid = waited_child_process.pid(); - let exit_code = waited_child_process.exit_code(); + // return immediately if we find a zombie child + let zombie_child = unwaited_children + .iter() + .find(|child| child.status().lock().is_zombie()); + + if let Some(zombie_child) = zombie_child { + let zombie_pid = zombie_child.pid(); + let exit_code = zombie_child.exit_code(); if wait_options.contains(WaitOptions::WNOWAIT) { // does not reap child, directly return - return Some((wait_pid, exit_code)); + return Ok(Some((zombie_pid, exit_code))); } else { - let exit_code = current.reap_zombie_child(wait_pid); - return Some((wait_pid, exit_code)); + let exit_code = current.reap_zombie_child(zombie_pid); + return Ok(Some((zombie_pid, exit_code))); } } if wait_options.contains(WaitOptions::WNOHANG) { - return Some((0, 0)); + return Ok(Some((0, 0))); } - None - }); + // wait + Ok(None) + })?; - (pid, exit_code) + Ok((pid, exit_code)) } diff --git a/src/kxos-std/src/syscall/access.rs b/src/kxos-std/src/syscall/access.rs index 191943e5e..197cfee90 100644 --- a/src/kxos-std/src/syscall/access.rs +++ b/src/kxos-std/src/syscall/access.rs @@ -1,12 +1,10 @@ use super::{constants::*, SyscallReturn}; -use crate::{memory::read_bytes_from_user, prelude::*, syscall::SYS_ACCESS}; +use crate::{memory::read_cstring_from_user, prelude::*, syscall::SYS_ACCESS}; pub fn sys_access(filename_ptr: Vaddr, file_mode: u64) -> Result { debug!("[syscall][id={}][SYS_ACCESS]", SYS_ACCESS); - let mut filename_buffer = vec![0u8; MAX_FILENAME_LEN]; - read_bytes_from_user(filename_ptr, &mut filename_buffer)?; - let filename = CString::from(CStr::from_bytes_until_nul(&filename_buffer).unwrap()); - debug!("filename: {:?}", filename); - warn!("access currenly does not check and just return success"); + let filename = read_cstring_from_user(filename_ptr, MAX_FILENAME_LEN)?; + debug!("filename: {:?}, file_mode = {}", filename, file_mode); + // TODO: access currenly does not check and just return success Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/arch_prctl.rs b/src/kxos-std/src/syscall/arch_prctl.rs index 6be34263b..b437d6d79 100644 --- a/src/kxos-std/src/syscall/arch_prctl.rs +++ b/src/kxos-std/src/syscall/arch_prctl.rs @@ -31,7 +31,10 @@ impl TryFrom for ArchPrctlCode { pub fn sys_arch_prctl(code: u64, addr: u64, context: &mut CpuContext) -> Result { debug!("[syscall][id={}][SYS_ARCH_PRCTL]", SYS_ARCH_PRCTL); let arch_prctl_code = ArchPrctlCode::try_from(code)?; - debug!("arch_prctl_code: {:?}", arch_prctl_code); + debug!( + "arch_prctl_code: {:?}, addr = 0x{:x}", + arch_prctl_code, addr + ); let res = do_arch_prctl(arch_prctl_code, addr, context).unwrap(); Ok(SyscallReturn::Return(res as _)) } @@ -39,7 +42,6 @@ pub fn sys_arch_prctl(code: u64, addr: u64, context: &mut CpuContext) -> Result< pub fn do_arch_prctl(code: ArchPrctlCode, addr: u64, context: &mut CpuContext) -> Result { match code { ArchPrctlCode::ARCH_SET_FS => { - debug!("set user fs: 0x{:x}", addr); context.fs_base = addr; Ok(0) } diff --git a/src/kxos-std/src/syscall/brk.rs b/src/kxos-std/src/syscall/brk.rs index d9c4c83e9..7ef2434db 100644 --- a/src/kxos-std/src/syscall/brk.rs +++ b/src/kxos-std/src/syscall/brk.rs @@ -1,18 +1,18 @@ use crate::prelude::*; use crate::syscall::SyscallReturn; -use crate::{process::Process, syscall::SYS_BRK}; +use crate::syscall::SYS_BRK; /// expand the user heap to new heap end, returns the new heap end if expansion succeeds. pub fn sys_brk(heap_end: u64) -> Result { debug!("[syscall][id={}][SYS_BRK]", SYS_BRK); - let current = Process::current(); let new_heap_end = if heap_end == 0 { None } else { Some(heap_end as usize) }; - let current = Process::current(); + debug!("new heap end = {:x?}", heap_end); + let current = current!(); let user_heap = current .user_heap() .expect("brk should work on process with user heap"); diff --git a/src/kxos-std/src/syscall/clone.rs b/src/kxos-std/src/syscall/clone.rs index 80de9fa56..1758104b0 100644 --- a/src/kxos-std/src/syscall/clone.rs +++ b/src/kxos-std/src/syscall/clone.rs @@ -16,13 +16,8 @@ pub fn sys_clone( parent_context: CpuContext, ) -> Result { debug!("[syscall][id={}][SYS_CLONE]", SYS_CLONE); - debug!("flags = {}", clone_flags); let clone_flags = CloneFlags::from(clone_flags); - debug!("flags = {:?}", clone_flags); - debug!("child_stack_ptr = 0x{:x}", new_sp); - debug!("parent_tid_ptr = 0x{:x}", parent_tidptr); - debug!("child tid ptr = 0x{:x}", child_tidptr); - debug!("tls = 0x{:x}", tls); + debug!("flags = {:?}, child_stack_ptr = 0x{:x}, parent_tid_ptr = 0x{:x}, child tid ptr = 0x{:x}, tls = 0x{:x}", clone_flags, new_sp, parent_tidptr, child_tidptr, tls); let clone_args = CloneArgs::new(new_sp, parent_tidptr, child_tidptr, tls, clone_flags); let child_process = clone_child(parent_context, clone_args).unwrap(); let child_pid = child_process.pid(); diff --git a/src/kxos-std/src/syscall/constants.rs b/src/kxos-std/src/syscall/constants.rs index 13868c317..35274c661 100644 --- a/src/kxos-std/src/syscall/constants.rs +++ b/src/kxos-std/src/syscall/constants.rs @@ -1 +1,6 @@ +/// LONGEST ALLOWED FILENAME pub const MAX_FILENAME_LEN: usize = 128; +pub const MAX_ARGV_NUMBER: usize = 128; +pub const MAX_ENVP_NUMBER: usize = 128; +pub const MAX_ARG_LEN: usize = 128; +pub const MAX_ENV_LEN: usize = 128; diff --git a/src/kxos-std/src/syscall/execve.rs b/src/kxos-std/src/syscall/execve.rs index 89ffe0238..b2415734b 100644 --- a/src/kxos-std/src/syscall/execve.rs +++ b/src/kxos-std/src/syscall/execve.rs @@ -1,8 +1,9 @@ use kxos_frame::cpu::CpuContext; use super::{constants::*, SyscallReturn}; +use crate::memory::{read_cstring_from_user, read_val_from_user}; use crate::process::elf::load_elf_to_vm_space; -use crate::{memory::read_bytes_from_user, prelude::*, process::Process, syscall::SYS_EXECVE}; +use crate::{prelude::*, syscall::SYS_EXECVE}; pub fn sys_execve( filename_ptr: Vaddr, @@ -11,16 +12,19 @@ pub fn sys_execve( context: &mut CpuContext, ) -> Result { debug!("[syscall][id={}][SYS_EXECVE]", SYS_EXECVE); - let mut filename_buffer = vec![0u8; MAX_FILENAME_LEN]; - read_bytes_from_user(filename_ptr, &mut filename_buffer)?; - let filename = CString::from(CStr::from_bytes_until_nul(&filename_buffer).unwrap()); - debug!("filename: {:?}", filename); - + let filename = read_cstring_from_user(filename_ptr, MAX_FILENAME_LEN)?; + let argv = read_cstring_vec(argv_ptr_ptr, MAX_ARGV_NUMBER, MAX_ARG_LEN)?; + let envp = read_cstring_vec(envp_ptr_ptr, MAX_ENVP_NUMBER, MAX_ENV_LEN)?; + debug!( + "filename: {:?}, argv = {:?}, envp = {:?}", + filename, argv, envp + ); if filename != CString::new("./hello").unwrap() { panic!("Unknown filename."); } + let elf_file_content = crate::user_apps::read_execve_hello_content(); - let current = Process::current(); + let current = current!(); // Set process vm space to default let vm_space = current .vm_space() @@ -31,8 +35,8 @@ pub fn sys_execve( .expect("[Internal Error] User process should have user vm"); user_vm.set_default(); // load elf content to new vm space - let elf_load_info = - load_elf_to_vm_space(filename, elf_file_content, &vm_space).expect("load elf failed"); + let elf_load_info = load_elf_to_vm_space(filename, elf_file_content, &vm_space, argv, envp) + .expect("load elf failed"); debug!("load elf in execve succeeds"); // set signal disposition to default current.sig_dispositions().lock().inherit(); @@ -49,3 +53,28 @@ pub fn sys_execve( debug!("user stack top: 0x{:x}", elf_load_info.user_stack_top()); Ok(SyscallReturn::NoReturn) } + +fn read_cstring_vec( + array_ptr: Vaddr, + max_string_number: usize, + max_string_len: usize, +) -> Result> { + let mut res = Vec::new(); + let mut read_addr = array_ptr; + let mut find_null = false; + for _ in 0..max_string_number { + let cstring_ptr = read_val_from_user::(read_addr)?; + read_addr += 8; + // read a null pointer + if cstring_ptr == 0 { + find_null = true; + break; + } + let cstring = read_cstring_from_user(cstring_ptr, max_string_len)?; + res.push(cstring); + } + if !find_null { + return_errno!(Errno::E2BIG); + } + Ok(res) +} diff --git a/src/kxos-std/src/syscall/fstat.rs b/src/kxos-std/src/syscall/fstat.rs index 2ecb99ddf..45d88b7ec 100644 --- a/src/kxos-std/src/syscall/fstat.rs +++ b/src/kxos-std/src/syscall/fstat.rs @@ -7,20 +7,15 @@ use crate::syscall::{SyscallReturn, SYS_FSTAT}; pub fn sys_fstat(fd: u64, stat_buf_ptr: Vaddr) -> Result { debug!("[syscall][id={}][SYS_FSTAT]", SYS_FSTAT); - debug!("fd = {}", fd); - debug!("stat_buf_addr = 0x{:x}", stat_buf_ptr); + debug!("fd = {}, stat_buf_addr = 0x{:x}", fd, stat_buf_ptr); let current = current!(); - let vm_space = current - .vm_space() - .expect("[Internel Error] User process should have vm space"); + let vm_space = current.vm_space().unwrap(); if fd == 1 { let stat = Stat::stdout_stat(); - vm_space - .write_val(stat_buf_ptr, &stat) - .expect("Write value failed"); + vm_space.write_val(stat_buf_ptr, &stat)?; return Ok(SyscallReturn::Return(0)); } - warn!("TODO: fstat only returns fake result now."); + // TODO: fstat only returns fake result now Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/futex.rs b/src/kxos-std/src/syscall/futex.rs index b0ae280ef..49e79024c 100644 --- a/src/kxos-std/src/syscall/futex.rs +++ b/src/kxos-std/src/syscall/futex.rs @@ -1,8 +1,11 @@ +use core::sync::atomic::{AtomicBool, Ordering}; + +use crate::process::{Pid, Process}; use crate::syscall::SyscallReturn; use crate::{memory::read_val_from_user, syscall::SYS_FUTEX}; use crate::prelude::*; -use kxos_frame::{cpu::num_cpus, sync::WaitQueue}; +use kxos_frame::cpu::num_cpus; type FutexBitSet = u32; type FutexBucketRef = Arc>; @@ -93,7 +96,7 @@ pub fn futex_wait_bitset( let (_, futex_bucket_ref) = FUTEX_BUCKETS.get_bucket(futex_key); // lock futex bucket ref here to avoid data race - let futex_bucket = futex_bucket_ref.lock(); + let mut futex_bucket = futex_bucket_ref.lock(); if futex_key.load_val() != futex_val { return_errno_with_message!(Errno::EINVAL, "futex value does not match"); @@ -101,13 +104,9 @@ pub fn futex_wait_bitset( let futex_item = FutexItem::new(futex_key, bitset); futex_bucket.enqueue_item(futex_item); - let wait_queue = futex_bucket.wait_queue(); - // drop lock drop(futex_bucket); - wait_queue.wait_on(futex_item); - Ok(()) } @@ -129,8 +128,8 @@ pub fn futex_wake_bitset( let futex_key = FutexKey::new(futex_addr); let (_, futex_bucket_ref) = FUTEX_BUCKETS.get_bucket(futex_key); - let futex_bucket = futex_bucket_ref.lock(); - let res = futex_bucket.batch_wake_and_deque_items(futex_key, max_count, bitset); + let mut futex_bucket = futex_bucket_ref.lock(); + let res = futex_bucket.dequeue_and_wake_items(futex_key, max_count, bitset); Ok(res) } @@ -152,17 +151,14 @@ pub fn futex_requeue( let nwakes = { if bucket_idx == new_bucket_idx { - let futex_bucket = futex_bucket_ref.lock(); - let nwakes = futex_bucket.batch_wake_and_deque_items( - futex_key, - max_nwakes, - FUTEX_BITSET_MATCH_ANY, - ); + let mut futex_bucket = futex_bucket_ref.lock(); + let nwakes = + futex_bucket.dequeue_and_wake_items(futex_key, max_nwakes, FUTEX_BITSET_MATCH_ANY); futex_bucket.update_item_keys(futex_key, futex_new_key, max_nrequeues); drop(futex_bucket); nwakes } else { - let (futex_bucket, futex_new_bucket) = { + let (mut futex_bucket, mut futex_new_bucket) = { if bucket_idx < new_bucket_idx { let futex_bucket = futex_bucket_ref.lock(); let futext_new_bucket = futex_new_bucket_ref.lock(); @@ -175,14 +171,11 @@ pub fn futex_requeue( } }; - let nwakes = futex_bucket.batch_wake_and_deque_items( - futex_key, - max_nwakes, - FUTEX_BITSET_MATCH_ANY, - ); + let nwakes = + futex_bucket.dequeue_and_wake_items(futex_key, max_nwakes, FUTEX_BITSET_MATCH_ANY); futex_bucket.requeue_items_to_another_bucket( futex_key, - &futex_new_bucket, + &mut futex_new_bucket, futex_new_key, max_nrequeues, ); @@ -240,84 +233,120 @@ impl FutexBucketVec { } struct FutexBucket { - wait_queue: Arc>, + queue: VecDeque, } impl FutexBucket { pub fn new() -> FutexBucket { FutexBucket { - wait_queue: Arc::new(WaitQueue::new()), + queue: VecDeque::new(), } } - pub fn wait_queue(&self) -> Arc> { - self.wait_queue.clone() + pub fn enqueue_item(&mut self, item: FutexItem) { + self.queue.push_back(item); } - pub fn enqueue_item(&self, item: FutexItem) { - self.wait_queue.enqueue(item); + pub fn dequeue_item(&mut self, item: &FutexItem) { + let item_i = self + .queue + .iter() + .position(|futex_item| *futex_item == *item); + if let Some(item_i) = item_i { + self.queue.remove(item_i).unwrap(); + } } - pub fn dequeue_item(&self, item: FutexItem) { - self.wait_queue.dequeue(item); - } - - pub fn batch_wake_and_deque_items( - &self, + pub fn dequeue_and_wake_items( + &mut self, key: FutexKey, max_count: usize, bitset: FutexBitSet, ) -> usize { - self.wait_queue.batch_wake_and_deque( - max_count, - &(key, bitset), - |futex_item, (futex_key, bitset)| { - if futex_item.key == *futex_key && (*bitset & futex_item.bitset) != 0 { - true - } else { - false - } - }, - ) + let mut count = 0; + let mut items_to_wake = Vec::new(); + + self.queue.retain(|item| { + if count >= max_count || key != item.key || (bitset & item.bitset) == 0 { + true + } else { + items_to_wake.push(item.clone()); + count += 1; + false + } + }); + + FutexItem::batch_wake(&items_to_wake); + count } - pub fn update_item_keys(&self, key: FutexKey, new_key: FutexKey, max_count: usize) { - self.wait_queue.update_waiters_data( - |futex_key, futex_item| futex_item.key == *futex_key, - &key, - &new_key, - |futex_item, new_futex_key| FutexItem::new(new_futex_key.clone(), futex_item.bitset), - max_count, - ) + pub fn update_item_keys(&mut self, key: FutexKey, new_key: FutexKey, max_count: usize) { + let mut count = 0; + for item in self.queue.iter_mut() { + if count == max_count { + break; + } + if (*item).key == key { + (*item).key = new_key; + count += 1; + } + } } pub fn requeue_items_to_another_bucket( - &self, + &mut self, key: FutexKey, - another: &Self, + another: &mut Self, new_key: FutexKey, max_nrequeues: usize, ) { - let requeue_items = - self.wait_queue - .remove_waiters(|item, key| item.key == *key, &key, max_nrequeues); + let mut count = 0; - requeue_items.into_iter().for_each(|mut item| { - item.key = new_key; - another.enqueue_item(item); + self.queue.retain(|item| { + if count >= max_nrequeues || key != item.key { + true + } else { + let mut new_item = item.clone(); + new_item.key = new_key; + another.enqueue_item(new_item); + count += 1; + false + } }); } } -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, PartialEq, Clone)] struct FutexItem { key: FutexKey, bitset: FutexBitSet, + waiter: FutexWaiterRef, } impl FutexItem { pub fn new(key: FutexKey, bitset: FutexBitSet) -> Self { - FutexItem { key, bitset } + FutexItem { + key, + bitset, + waiter: Arc::new(FutexWaiter::new()), + } + } + + pub fn wake(&self) { + self.waiter.wake(); + } + + pub fn wait(&self) { + self.waiter.wait(); + } + + pub fn waiter(&self) -> &FutexWaiterRef { + &self.waiter + } + + pub fn batch_wake(items: &[FutexItem]) { + let waiters = items.iter().map(|item| item.waiter()).collect::>(); + FutexWaiter::batch_wake(&waiters); } } @@ -403,3 +432,47 @@ pub fn futex_op_and_flags_from_u32(bits: u32) -> Result<(FutexOp, FutexFlags)> { }; Ok((op, flags)) } + +type FutexWaiterRef = Arc; + +#[derive(Debug)] +struct FutexWaiter { + is_woken: AtomicBool, + pid: Pid, +} + +impl PartialEq for FutexWaiter { + fn eq(&self, other: &Self) -> bool { + self.pid == other.pid + } +} + +impl FutexWaiter { + pub fn new() -> Self { + Self { + is_woken: AtomicBool::new(false), + pid: current!().pid(), + } + } + + pub fn wait(&self) { + self.is_woken.store(false, Ordering::SeqCst); + while !self.is_woken() { + Process::yield_now(); + } + } + + pub fn wake(&self) { + self.is_woken.store(true, Ordering::SeqCst); + } + + pub fn is_woken(&self) -> bool { + self.is_woken.load(Ordering::SeqCst) + } + + pub fn batch_wake(waiters: &[&FutexWaiterRef]) { + waiters.iter().for_each(|waiter| { + waiter.wake(); + }); + } +} diff --git a/src/kxos-std/src/syscall/getegid.rs b/src/kxos-std/src/syscall/getegid.rs index d1e9f2c85..04175e3d2 100644 --- a/src/kxos-std/src/syscall/getegid.rs +++ b/src/kxos-std/src/syscall/getegid.rs @@ -4,6 +4,6 @@ use super::SyscallReturn; pub fn sys_getegid() -> Result { debug!("[syscall][id={}][SYS_GETEGID]", SYS_GETEGID); - warn!("TODO: getegid only return a fake egid now"); + // TODO: getegid only return a fake egid now Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/geteuid.rs b/src/kxos-std/src/syscall/geteuid.rs index 1c11f4dcc..8cb34c885 100644 --- a/src/kxos-std/src/syscall/geteuid.rs +++ b/src/kxos-std/src/syscall/geteuid.rs @@ -4,6 +4,6 @@ use super::SyscallReturn; pub fn sys_geteuid() -> Result { debug!("[syscall][id={}][SYS_GETEUID]", SYS_GETEUID); - warn!("TODO: geteuid only return a fake euid now"); + // TODO: geteuid only return a fake euid now" Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/getgid.rs b/src/kxos-std/src/syscall/getgid.rs index eefe27ed2..a6a14160e 100644 --- a/src/kxos-std/src/syscall/getgid.rs +++ b/src/kxos-std/src/syscall/getgid.rs @@ -4,6 +4,6 @@ use super::SyscallReturn; pub fn sys_getgid() -> Result { debug!("[syscall][id={}][SYS_GETGID]", SYS_GETGID); - warn!("TODO: getgid only return a fake gid now"); + // TODO: getgid only return a fake gid now" Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/getpid.rs b/src/kxos-std/src/syscall/getpid.rs index 493b7371f..20bf8848f 100644 --- a/src/kxos-std/src/syscall/getpid.rs +++ b/src/kxos-std/src/syscall/getpid.rs @@ -1,12 +1,12 @@ use crate::prelude::*; -use crate::{process::Process, syscall::SYS_GETPID}; +use crate::syscall::SYS_GETPID; use super::SyscallReturn; pub fn sys_getpid() -> Result { debug!("[syscall][id={}][SYS_GETPID]", SYS_GETPID); - let pid = Process::current().pid(); - info!("[sys_getpid]: pid = {}", pid); + let pid = current!().pid(); + debug!("[sys_getpid]: pid = {}", pid); Ok(SyscallReturn::Return(pid as _)) } diff --git a/src/kxos-std/src/syscall/gettid.rs b/src/kxos-std/src/syscall/gettid.rs index 028d6e891..1edf0e0c8 100644 --- a/src/kxos-std/src/syscall/gettid.rs +++ b/src/kxos-std/src/syscall/gettid.rs @@ -1,12 +1,12 @@ use crate::prelude::*; -use crate::{process::Process, syscall::SYS_GETTID}; +use crate::syscall::SYS_GETTID; use super::SyscallReturn; pub fn sys_gettid() -> Result { debug!("[syscall][id={}][SYS_GETTID]", SYS_GETTID); // For single-thread process, tid is equal to pid - let tid = Process::current().pid(); + let tid = current!().pid(); Ok(SyscallReturn::Return(tid as _)) } diff --git a/src/kxos-std/src/syscall/getuid.rs b/src/kxos-std/src/syscall/getuid.rs index f9bef9ddc..60059bdd6 100644 --- a/src/kxos-std/src/syscall/getuid.rs +++ b/src/kxos-std/src/syscall/getuid.rs @@ -4,6 +4,6 @@ use super::SyscallReturn; pub fn sys_getuid() -> Result { debug!("[syscall][id={}][SYS_GETUID]", SYS_GETUID); - warn!("TODO: getuid only return a fake uid now"); + // TODO: getuid only return a fake uid now"); Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/kill.rs b/src/kxos-std/src/syscall/kill.rs index 452e7abd1..f7f96d466 100644 --- a/src/kxos-std/src/syscall/kill.rs +++ b/src/kxos-std/src/syscall/kill.rs @@ -13,6 +13,10 @@ pub fn sys_kill(process_filter: u64, sig_num: u64) -> Result { debug!("[syscall][id={}][SYS_KILL]", SYS_KILL); let process_filter = ProcessFilter::from_id(process_filter as _); let sig_num = SigNum::try_from(sig_num as u8).unwrap(); + debug!( + "process_filter = {:?}, sig_num = {:?}", + process_filter, sig_num + ); do_sys_kill(process_filter, sig_num)?; Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/mmap.rs b/src/kxos-std/src/syscall/mmap.rs index 4af368cde..141a38d85 100644 --- a/src/kxos-std/src/syscall/mmap.rs +++ b/src/kxos-std/src/syscall/mmap.rs @@ -4,7 +4,7 @@ use crate::prelude::*; use crate::process::process_vm::mmap_area::MMapFlags; use kxos_frame::vm::VmPerm; -use crate::{process::Process, syscall::SYS_MMAP}; +use crate::syscall::SYS_MMAP; use super::SyscallReturn; @@ -38,12 +38,10 @@ pub fn do_sys_mmap( fd: usize, offset: usize, ) -> Vaddr { - debug!("addr = 0x{:x}", addr); - debug!("len = {}", len); - debug!("perms = {:?}", vm_perm); - debug!("flags = {:?}", flags); - debug!("fd = 0x{:x}", fd); - debug!("offset = 0x{:x}", offset); + debug!( + "addr = 0x{:x}, len = 0x{:x}, perms = {:?}, flags = {:?}, fd = {}, offset = 0x{:x}", + addr, len, vm_perm, flags, fd, offset + ); if flags.contains(MMapFlags::MAP_ANONYMOUS) & !flags.contains(MMapFlags::MAP_FIXED) { // only support map anonymous areas on **NOT** fixed addr now @@ -51,7 +49,7 @@ pub fn do_sys_mmap( panic!("Unsupported mmap flags: {:?}", flags); } - let current = Process::current(); + let current = current!(); let mmap_area = current .mmap_area() .expect("mmap should work on process with mmap area"); diff --git a/src/kxos-std/src/syscall/mprotect.rs b/src/kxos-std/src/syscall/mprotect.rs index 48c9df88e..65400cb37 100644 --- a/src/kxos-std/src/syscall/mprotect.rs +++ b/src/kxos-std/src/syscall/mprotect.rs @@ -14,9 +14,10 @@ pub fn sys_mprotect(vaddr: u64, len: u64, perms: u64) -> Result { } pub fn do_sys_mprotect(addr: Vaddr, len: usize, perms: VmPerm) -> isize { - debug!("addr = 0x{:x}", addr); - debug!("len = 0x{:x}", len); - debug!("perms = {:?}", perms); - warn!("TODO: mprotect do nothing now"); + debug!( + "addr = 0x{:x}, len = 0x{:x}, perms = {:?}", + addr, len, perms + ); + // TODO: mprotect do nothing now 0 } diff --git a/src/kxos-std/src/syscall/readlink.rs b/src/kxos-std/src/syscall/readlink.rs index 4d530435a..19e9de13e 100644 --- a/src/kxos-std/src/syscall/readlink.rs +++ b/src/kxos-std/src/syscall/readlink.rs @@ -2,7 +2,6 @@ use crate::prelude::*; use crate::{ memory::{read_bytes_from_user, write_bytes_to_user}, - process::Process, syscall::SYS_READLINK, }; @@ -31,12 +30,13 @@ pub fn do_sys_readlink( user_buf_ptr: Vaddr, user_buf_len: usize, ) -> Result { - debug!("filename ptr = 0x{:x}", filename_ptr); - debug!("user_buf_ptr = 0x{:x}", user_buf_ptr); - debug!("user_buf_len = 0x{:x}", user_buf_len); + debug!( + "filename ptr = 0x{:x}, user_buf_ptr = 0x{:x}, user_buf_len = 0x{:x}", + filename_ptr, user_buf_ptr, user_buf_len + ); let mut filename_buffer = [0u8; MAX_FILENAME_LEN]; - let current = Process::current(); + let current = current!(); read_bytes_from_user(filename_ptr, &mut filename_buffer)?; let filename = CStr::from_bytes_until_nul(&filename_buffer).expect("Invalid filename"); debug!("filename = {:?}", filename); diff --git a/src/kxos-std/src/syscall/rt_sigaction.rs b/src/kxos-std/src/syscall/rt_sigaction.rs index bbd96e057..fedd74e8b 100644 --- a/src/kxos-std/src/syscall/rt_sigaction.rs +++ b/src/kxos-std/src/syscall/rt_sigaction.rs @@ -15,14 +15,12 @@ pub fn sys_rt_sigaction( ) -> Result { debug!("[syscall][id={}][SYS_RT_SIGACTION]", SYS_RT_SIGACTION); let sig_num = SigNum::try_from(sig_num)?; - debug!("sig_num = {}", sig_num.sig_name()); - debug!("sig_action_ptr = 0x{:x}", sig_action_ptr); - debug!("old_sig_action_ptr = 0x{:x}", old_sig_action_ptr); - debug!("sigset_size = {}", sigset_size); let sig_action_c = read_val_from_user::(sig_action_ptr)?; - debug!("sig_action_c = {:?}", sig_action_c); let sig_action = SigAction::try_from(sig_action_c).unwrap(); - debug!("sig_action = {:x?}", sig_action); + debug!( + "sig_num = {:?}, sig_action = {:x?}, old_sig_action_ptr = 0x{:x}, sigset_size = {}", + sig_num, sig_action, old_sig_action_ptr, sigset_size + ); let current = current!(); let mut sig_dispositions = current.sig_dispositions().lock(); diff --git a/src/kxos-std/src/syscall/rt_sigprocmask.rs b/src/kxos-std/src/syscall/rt_sigprocmask.rs index 7ce7d29eb..34844ef5a 100644 --- a/src/kxos-std/src/syscall/rt_sigprocmask.rs +++ b/src/kxos-std/src/syscall/rt_sigprocmask.rs @@ -13,12 +13,12 @@ pub fn sys_rt_sigprocmask( ) -> Result { debug!("[syscall][id={}][SYS_RT_SIGPROCMASK]", SYS_RT_SIGPROCMASK); let mask_op = MaskOp::try_from(how).unwrap(); - debug!("mask op = {:?}", mask_op); - debug!("set_ptr = 0x{:x}", set_ptr); - debug!("oldset_ptr = 0x{:x}", oldset_ptr); - debug!("sigset_size = {}", sigset_size); + debug!( + "mask op = {:?}, set_ptr = 0x{:x}, oldset_ptr = 0x{:x}, sigset_size = {}", + mask_op, set_ptr, oldset_ptr, sigset_size + ); if sigset_size != 8 { - warn!("sigset size is not equal to 8"); + error!("sigset size is not equal to 8"); } do_rt_sigprocmask(mask_op, set_ptr, oldset_ptr, sigset_size).unwrap(); Ok(SyscallReturn::Return(0)) diff --git a/src/kxos-std/src/syscall/rt_sigreturn.rs b/src/kxos-std/src/syscall/rt_sigreturn.rs index b816df719..3c0b6180d 100644 --- a/src/kxos-std/src/syscall/rt_sigreturn.rs +++ b/src/kxos-std/src/syscall/rt_sigreturn.rs @@ -1,9 +1,10 @@ use crate::{memory::read_val_from_user, prelude::*, process::signal::c_types::ucontext_t}; use kxos_frame::cpu::CpuContext; -use super::SyscallReturn; +use super::{SyscallReturn, SYS_RT_SIGRETRUN}; pub fn sys_rt_sigreturn(context: &mut CpuContext) -> Result { + debug!("[syscall][id={}][SYS_RT_SIGRETURN]", SYS_RT_SIGRETRUN); let current = current!(); let sig_context = current.sig_context().lock().pop_back().unwrap(); let ucontext = read_val_from_user::(sig_context)?; diff --git a/src/kxos-std/src/syscall/tgkill.rs b/src/kxos-std/src/syscall/tgkill.rs index 57a764c8f..feb967adb 100644 --- a/src/kxos-std/src/syscall/tgkill.rs +++ b/src/kxos-std/src/syscall/tgkill.rs @@ -12,10 +12,8 @@ use super::SyscallReturn; /// and tgid as its process group id. pub fn sys_tgkill(tgid: Pgid, pid: Pid, sig_num: u8) -> Result { debug!("[syscall][id={}][SYS_TGKILL]", SYS_TGKILL); - debug!("tgid = {}", tgid); - debug!("pid = {}", pid); let sig_num = SigNum::from_u8(sig_num); - debug!("sig_num = {:?}", sig_num); + debug!("tgid = {}, pid = {}, sig_num = {:?}", tgid, pid, sig_num); let target_process = table::pid_to_process(pid).ok_or(Error::with_message(Errno::EINVAL, "Invalid pid"))?; let pgid = target_process.pgid(); diff --git a/src/kxos-std/src/syscall/uname.rs b/src/kxos-std/src/syscall/uname.rs index 47dd9c081..7383a8919 100644 --- a/src/kxos-std/src/syscall/uname.rs +++ b/src/kxos-std/src/syscall/uname.rs @@ -58,17 +58,9 @@ fn copy_cstring_to_u8_slice(src: &CStr, dst: &mut [u8]) { dst[..len].copy_from_slice(&src[..len]); } -pub fn sys_uname(old_uname_addr: u64) -> Result { +pub fn sys_uname(old_uname_addr: Vaddr) -> Result { debug!("[syscall][id={}][SYS_UNAME]", SYS_UNAME); - do_sys_uname(old_uname_addr as Vaddr)?; + debug!("old uname addr = 0x{:x}", old_uname_addr); + write_val_to_user(old_uname_addr, &*UTS_NAME)?; Ok(SyscallReturn::Return(0)) } - -pub fn do_sys_uname(old_uname_addr: Vaddr) -> Result { - debug!("old_uname_addr: 0x{:x}", old_uname_addr); - debug!("uts name size: {}", core::mem::size_of::()); - debug!("uts name align: {}", core::mem::align_of::()); - - write_val_to_user(old_uname_addr, &*UTS_NAME)?; - Ok(0) -} diff --git a/src/kxos-std/src/syscall/wait4.rs b/src/kxos-std/src/syscall/wait4.rs index f0db5761b..82addf485 100644 --- a/src/kxos-std/src/syscall/wait4.rs +++ b/src/kxos-std/src/syscall/wait4.rs @@ -9,14 +9,15 @@ use crate::process::wait::WaitOptions; use super::SyscallReturn; -pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> Result { +pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u32) -> Result { debug!("[syscall][id={}][SYS_WAIT4]", SYS_WAIT4); - let wait_options = WaitOptions::from_bits(wait_options as u32).expect("Unknown wait options"); - debug!("pid = {}", wait_pid as i32); - debug!("exit_status_ptr = {}", exit_status_ptr); - debug!("wait_options: {:?}", wait_options); + let wait_options = WaitOptions::from_bits(wait_options).expect("Unknown wait options"); + debug!( + "pid = {}, exit_status_ptr = {}, wait_options: {:?}", + wait_pid as i32, exit_status_ptr, wait_options + ); let process_filter = ProcessFilter::from_id(wait_pid as _); - let (return_pid, exit_code) = wait_child_exit(process_filter, wait_options); + let (return_pid, exit_code) = wait_child_exit(process_filter, wait_options)?; if return_pid != 0 && exit_status_ptr != 0 { write_val_to_user(exit_status_ptr as _, &exit_code)?; } diff --git a/src/kxos-std/src/syscall/waitid.rs b/src/kxos-std/src/syscall/waitid.rs index aa74091ed..da1653c07 100644 --- a/src/kxos-std/src/syscall/waitid.rs +++ b/src/kxos-std/src/syscall/waitid.rs @@ -15,6 +15,6 @@ pub fn sys_waitid( // FIXME: what does infoq and rusage use for? let process_filter = ProcessFilter::from_which_and_id(which, upid); let wait_options = WaitOptions::from_bits(options as u32).expect("Unknown wait options"); - let (exit_code, pid) = wait_child_exit(process_filter, wait_options); + let (exit_code, pid) = wait_child_exit(process_filter, wait_options)?; Ok(SyscallReturn::Return(pid as _)) } diff --git a/src/kxos-std/src/syscall/write.rs b/src/kxos-std/src/syscall/write.rs index 2eddb05ea..4b6fb2599 100644 --- a/src/kxos-std/src/syscall/write.rs +++ b/src/kxos-std/src/syscall/write.rs @@ -10,6 +10,10 @@ const STDERR: u64 = 2; pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result { // only suppprt STDOUT now. debug!("[syscall][id={}][SYS_WRITE]", SYS_WRITE); + debug!( + "fd = {}, user_buf_ptr = 0x{:x}, user_buf_len = 0x{:x}", + fd, user_buf_ptr, user_buf_len + ); if fd == STDOUT || fd == STDERR { let mut buffer = vec![0u8; user_buf_len as usize]; diff --git a/src/kxos-std/src/syscall/writev.rs b/src/kxos-std/src/syscall/writev.rs index 5acba95d0..e34a72f82 100644 --- a/src/kxos-std/src/syscall/writev.rs +++ b/src/kxos-std/src/syscall/writev.rs @@ -23,24 +23,23 @@ pub fn sys_writev(fd: u64, io_vec_ptr: u64, io_vec_count: u64) -> Result Result { - debug!("fd = {}", fd); - debug!("io_vec_ptr = 0x{:x}", io_vec_ptr); - debug!("io_vec_counter = 0x{:x}", io_vec_count); + debug!( + "fd = {}, io_vec_ptr = 0x{:x}, io_vec_counter = 0x{:x}", + fd, io_vec_ptr, io_vec_count + ); let mut write_len = 0; for i in 0..io_vec_count { let io_vec = read_val_from_user::(io_vec_ptr + i * 8)?; let base = io_vec.base; let len = io_vec.len; - debug!("base = 0x{:x}", base); - debug!("len = {}", len); let mut buffer = vec![0u8; len]; read_bytes_from_user(base, &mut buffer)?; let content = alloc::str::from_utf8(&buffer).unwrap(); write_len += len; if fd == 1 { - info!("User Mode Message: {}", content); + print!("{}", content); } else if fd == 2 { - info!("User Mode Error Message: {}", content); + print!("{}", content); } else { info!("content = {}", content); panic!("Unsupported fd {}", fd); diff --git a/src/kxos-user/execve/execve b/src/kxos-user/execve/execve index 673f205d3..a5403b6a9 100755 --- a/src/kxos-user/execve/execve +++ b/src/kxos-user/execve/execve @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:afc9465a8ae782da4e049d2b660a27b678394e683814c29a9601bc135126a0e5 +oid sha256:c04094e4c0da36e9f8cc5059f540dbc2123d5e4caa1d0b7427577ee734710b23 size 871952 diff --git a/src/kxos-user/execve/execve.c b/src/kxos-user/execve/execve.c index 547d9dae7..13258ac62 100644 --- a/src/kxos-user/execve/execve.c +++ b/src/kxos-user/execve/execve.c @@ -2,8 +2,8 @@ #include int main() { - char* argv[] = { NULL }; - char* envp[] = { NULL }; + char* argv[] = { "argv1", "argv2", NULL }; + char* envp[] = { "home=/", "version=1.1", NULL }; printf("Execve a new file ./hello:\n"); // flush the stdout content to ensure the content print to console fflush(stdout); diff --git a/src/kxos-user/execve/hello b/src/kxos-user/execve/hello index dc2959f18..be093b65e 100755 --- a/src/kxos-user/execve/hello +++ b/src/kxos-user/execve/hello @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b1e30d140892a01630093a376819dcfb400754c9dbf71f845df945fc14fc861 -size 871896 +oid sha256:d0152798ba393fb04603ead02083e74de560d9cf51584f5cdca762d0706ebd2d +size 871960 diff --git a/src/kxos-user/execve/hello.c b/src/kxos-user/execve/hello.c index 8bc0d9de0..014411efd 100644 --- a/src/kxos-user/execve/hello.c +++ b/src/kxos-user/execve/hello.c @@ -1,6 +1,16 @@ #include -int main() { +int main(int argc, char *argv[], char *envp[]) { printf("Hello world from hello.c(execved in execve.c)!\n"); + printf("argc = %d\n", argc); + for(int i = 0; i < argc; i++) { + printf("%s\n", argv[i]); + } + for(int i = 0 ;; i++) { + if (envp[i] == NULL) { + break; + } + printf("%s\n", envp[i]); + } return 0; } \ No newline at end of file