mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 05:16:47 +00:00
add syscall wait4 and waitid
This commit is contained in:
parent
21290f1cff
commit
e29bb58d45
@ -89,7 +89,7 @@ impl<P> Drop for RcuReclaimer<P> {
|
||||
wq.wake_one();
|
||||
}
|
||||
});
|
||||
wq.wait_until(|| true);
|
||||
wq.wait_until(None::<u8>, || Some(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,69 +1,123 @@
|
||||
use alloc::collections::VecDeque;
|
||||
use spin::mutex::Mutex;
|
||||
|
||||
use crate::{debug, task::Task};
|
||||
|
||||
/// A wait queue.
|
||||
///
|
||||
/// One may wait on a wait queue to put its executing thread to sleep.
|
||||
/// 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 {}
|
||||
pub struct WaitQueue<D: Clone + Eq + PartialEq> {
|
||||
waiters: Mutex<VecDeque<Waiter<D>>>,
|
||||
}
|
||||
|
||||
impl WaitQueue {
|
||||
impl<D: Clone + Eq + PartialEq> WaitQueue<D> {
|
||||
/// Creates a new instance.
|
||||
pub fn new() -> Self {
|
||||
todo!()
|
||||
WaitQueue {
|
||||
waiters: Mutex::new(VecDeque::new()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait until some condition becomes true.
|
||||
///
|
||||
/// This method takes a closure that tests a user-given condition.
|
||||
/// The method only returns if the condition becomes true.
|
||||
/// The method only returns if the condition returns Some(_).
|
||||
/// A waker thread should first make the condition true, then invoke the
|
||||
/// `wake`-family method. This ordering is important to ensure that waiter
|
||||
/// threads do not lose any wakeup notifiations.
|
||||
///
|
||||
/// By taking a condition closure, this wait-wakeup mechanism becomes
|
||||
/// more efficient and robust.
|
||||
pub fn wait_until<F>(&self, mut cond: F)
|
||||
pub fn wait_until<F, R>(&self, data: D, mut cond: F) -> R
|
||||
where
|
||||
F: FnMut() -> bool,
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
let waiter = Waiter::new();
|
||||
let waiter = Waiter::new(data);
|
||||
self.enqueue(&waiter);
|
||||
loop {
|
||||
if (cond)() {
|
||||
if let Some(r) = cond() {
|
||||
self.dequeue(&waiter);
|
||||
break;
|
||||
return r;
|
||||
}
|
||||
waiter.wait();
|
||||
}
|
||||
self.dequeue(&waiter);
|
||||
}
|
||||
|
||||
/// Wake one waiter thread, if there is one.
|
||||
pub fn wake_one(&self) {
|
||||
todo!()
|
||||
if let Some(waiter) = self.waiters.lock().front_mut() {
|
||||
waiter.wake_up();
|
||||
}
|
||||
}
|
||||
|
||||
/// Wake all waiter threads.
|
||||
pub fn wake_all(&self) {
|
||||
todo!()
|
||||
self.waiters.lock().iter_mut().for_each(|waiter| {
|
||||
waiter.wake_up();
|
||||
});
|
||||
}
|
||||
|
||||
fn enqueue(&self, waiter: &Waiter) {
|
||||
todo!()
|
||||
/// 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_mut().for_each(|waiter| {
|
||||
if cond(waiter.data(), cond_data) {
|
||||
waiter.wake_up()
|
||||
}
|
||||
})
|
||||
}
|
||||
fn dequeue(&self, waiter: &Waiter) {
|
||||
todo!()
|
||||
|
||||
fn enqueue(&self, waiter: &Waiter<D>) {
|
||||
self.waiters.lock().push_back(waiter.clone());
|
||||
}
|
||||
fn dequeue(&self, waiter: &Waiter<D>) {
|
||||
let mut waiters_lock = self.waiters.lock();
|
||||
let len = waiters_lock.len();
|
||||
let mut index = 0;
|
||||
for i in 0..len {
|
||||
if waiters_lock[i] == *waiter {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
waiters_lock.remove(index);
|
||||
drop(waiters_lock);
|
||||
}
|
||||
}
|
||||
|
||||
struct Waiter {}
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct Waiter<D: Clone + Eq + PartialEq> {
|
||||
is_woken_up: bool,
|
||||
data: D,
|
||||
}
|
||||
|
||||
impl Waiter {
|
||||
pub fn new() -> Self {
|
||||
todo!()
|
||||
impl<D: Clone + Eq + PartialEq> Waiter<D> {
|
||||
pub fn new(data: D) -> Self {
|
||||
Waiter {
|
||||
is_woken_up: false,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait(&self) {
|
||||
todo!()
|
||||
while !self.is_woken_up {
|
||||
// yield the execution, to allow other task to contine
|
||||
debug!("Waiter: wait");
|
||||
Task::yield_now();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wake_up(&mut self) {
|
||||
self.is_woken_up = true;
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &D {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
@ -55,9 +55,9 @@ pub unsafe trait Pod: Copy + Sized + Debug {
|
||||
/// FIXME: use derive instead
|
||||
#[macro_export]
|
||||
macro_rules! impl_pod_for {
|
||||
($($token:tt),*/* define the input */) => {
|
||||
($($pod_ty:ty),*/* define the input */) => {
|
||||
/* define the expansion */
|
||||
$(unsafe impl Pod for $token {})*
|
||||
$(unsafe impl Pod for $pod_ty {})*
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,9 @@
|
||||
#![allow(unused_variables)]
|
||||
#![feature(const_btree_new)]
|
||||
#![feature(cstr_from_bytes_until_nul)]
|
||||
#![feature(half_open_range_patterns)]
|
||||
#![feature(exclusive_range_pattern)]
|
||||
#![feature(btree_drain_filter)]
|
||||
|
||||
use alloc::ffi::CString;
|
||||
use kxos_frame::{debug, info, println};
|
||||
|
@ -58,3 +58,12 @@ pub fn write_bytes_to_user(dest: Vaddr, src: &[u8]) {
|
||||
.expect("[Internal error]Current should have vm space to write bytes to user");
|
||||
vm_space.write_bytes(dest, src).expect("write bytes failed")
|
||||
}
|
||||
|
||||
/// write val (Plain of Data type) to user space of current process.
|
||||
pub fn write_val_to_user<T: Pod>(dest: Vaddr, val: T) {
|
||||
let current = Process::current();
|
||||
let vm_space = current
|
||||
.vm_space()
|
||||
.expect("[Internal error]Current should have vm space to write val to user");
|
||||
vm_space.write_val(dest, &val).expect("write val failed");
|
||||
}
|
||||
|
@ -1,38 +1,43 @@
|
||||
use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering};
|
||||
|
||||
use alloc::collections::BTreeMap;
|
||||
use alloc::ffi::CString;
|
||||
use alloc::{
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use kxos_frame::sync::WaitQueue;
|
||||
use kxos_frame::{debug, task::Task, user::UserSpace, vm::VmSpace};
|
||||
use spin::Mutex;
|
||||
|
||||
use crate::memory::mmap_area::MmapArea;
|
||||
use crate::memory::user_heap::UserHeap;
|
||||
|
||||
use self::process_filter::ProcessFilter;
|
||||
use self::status::ProcessStatus;
|
||||
use self::task::create_user_task_from_elf;
|
||||
use self::user_vm_data::UserVm;
|
||||
|
||||
pub mod fifo_scheduler;
|
||||
pub mod process_filter;
|
||||
pub mod status;
|
||||
pub mod task;
|
||||
pub mod user_vm_data;
|
||||
pub mod wait;
|
||||
|
||||
static PID_ALLOCATOR: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
const CHILDREN_CAPACITY: usize = 16;
|
||||
pub type Pid = usize;
|
||||
pub type Pgid = usize;
|
||||
pub type ExitCode = i32;
|
||||
|
||||
/// Process stands for a set of tasks that shares the same userspace.
|
||||
/// Currently, we only support one task inside a process.
|
||||
pub struct Process {
|
||||
// Immutable Part
|
||||
pid: usize,
|
||||
pid: Pid,
|
||||
task: Arc<Task>,
|
||||
filename: Option<CString>,
|
||||
user_space: Option<Arc<UserSpace>>,
|
||||
user_vm: Option<UserVm>,
|
||||
waiting_children: WaitQueue<ProcessFilter>,
|
||||
|
||||
// Mutable Part
|
||||
/// The exit code
|
||||
@ -42,7 +47,7 @@ pub struct Process {
|
||||
/// Parent process
|
||||
parent: Mutex<Option<Weak<Process>>>,
|
||||
/// Children processes
|
||||
children: Mutex<Vec<Arc<Process>>>,
|
||||
children: Mutex<BTreeMap<usize, Arc<Process>>>,
|
||||
}
|
||||
|
||||
impl Process {
|
||||
@ -52,7 +57,7 @@ impl Process {
|
||||
let process = task
|
||||
.data()
|
||||
.downcast_ref::<Weak<Process>>()
|
||||
.expect("[Internal Error] Task data should points to weak<process>");
|
||||
.expect("[Internal Error] task data should points to weak<process>");
|
||||
process
|
||||
.upgrade()
|
||||
.expect("[Internal Error] current process cannot be None")
|
||||
@ -60,7 +65,7 @@ impl Process {
|
||||
|
||||
/// create a new process(not schedule it)
|
||||
pub fn new(
|
||||
pid: usize,
|
||||
pid: Pid,
|
||||
task: Arc<Task>,
|
||||
exec_filename: Option<CString>,
|
||||
user_vm: Option<UserVm>,
|
||||
@ -74,13 +79,15 @@ impl Process {
|
||||
let current_process = Process::current();
|
||||
Some(Arc::downgrade(¤t_process))
|
||||
};
|
||||
let children = Vec::with_capacity(CHILDREN_CAPACITY);
|
||||
let children = BTreeMap::new();
|
||||
let waiting_children = WaitQueue::new();
|
||||
Self {
|
||||
pid,
|
||||
task,
|
||||
filename: exec_filename,
|
||||
user_space,
|
||||
user_vm,
|
||||
waiting_children,
|
||||
exit_code: AtomicI32::new(0),
|
||||
status: Mutex::new(ProcessStatus::Runnable),
|
||||
parent: Mutex::new(parent),
|
||||
@ -88,6 +95,10 @@ impl Process {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn waiting_children(&self) -> &WaitQueue<ProcessFilter> {
|
||||
&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);
|
||||
@ -130,21 +141,35 @@ impl Process {
|
||||
})
|
||||
}
|
||||
|
||||
/// returns the pid
|
||||
pub fn pid(&self) -> usize {
|
||||
/// returns the pid of the process
|
||||
pub fn pid(&self) -> Pid {
|
||||
self.pid
|
||||
}
|
||||
|
||||
/// returns the process group id of the process
|
||||
pub fn pgid(&self) -> Pgid {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// add a child process
|
||||
pub fn add_child(&self, child: Arc<Process>) {
|
||||
debug!("process: {}, add child: {} ", self.pid(), child.pid());
|
||||
self.children.lock().push(child);
|
||||
let child_pid = child.pid();
|
||||
self.children.lock().insert(child_pid, child);
|
||||
}
|
||||
|
||||
fn set_parent(&self, parent: Weak<Process>) {
|
||||
let _ = self.parent.lock().insert(parent);
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<Arc<Process>> {
|
||||
self.parent
|
||||
.lock()
|
||||
.as_ref()
|
||||
.map(|parent| parent.upgrade())
|
||||
.flatten()
|
||||
}
|
||||
|
||||
/// Set the exit code when calling exit or exit_group
|
||||
pub fn set_exit_code(&self, exit_code: i32) {
|
||||
self.exit_code.store(exit_code, Ordering::Relaxed);
|
||||
@ -153,17 +178,27 @@ impl Process {
|
||||
/// Exit current process
|
||||
/// Set the status of current process as Zombie
|
||||
/// Move all children to init process
|
||||
/// Wake up the parent wait queue if parent is waiting for self
|
||||
pub fn exit(&self) {
|
||||
self.status.lock().set_zombie();
|
||||
// move children to the init process
|
||||
let current_process = Process::current();
|
||||
if !current_process.is_init_process() {
|
||||
let init_process = get_init_process();
|
||||
for child in self.children.lock().drain(..) {
|
||||
child.set_parent(Arc::downgrade(&init_process));
|
||||
init_process.add_child(child);
|
||||
for (_, child_process) in self.children.lock().drain_filter(|_, _| true) {
|
||||
child_process.set_parent(Arc::downgrade(&init_process));
|
||||
init_process.add_child(child_process);
|
||||
}
|
||||
}
|
||||
|
||||
// wake up parent waiting children, if any
|
||||
if let Some(parent) = current_process.parent() {
|
||||
parent
|
||||
.waiting_children()
|
||||
.wake_all_on_condition(¤t_process.pid(), |filter, pid| {
|
||||
filter.contains_pid(*pid)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// if the current process is init process
|
||||
@ -215,6 +250,38 @@ 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
|
||||
/// We current just remove the child from the children map.
|
||||
pub fn reap_zombie_child(&self, pid: Pid) -> i32 {
|
||||
let child_process = self.children.lock().remove(&pid).unwrap();
|
||||
assert!(child_process.status() == ProcessStatus::Zombie);
|
||||
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().is_zombie() {
|
||||
return Some(child_process.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn exit_code(&self) -> i32 {
|
||||
self.exit_code.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// whether the process has child process
|
||||
pub fn has_child(&self) -> bool {
|
||||
self.children.lock().len() != 0
|
||||
@ -223,6 +290,10 @@ impl Process {
|
||||
pub fn filename(&self) -> Option<&CString> {
|
||||
self.filename.as_ref()
|
||||
}
|
||||
|
||||
pub fn status(&self) -> ProcessStatus {
|
||||
self.status.lock().clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the init process
|
||||
@ -242,6 +313,6 @@ pub fn get_init_process() -> Arc<Process> {
|
||||
}
|
||||
|
||||
/// allocate a new pid for new process
|
||||
pub fn new_pid() -> usize {
|
||||
pub fn new_pid() -> Pid {
|
||||
PID_ALLOCATOR.fetch_add(1, Ordering::Release)
|
||||
}
|
||||
|
49
src/kxos-std/src/process/process_filter.rs
Normal file
49
src/kxos-std/src/process/process_filter.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use super::{Pgid, Pid, Process};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ProcessFilter {
|
||||
Any,
|
||||
WithPid(Pid),
|
||||
WithPgid(Pgid),
|
||||
}
|
||||
|
||||
impl ProcessFilter {
|
||||
// used for waitid
|
||||
pub fn from_which_and_id(which: u64, id: u64) -> Self {
|
||||
// Does not support PID_FD now(which = 3)
|
||||
// https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/wait.h#L20
|
||||
match which {
|
||||
0 => ProcessFilter::Any,
|
||||
1 => ProcessFilter::WithPid(id as Pid),
|
||||
2 => ProcessFilter::WithPgid(id as Pgid),
|
||||
_ => panic!("Unknown id type"),
|
||||
}
|
||||
}
|
||||
|
||||
// used for wait4
|
||||
pub fn from_wait_pid(wait_pid: isize) -> Self {
|
||||
// https://man7.org/linux/man-pages/man2/waitpid.2.html
|
||||
if wait_pid < -1 {
|
||||
// process group ID is equal to the absolute value of pid.
|
||||
ProcessFilter::WithPgid((-wait_pid) as Pgid)
|
||||
} else if wait_pid == -1 {
|
||||
// wait for any child process
|
||||
ProcessFilter::Any
|
||||
} else if wait_pid == 0 {
|
||||
// wait for any child process with same process group ID
|
||||
let pgid = Process::current().pgid();
|
||||
ProcessFilter::WithPgid(pgid)
|
||||
} else {
|
||||
// pid > 0. wait for the child whose process ID is equal to the value of pid.
|
||||
ProcessFilter::WithPid(wait_pid as Pid)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_pid(&self, pid: Pid) -> bool {
|
||||
match self {
|
||||
ProcessFilter::Any => true,
|
||||
ProcessFilter::WithPid(filter_pid) => *filter_pid == pid,
|
||||
ProcessFilter::WithPgid(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
//! The process status
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ProcessStatus {
|
||||
Runnable,
|
||||
Zombie,
|
||||
@ -8,4 +10,8 @@ impl ProcessStatus {
|
||||
pub fn set_zombie(&mut self) {
|
||||
*self = ProcessStatus::Zombie;
|
||||
}
|
||||
|
||||
pub fn is_zombie(&self) -> bool {
|
||||
*self == ProcessStatus::Zombie
|
||||
}
|
||||
}
|
||||
|
58
src/kxos-std/src/process/wait.rs
Normal file
58
src/kxos-std/src/process/wait.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use bitflags::bitflags;
|
||||
|
||||
use super::{process_filter::ProcessFilter, ExitCode, Pid, Process};
|
||||
|
||||
// The definition of WaitOptions is from Occlum
|
||||
bitflags! {
|
||||
pub struct WaitOptions: u32 {
|
||||
const WNOHANG = 0x1;
|
||||
//Note: Below flags are not supported yet
|
||||
const WSTOPPED = 0x2; // Same as WUNTRACED
|
||||
const WEXITED = 0x4;
|
||||
const WCONTINUED = 0x8;
|
||||
const WNOWAIT = 0x01000000;
|
||||
}
|
||||
}
|
||||
|
||||
impl WaitOptions {
|
||||
pub fn supported(&self) -> bool {
|
||||
let unsupported_flags = WaitOptions::all() - WaitOptions::WNOHANG;
|
||||
!self.intersects(unsupported_flags)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait_child_exit(
|
||||
process_filter: ProcessFilter,
|
||||
wait_options: WaitOptions,
|
||||
) -> (Pid, ExitCode) {
|
||||
let current = Process::current();
|
||||
|
||||
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!(),
|
||||
};
|
||||
|
||||
// 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();
|
||||
if wait_options.contains(WaitOptions::WNOWAIT) {
|
||||
// does not reap child, directly return
|
||||
return Some((wait_pid, exit_code));
|
||||
} else {
|
||||
let exit_code = current.reap_zombie_child(wait_pid);
|
||||
return Some((wait_pid, exit_code));
|
||||
}
|
||||
}
|
||||
|
||||
if wait_options.contains(WaitOptions::WNOHANG) {
|
||||
return Some((0, 0));
|
||||
}
|
||||
|
||||
None
|
||||
});
|
||||
|
||||
(pid, exit_code)
|
||||
}
|
@ -31,7 +31,7 @@ pub fn sys_arch_prctl(code: u64, addr: u64, context: &mut CpuContext) -> Syscall
|
||||
Err(_) => SyscallResult::Return(-1),
|
||||
Ok(code) => {
|
||||
let res = do_arch_prctl(code, addr, context).unwrap();
|
||||
SyscallResult::Return(res as i32)
|
||||
SyscallResult::Return(res as _)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,5 +23,5 @@ pub fn sys_brk(heap_end: u64) -> SyscallResult {
|
||||
.expect("brk should work on process with user space");
|
||||
let new_heap_end = user_heap.brk(new_heap_end, vm_space);
|
||||
|
||||
SyscallResult::Return(new_heap_end as i32)
|
||||
SyscallResult::Return(new_heap_end as _)
|
||||
}
|
||||
|
@ -7,6 +7,6 @@ use crate::{
|
||||
|
||||
pub fn sys_exit_group(exit_code: u64) -> SyscallResult {
|
||||
debug!("[syscall][id={}][SYS_EXIT_GROUP]", SYS_EXIT_GROUP);
|
||||
Process::current().set_exit_code(exit_code as i32);
|
||||
SyscallResult::Exit(exit_code as i32)
|
||||
Process::current().set_exit_code(exit_code as _);
|
||||
SyscallResult::Exit(exit_code as _)
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use super::SyscallResult;
|
||||
pub fn sys_fork(parent_context: CpuContext) -> SyscallResult {
|
||||
debug!("[syscall][id={}][SYS_FORK]", SYS_FORK);
|
||||
let child_process = fork(parent_context);
|
||||
SyscallResult::Return(child_process.pid() as i32)
|
||||
SyscallResult::Return(child_process.pid() as _)
|
||||
}
|
||||
|
||||
/// Fork a child process
|
||||
|
@ -8,5 +8,5 @@ pub fn sys_getpid() -> SyscallResult {
|
||||
debug!("[syscall][id={}][SYS_GETPID]", SYS_GETPID);
|
||||
let pid = Process::current().pid();
|
||||
info!("[sys_getpid]: pid = {}", pid);
|
||||
SyscallResult::Return(pid as i32)
|
||||
SyscallResult::Return(pid as _)
|
||||
}
|
||||
|
@ -8,5 +8,5 @@ pub fn sys_gettid() -> SyscallResult {
|
||||
debug!("[syscall][id={}][SYS_GETTID]", SYS_GETTID);
|
||||
// For single-thread process, tid is equal to pid
|
||||
let tid = Process::current().pid();
|
||||
SyscallResult::Return(tid as i32)
|
||||
SyscallResult::Return(tid as _)
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ pub fn sys_mmap(
|
||||
fd as usize,
|
||||
offset as usize,
|
||||
);
|
||||
SyscallResult::Return(res as i32)
|
||||
SyscallResult::Return(res as _)
|
||||
}
|
||||
|
||||
pub fn do_sys_mmap(
|
||||
|
@ -19,6 +19,8 @@ use crate::syscall::mprotect::sys_mprotect;
|
||||
use crate::syscall::readlink::sys_readlink;
|
||||
use crate::syscall::tgkill::sys_tgkill;
|
||||
use crate::syscall::uname::sys_uname;
|
||||
use crate::syscall::wait4::sys_wait4;
|
||||
use crate::syscall::waitid::sys_waitid;
|
||||
use crate::syscall::write::sys_write;
|
||||
use crate::syscall::writev::sys_writev;
|
||||
|
||||
@ -36,6 +38,8 @@ mod readlink;
|
||||
mod sched_yield;
|
||||
mod tgkill;
|
||||
mod uname;
|
||||
mod wait4;
|
||||
mod waitid;
|
||||
mod write;
|
||||
mod writev;
|
||||
|
||||
@ -51,6 +55,7 @@ const SYS_SCHED_YIELD: u64 = 24;
|
||||
const SYS_GETPID: u64 = 39;
|
||||
const SYS_FORK: u64 = 57;
|
||||
const SYS_EXIT: u64 = 60;
|
||||
const SYS_WAIT4: u64 = 61;
|
||||
const SYS_UNAME: u64 = 63;
|
||||
const SYS_READLINK: u64 = 89;
|
||||
const SYS_GETUID: u64 = 102;
|
||||
@ -61,6 +66,7 @@ const SYS_ARCH_PRCTL: u64 = 158;
|
||||
const SYS_GETTID: u64 = 186;
|
||||
const SYS_EXIT_GROUP: u64 = 231;
|
||||
const SYS_TGKILL: u64 = 234;
|
||||
const SYS_WAITID: u64 = 247;
|
||||
|
||||
pub struct SyscallArgument {
|
||||
syscall_number: u64,
|
||||
@ -121,6 +127,7 @@ pub fn syscall_dispatch(
|
||||
SYS_GETPID => sys_getpid(),
|
||||
SYS_FORK => sys_fork(context.to_owned()),
|
||||
SYS_EXIT => sys_exit(args[0] as _),
|
||||
SYS_WAIT4 => sys_wait4(args[0], args[1], args[2]),
|
||||
SYS_UNAME => sys_uname(args[0]),
|
||||
SYS_READLINK => sys_readlink(args[0], args[1], args[2]),
|
||||
SYS_GETUID => sys_getuid(),
|
||||
@ -131,6 +138,7 @@ pub fn syscall_dispatch(
|
||||
SYS_GETTID => sys_gettid(),
|
||||
SYS_EXIT_GROUP => sys_exit_group(args[0]),
|
||||
SYS_TGKILL => sys_tgkill(args[0], args[1], args[2]),
|
||||
SYS_WAITID => sys_waitid(args[0], args[1], args[2], args[3], args[4]),
|
||||
_ => panic!("Unsupported syscall number: {}", syscall_number),
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ pub fn sys_readlink(filename_ptr: u64, user_buf_ptr: u64, user_buf_len: u64) ->
|
||||
user_buf_ptr as Vaddr,
|
||||
user_buf_len as usize,
|
||||
);
|
||||
SyscallResult::Return(res as i32)
|
||||
SyscallResult::Return(res as _)
|
||||
}
|
||||
|
||||
/// do sys readlink
|
||||
|
24
src/kxos-std/src/syscall/wait4.rs
Normal file
24
src/kxos-std/src/syscall/wait4.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use crate::{
|
||||
memory::write_val_to_user,
|
||||
process::{process_filter::ProcessFilter, wait::wait_child_exit},
|
||||
syscall::SYS_WAIT4,
|
||||
};
|
||||
|
||||
use super::SyscallResult;
|
||||
use crate::process::wait::WaitOptions;
|
||||
use kxos_frame::debug;
|
||||
|
||||
pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> SyscallResult {
|
||||
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 isize);
|
||||
debug!("exit_status_ptr = {}", exit_status_ptr);
|
||||
debug!("wait_options: {:?}", wait_options);
|
||||
let process_filter = ProcessFilter::from_wait_pid(wait_pid as _);
|
||||
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);
|
||||
}
|
||||
|
||||
SyscallResult::Return(return_pid as _)
|
||||
}
|
18
src/kxos-std/src/syscall/waitid.rs
Normal file
18
src/kxos-std/src/syscall/waitid.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use crate::process::{process_filter::ProcessFilter, wait::wait_child_exit};
|
||||
|
||||
use super::SyscallResult;
|
||||
use crate::process::wait::WaitOptions;
|
||||
|
||||
pub fn sys_waitid(
|
||||
which: u64,
|
||||
upid: u64,
|
||||
infoq_addr: u64,
|
||||
options: u64,
|
||||
rusage_addr: u64,
|
||||
) -> SyscallResult {
|
||||
// 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);
|
||||
SyscallResult::Return(pid)
|
||||
}
|
@ -22,7 +22,7 @@ pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> SyscallResult
|
||||
info!("Error message from user mode: {:?}", content);
|
||||
}
|
||||
|
||||
SyscallResult::Return(user_buf_len as i32)
|
||||
SyscallResult::Return(user_buf_len as _)
|
||||
} else {
|
||||
panic!("Unsupported fd number {}", fd);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ pub struct IoVec {
|
||||
pub fn sys_writev(fd: u64, io_vec_addr: u64, io_vec_count: u64) -> SyscallResult {
|
||||
debug!("[syscall][id={}][SYS_WRITEV]", SYS_WRITEV);
|
||||
let res = do_sys_writev(fd, io_vec_addr as Vaddr, io_vec_count as usize);
|
||||
SyscallResult::Return(res as i32)
|
||||
SyscallResult::Return(res as _)
|
||||
}
|
||||
|
||||
pub fn do_sys_writev(fd: u64, io_vec_addr: Vaddr, io_vec_count: usize) -> usize {
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6d1d5aa2ef1105eb716219002763836a47e95cef22997064f6f60bfd4c7a43de
|
||||
size 9528
|
||||
oid sha256:cea612414dc19fcd03b563607ea9a453a3d3390b9f3b229ef8e56b08e4d4c8c5
|
||||
size 9592
|
||||
|
@ -10,6 +10,7 @@ _start:
|
||||
je _child # child process
|
||||
jmp _parent # parent process
|
||||
_parent:
|
||||
call wait_child
|
||||
call get_pid
|
||||
call print_parent_message
|
||||
call exit
|
||||
@ -17,6 +18,16 @@ _child:
|
||||
call get_pid
|
||||
call print_child_message
|
||||
call exit
|
||||
wait_child:
|
||||
mov %rax, %rdi # child process id
|
||||
_loop:
|
||||
mov $61, %rax # syscall number of wait4
|
||||
mov $0, %rsi # exit status address
|
||||
mov $1, %rdx # WNOHANG
|
||||
syscall
|
||||
cmp %rdi, %rax # The return value is the pid of child
|
||||
jne _loop
|
||||
ret
|
||||
exit:
|
||||
mov $60, %rax # syscall number of exit
|
||||
mov $0, %rdi # exit code
|
||||
|
Loading…
x
Reference in New Issue
Block a user