mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-17 12:47:16 +00:00
refactor the implementation of wait
This commit is contained in:
parent
c98b9d360f
commit
b53f99b169
@ -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;
|
||||
|
@ -8,4 +8,5 @@ pub enum Error {
|
||||
IoError,
|
||||
InvalidVmpermBits,
|
||||
NotEnoughResources,
|
||||
NoChild,
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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) => {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)?))
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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(¤t_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(¤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<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
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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 _))
|
||||
}
|
||||
|
@ -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 _))
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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))
|
||||
|
@ -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)?;
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)?;
|
||||
}
|
||||
|
@ -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 _))
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:afc9465a8ae782da4e049d2b660a27b678394e683814c29a9601bc135126a0e5
|
||||
oid sha256:c04094e4c0da36e9f8cc5059f540dbc2123d5e4caa1d0b7427577ee734710b23
|
||||
size 871952
|
||||
|
@ -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);
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7b1e30d140892a01630093a376819dcfb400754c9dbf71f845df945fc14fc861
|
||||
size 871896
|
||||
oid sha256:d0152798ba393fb04603ead02083e74de560d9cf51584f5cdca762d0706ebd2d
|
||||
size 871960
|
||||
|
@ -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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user