refactor the implementation of wait

This commit is contained in:
Jianfeng Jiang 2022-11-09 15:14:12 +08:00
parent c98b9d360f
commit b53f99b169
48 changed files with 664 additions and 467 deletions

View File

@ -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;

View File

@ -8,4 +8,5 @@ pub enum Error {
IoError,
InvalidVmpermBits,
NotEnoughResources,
NoChild,
}

View File

@ -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<P> Drop for RcuReclaimer<P> {
wq.wake_one();
}
});
wq.wait_until(None::<u8>, || Some(0));
wq.wait_until(|| Ok(Some(0u8))).unwrap();
}
}

View File

@ -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<D: Clone + Eq + PartialEq> {
waiters: Mutex<VecDeque<WaiterRef<D>>>,
pub struct WaitQueue {
waiters: Mutex<VecDeque<Arc<Waiter>>>,
}
impl<D: Clone + Eq + PartialEq> WaitQueue<D> {
impl WaitQueue {
/// Creates a new instance.
pub fn new() -> Self {
WaitQueue {
@ -33,16 +35,22 @@ impl<D: Clone + Eq + PartialEq> WaitQueue<D> {
///
/// By taking a condition closure, his wait-wakeup mechanism becomes
/// more efficient and robust.
pub fn wait_until<F, R>(&self, data: D, mut cond: F) -> R
pub fn wait_until<F, R>(&self, mut cond: F) -> Result<R>
where
F: FnMut() -> Option<R>,
F: FnMut() -> Result<Option<R>>,
{
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<D: Clone + Eq + PartialEq> WaitQueue<D> {
/// 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<D: Clone + Eq + PartialEq> WaitQueue<D> {
}
}
/// 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<F, C>(&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<F, C>(&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<F, C>(&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<F, C>(&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<F1, F2, C>(
&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<F1, F2, C>(
// &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<C, F>(&self, cond: F, cond_data: &C, max_count: usize) -> Vec<D>
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<C, F>(&self, cond: F, cond_data: &C, max_count: usize) -> Vec<D>
// 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<D>) {
self.waiters.lock().push_back(waiter_ref.clone());
}
fn dequeue_waiter(&self, waiter_ref: &WaiterRef<D>) {
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<Waiter>) {
if waiter.is_exclusive() {
self.waiters.lock().push_back(waiter.clone())
} else {
self.waiters.lock().push_front(waiter.clone());
}
drop(waiters_lock);
}
}
type WaiterRef<D> = Arc<Waiter<D>>;
/// 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<D>) {
// 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<D: Clone + Eq + PartialEq> {
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<D: Clone + Eq + PartialEq> Waiter<D> {
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;
}
}

View File

@ -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;

View File

@ -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
}
}

View File

@ -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() {

View File

@ -188,6 +188,7 @@ impl From<kxos_frame::Error> 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<core::str::Utf8Error> for Error {
}
}
impl From<core::ffi::FromBytesUntilNulError> 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) => {

View File

@ -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());
}
}

View File

@ -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<T: Pod>(src: Vaddr) -> Result<T> {
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<T: Pod>(src: Vaddr) -> Result<T> {
/// 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<T: Pod>(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<T: Pod>(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<CString> {
let mut buffer = vec![0u8; max_len];
read_bytes_from_user(addr, &mut buffer)?;
Ok(CString::from(CStr::from_bytes_until_nul(&buffer)?))
}

View File

@ -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<Process>) ->
}
fn clone_child_clear_tid(child_process: &Arc<Process>) -> Result<()> {
warn!("clone_child_clear_tid does nothing now");
// TODO: clone_child_clear_tid does nothing now
Ok(())
}

View File

@ -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<Self> {
pub fn parse_elf_data(
elf_file_content: &'a [u8],
filename: CString,
argv: Vec<CString>,
envp: Vec<CString>,
) -> Result<Self> {
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);

View File

@ -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<CString>,
envp: Vec<CString>,
) -> 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<CString>, envp: Vec<CString>) -> 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<u64>,
argv_pointers: &Vec<u64>,
) {
) -> 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::<u64>() * 2);
let envp_pointers_size = (envp_pointers.len() + 1) * mem::size_of::<u64>();
let argv_pointers_size = (argv_pointers.len() + 1) * mem::size_of::<u64>();
let argc_size = mem::size_of::<u64>();
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<u64> {
fn write_envp_strings(&mut self, vm_space: &VmSpace) -> Result<Vec<u64>> {
let envp = self
.envp
.iter()
@ -186,13 +190,13 @@ impl InitStack {
.collect::<Vec<_>>();
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<u64> {
fn write_argv_strings(&mut self, vm_space: &VmSpace) -> Result<Vec<u64>> {
let argv = self
.argv
.iter()
@ -200,17 +204,17 @@ impl InitStack {
.collect::<Vec<_>>();
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<u64>) {
fn write_envp_pointers(
&mut self,
vm_space: &VmSpace,
mut envp_pointers: Vec<u64>,
) -> 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<u64>) {
fn write_argv_pointers(
&mut self,
vm_space: &VmSpace,
mut argv_pointers: Vec<u64>,
) -> 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<u64> {
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<u64> {
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<u64> {
let bytes = val.as_bytes_with_nul();
self.write_bytes(bytes, vm_space)
}

View File

@ -16,8 +16,10 @@ pub fn load_elf_to_vm_space<'a>(
filename: CString,
elf_file_content: &'a [u8],
vm_space: &VmSpace,
argv: Vec<CString>,
envp: Vec<CString>,
) -> Result<ElfLoadInfo<'a>> {
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);

View File

@ -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<CString>,
user_space: Option<Arc<UserSpace>>,
user_vm: Option<UserVm>,
waiting_children: WaitQueue<ProcessFilter>,
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(&current_process))
};
let children = BTreeMap::new();
@ -122,13 +120,18 @@ impl Process {
}
}
pub fn waiting_children(&self) -> &WaitQueue<ProcessFilter> {
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<Self> {
let process = Process::create_user_process(filename, elf_file_content);
pub fn spawn_user_process(
filename: CString,
elf_file_content: &'static [u8],
argv: Vec<CString>,
envp: Vec<CString>,
) -> Arc<Self> {
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<Self> {
fn create_user_process(
filename: CString,
elf_file_content: &'static [u8],
argv: Vec<CString>,
envp: Vec<CString>,
) -> Arc<Self> {
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<Process>) {
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<Arc<Process>> {
pub fn parent(&self) -> Option<Arc<Process>> {
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(&current_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<Arc<Process>> {
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<Arc<Process>> {
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<BTreeMap<usize, Arc<Process>>> {
&self.children
}
pub fn exit_code(&self) -> i32 {
@ -410,7 +408,7 @@ impl Process {
/// Get the init process
pub fn get_init_process() -> Arc<Process> {
let mut current_process = Process::current();
let mut current_process = current!();
while current_process.pid() != 0 {
let process = current_process
.parent

View File

@ -22,10 +22,12 @@ pub fn create_user_task_from_elf(
filename: CString,
elf_file_content: &[u8],
parent: Weak<Process>,
argv: Vec<CString>,
envp: Vec<CString>,
) -> Arc<Task> {
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<UserSpace>, parent: Weak<Process>) -> 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);

View File

@ -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::<Vec<_>>();
// 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))
}

View File

@ -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<SyscallReturn> {
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))
}

View File

@ -31,7 +31,10 @@ impl TryFrom<u64> for ArchPrctlCode {
pub fn sys_arch_prctl(code: u64, addr: u64, context: &mut CpuContext) -> Result<SyscallReturn> {
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<u64> {
match code {
ArchPrctlCode::ARCH_SET_FS => {
debug!("set user fs: 0x{:x}", addr);
context.fs_base = addr;
Ok(0)
}

View File

@ -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<SyscallReturn> {
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");

View File

@ -16,13 +16,8 @@ pub fn sys_clone(
parent_context: CpuContext,
) -> Result<SyscallReturn> {
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();

View File

@ -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;

View File

@ -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<SyscallReturn> {
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<Vec<CString>> {
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::<usize>(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)
}

View File

@ -7,20 +7,15 @@ use crate::syscall::{SyscallReturn, SYS_FSTAT};
pub fn sys_fstat(fd: u64, stat_buf_ptr: Vaddr) -> Result<SyscallReturn> {
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))
}

View File

@ -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<Mutex<FutexBucket>>;
@ -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<WaitQueue<FutexItem>>,
queue: VecDeque<FutexItem>,
}
impl FutexBucket {
pub fn new() -> FutexBucket {
FutexBucket {
wait_queue: Arc::new(WaitQueue::new()),
queue: VecDeque::new(),
}
}
pub fn wait_queue(&self) -> Arc<WaitQueue<FutexItem>> {
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::<Vec<_>>();
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<FutexWaiter>;
#[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();
});
}
}

View File

@ -4,6 +4,6 @@ use super::SyscallReturn;
pub fn sys_getegid() -> Result<SyscallReturn> {
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))
}

View File

@ -4,6 +4,6 @@ use super::SyscallReturn;
pub fn sys_geteuid() -> Result<SyscallReturn> {
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))
}

View File

@ -4,6 +4,6 @@ use super::SyscallReturn;
pub fn sys_getgid() -> Result<SyscallReturn> {
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))
}

View File

@ -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<SyscallReturn> {
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 _))
}

View File

@ -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<SyscallReturn> {
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 _))
}

View File

@ -4,6 +4,6 @@ use super::SyscallReturn;
pub fn sys_getuid() -> Result<SyscallReturn> {
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))
}

View File

@ -13,6 +13,10 @@ pub fn sys_kill(process_filter: u64, sig_num: u64) -> Result<SyscallReturn> {
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))
}

View File

@ -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");

View File

@ -14,9 +14,10 @@ pub fn sys_mprotect(vaddr: u64, len: u64, perms: u64) -> Result<SyscallReturn> {
}
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
}

View File

@ -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<usize> {
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);

View File

@ -15,14 +15,12 @@ pub fn sys_rt_sigaction(
) -> Result<SyscallReturn> {
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::<sigaction_t>(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();

View File

@ -13,12 +13,12 @@ pub fn sys_rt_sigprocmask(
) -> Result<SyscallReturn> {
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))

View File

@ -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<SyscallReturn> {
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::<ucontext_t>(sig_context)?;

View File

@ -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<SyscallReturn> {
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();

View File

@ -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<SyscallReturn> {
pub fn sys_uname(old_uname_addr: Vaddr) -> Result<SyscallReturn> {
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<usize> {
debug!("old_uname_addr: 0x{:x}", old_uname_addr);
debug!("uts name size: {}", core::mem::size_of::<UtsName>());
debug!("uts name align: {}", core::mem::align_of::<UtsName>());
write_val_to_user(old_uname_addr, &*UTS_NAME)?;
Ok(0)
}

View File

@ -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<SyscallReturn> {
pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u32) -> Result<SyscallReturn> {
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)?;
}

View File

@ -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 _))
}

View File

@ -10,6 +10,10 @@ const STDERR: u64 = 2;
pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result<SyscallReturn> {
// 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];

View File

@ -23,24 +23,23 @@ pub fn sys_writev(fd: u64, io_vec_ptr: u64, io_vec_count: u64) -> Result<Syscall
}
pub fn do_sys_writev(fd: u64, io_vec_ptr: Vaddr, io_vec_count: usize) -> Result<usize> {
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::<IoVec>(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);

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:afc9465a8ae782da4e049d2b660a27b678394e683814c29a9601bc135126a0e5
oid sha256:c04094e4c0da36e9f8cc5059f540dbc2123d5e4caa1d0b7427577ee734710b23
size 871952

View File

@ -2,8 +2,8 @@
#include <unistd.h>
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);

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7b1e30d140892a01630093a376819dcfb400754c9dbf71f845df945fc14fc861
size 871896
oid sha256:d0152798ba393fb04603ead02083e74de560d9cf51584f5cdca762d0706ebd2d
size 871960

View File

@ -1,6 +1,16 @@
#include <stdio.h>
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;
}