mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 08:53:29 +00:00
Use builder pattern to refactor the process module
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
9ca64c281e
commit
f540345bfd
@ -194,8 +194,8 @@ impl FileLike for PtyMaster {
|
|||||||
// TODO: reimplement when adding session.
|
// TODO: reimplement when adding session.
|
||||||
let foreground = {
|
let foreground = {
|
||||||
let current = current!();
|
let current = current!();
|
||||||
let process_group = current.process_group().lock();
|
let process_group = current.process_group().unwrap();
|
||||||
process_group.clone()
|
Arc::downgrade(&process_group)
|
||||||
};
|
};
|
||||||
self.output.set_fg(foreground);
|
self.output.set_fg(foreground);
|
||||||
Ok(0)
|
Ok(0)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::fs::utils::{IoEvents, Pollee, Poller};
|
use crate::fs::utils::{IoEvents, Pollee, Poller};
|
||||||
use crate::process::process_group::ProcessGroup;
|
|
||||||
use crate::process::signal::constants::{SIGINT, SIGQUIT};
|
use crate::process::signal::constants::{SIGINT, SIGQUIT};
|
||||||
|
use crate::process::ProcessGroup;
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::{signal::signals::kernel::KernelSignal, Pgid},
|
process::{signal::signals::kernel::KernelSignal, Pgid},
|
||||||
|
@ -5,8 +5,7 @@ use self::line_discipline::LineDiscipline;
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::fs::utils::{IoEvents, IoctlCmd, Poller};
|
use crate::fs::utils::{IoEvents, IoctlCmd, Poller};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::process::process_group::ProcessGroup;
|
use crate::process::{process_table, ProcessGroup};
|
||||||
use crate::process::process_table;
|
|
||||||
use crate::util::{read_val_from_user, write_val_to_user};
|
use crate::util::{read_val_from_user, write_val_to_user};
|
||||||
|
|
||||||
pub mod driver;
|
pub mod driver;
|
||||||
@ -101,7 +100,10 @@ impl Device for Tty {
|
|||||||
IoctlCmd::TIOCSPGRP => {
|
IoctlCmd::TIOCSPGRP => {
|
||||||
// Set the process group id of fg progress group
|
// Set the process group id of fg progress group
|
||||||
let pgid = read_val_from_user::<i32>(arg)?;
|
let pgid = read_val_from_user::<i32>(arg)?;
|
||||||
match process_table::pgid_to_process_group(pgid) {
|
if pgid < 0 {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "invalid pgid");
|
||||||
|
}
|
||||||
|
match process_table::pgid_to_process_group(pgid as u32) {
|
||||||
None => self.ldisc.set_fg(Weak::new()),
|
None => self.ldisc.set_fg(Weak::new()),
|
||||||
Some(process_group) => self.ldisc.set_fg(Arc::downgrade(&process_group)),
|
Some(process_group) => self.ldisc.set_fg(Arc::downgrade(&process_group)),
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ impl CommFileOps {
|
|||||||
impl FileOps for CommFileOps {
|
impl FileOps for CommFileOps {
|
||||||
fn data(&self) -> Result<Vec<u8>> {
|
fn data(&self) -> Result<Vec<u8>> {
|
||||||
let mut comm_output = {
|
let mut comm_output = {
|
||||||
let exe_path = self.0.executable_path().read();
|
let exe_path = self.0.executable_path();
|
||||||
let last_component = exe_path.rsplit('/').next().unwrap_or(&exe_path);
|
let last_component = exe_path.rsplit('/').next().unwrap_or(&exe_path);
|
||||||
let mut comm = last_component.as_bytes().to_vec();
|
let mut comm = last_component.as_bytes().to_vec();
|
||||||
comm.push(b'\0');
|
comm.push(b'\0');
|
||||||
|
@ -14,6 +14,6 @@ impl ExeSymOps {
|
|||||||
|
|
||||||
impl SymOps for ExeSymOps {
|
impl SymOps for ExeSymOps {
|
||||||
fn read_link(&self) -> Result<String> {
|
fn read_link(&self) -> Result<String> {
|
||||||
Ok(self.0.executable_path().read().clone())
|
Ok(self.0.executable_path())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ fn init_thread() {
|
|||||||
.expect("Run init process failed.");
|
.expect("Run init process failed.");
|
||||||
|
|
||||||
// Wait till initproc become zombie.
|
// Wait till initproc become zombie.
|
||||||
while !initproc.status().lock().is_zombie() {
|
while !initproc.is_zombie() {
|
||||||
// We don't have preemptive scheduler now.
|
// We don't have preemptive scheduler now.
|
||||||
// The long running init thread should yield its own execution to allow other tasks to go on.
|
// The long running init thread should yield its own execution to allow other tasks to go on.
|
||||||
Thread::yield_now();
|
Thread::yield_now();
|
||||||
|
@ -28,7 +28,7 @@ pub(crate) use pod::Pod;
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! current {
|
macro_rules! current {
|
||||||
() => {
|
() => {
|
||||||
$crate::process::Process::current()
|
$crate::process::current()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
use jinux_frame::{
|
use jinux_frame::{cpu::UserContext, user::UserSpace, vm::VmIo};
|
||||||
cpu::UserContext,
|
|
||||||
user::UserSpace,
|
|
||||||
vm::{VmIo, VmSpace},
|
|
||||||
};
|
|
||||||
|
|
||||||
use jinux_rights::Full;
|
use jinux_rights::Full;
|
||||||
|
|
||||||
@ -12,9 +8,7 @@ use crate::{
|
|||||||
fs::{fs_resolver::FsResolver, utils::FileCreationMask},
|
fs::{fs_resolver::FsResolver, utils::FileCreationMask},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::{
|
process::{
|
||||||
posix_thread::{
|
posix_thread::{PosixThreadBuilder, PosixThreadExt, ThreadName},
|
||||||
builder::PosixThreadBuilder, name::ThreadName, posix_thread_ext::PosixThreadExt,
|
|
||||||
},
|
|
||||||
process_table,
|
process_table,
|
||||||
},
|
},
|
||||||
thread::{allocate_tid, thread_table, Thread, Tid},
|
thread::{allocate_tid, thread_table, Thread, Tid},
|
||||||
@ -24,7 +18,7 @@ use crate::{
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
posix_thread::PosixThread, process_vm::ProcessVm, signal::sig_disposition::SigDispositions,
|
posix_thread::PosixThread, process_vm::ProcessVm, signal::sig_disposition::SigDispositions,
|
||||||
Process,
|
Process, ProcessBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
@ -164,27 +158,39 @@ fn clone_child_thread(parent_context: UserContext, clone_args: CloneArgs) -> Res
|
|||||||
debug_assert!(clone_flags.contains(CloneFlags::CLONE_FILES));
|
debug_assert!(clone_flags.contains(CloneFlags::CLONE_FILES));
|
||||||
debug_assert!(clone_flags.contains(CloneFlags::CLONE_SIGHAND));
|
debug_assert!(clone_flags.contains(CloneFlags::CLONE_SIGHAND));
|
||||||
let child_root_vmar = current.root_vmar();
|
let child_root_vmar = current.root_vmar();
|
||||||
let child_vm_space = child_root_vmar.vm_space().clone();
|
|
||||||
let child_cpu_context = clone_cpu_context(
|
let child_user_space = {
|
||||||
parent_context,
|
let child_vm_space = child_root_vmar.vm_space().clone();
|
||||||
clone_args.new_sp,
|
let child_cpu_context = clone_cpu_context(
|
||||||
clone_args.tls,
|
parent_context,
|
||||||
clone_flags,
|
clone_args.new_sp,
|
||||||
);
|
clone_args.tls,
|
||||||
let child_user_space = Arc::new(UserSpace::new(child_vm_space, child_cpu_context));
|
clone_flags,
|
||||||
|
);
|
||||||
|
Arc::new(UserSpace::new(child_vm_space, child_cpu_context))
|
||||||
|
};
|
||||||
clone_sysvsem(clone_flags)?;
|
clone_sysvsem(clone_flags)?;
|
||||||
|
|
||||||
|
// Inherit sigmask from current thread
|
||||||
|
let sig_mask = {
|
||||||
|
let current_thread = current_thread!();
|
||||||
|
let current_posix_thread = current_thread.as_posix_thread().unwrap();
|
||||||
|
let sigmask = current_posix_thread.sig_mask().lock();
|
||||||
|
*sigmask
|
||||||
|
};
|
||||||
|
|
||||||
let child_tid = allocate_tid();
|
let child_tid = allocate_tid();
|
||||||
// inherit sigmask from current thread
|
let child_thread = {
|
||||||
let current_thread = current_thread!();
|
let is_main_thread = child_tid == current.pid();
|
||||||
let current_posix_thread = current_thread.as_posix_thread().unwrap();
|
let thread_builder = PosixThreadBuilder::new(child_tid, child_user_space)
|
||||||
let sig_mask = *current_posix_thread.sig_mask().lock();
|
.process(Arc::downgrade(¤t))
|
||||||
let is_main_thread = child_tid == current.pid();
|
.sig_mask(sig_mask)
|
||||||
let thread_builder = PosixThreadBuilder::new(child_tid, child_user_space)
|
.is_main_thread(is_main_thread);
|
||||||
.process(Arc::downgrade(¤t))
|
thread_builder.build()
|
||||||
.is_main_thread(is_main_thread);
|
};
|
||||||
let child_thread = thread_builder.build();
|
|
||||||
current.threads.lock().push(child_thread.clone());
|
current.threads().lock().push(child_thread.clone());
|
||||||
|
|
||||||
let child_posix_thread = child_thread.as_posix_thread().unwrap();
|
let child_posix_thread = child_thread.as_posix_thread().unwrap();
|
||||||
clone_parent_settid(child_tid, clone_args.parent_tidptr, clone_flags)?;
|
clone_parent_settid(child_tid, clone_args.parent_tidptr, clone_flags)?;
|
||||||
clone_child_cleartid(child_posix_thread, clone_args.child_tidptr, clone_flags)?;
|
clone_child_cleartid(child_posix_thread, clone_args.child_tidptr, clone_flags)?;
|
||||||
@ -203,73 +209,77 @@ fn clone_child_process(parent_context: UserContext, clone_args: CloneArgs) -> Re
|
|||||||
let clone_flags = clone_args.clone_flags;
|
let clone_flags = clone_args.clone_flags;
|
||||||
|
|
||||||
// clone vm
|
// clone vm
|
||||||
let child_root_vmar = {
|
|
||||||
let parent_root_vmar = current.root_vmar();
|
|
||||||
clone_vm(parent_root_vmar, clone_flags)?
|
|
||||||
};
|
|
||||||
|
|
||||||
let child_process_vm = {
|
let child_process_vm = {
|
||||||
let child_user_heap = current.user_heap().clone();
|
let parent_process_vm = current.vm();
|
||||||
ProcessVm::new(child_user_heap, child_root_vmar.dup()?)
|
clone_vm(parent_process_vm, clone_flags)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// clone user space
|
// clone user space
|
||||||
let child_cpu_context = clone_cpu_context(
|
let child_user_space = {
|
||||||
parent_context,
|
let child_cpu_context = clone_cpu_context(
|
||||||
clone_args.new_sp,
|
parent_context,
|
||||||
clone_args.tls,
|
clone_args.new_sp,
|
||||||
clone_flags,
|
clone_args.tls,
|
||||||
);
|
clone_flags,
|
||||||
let child_vm_space = child_root_vmar.vm_space().clone();
|
);
|
||||||
let child_user_space = Arc::new(UserSpace::new(child_vm_space, child_cpu_context));
|
let child_vm_space = {
|
||||||
|
let child_root_vmar = child_process_vm.root_vmar();
|
||||||
|
child_root_vmar.vm_space().clone()
|
||||||
|
};
|
||||||
|
Arc::new(UserSpace::new(child_vm_space, child_cpu_context))
|
||||||
|
};
|
||||||
|
|
||||||
// clone file table
|
// clone file table
|
||||||
let child_file_table = clone_files(current.file_table(), clone_flags);
|
let child_file_table = clone_files(current.file_table(), clone_flags);
|
||||||
|
|
||||||
// clone fs
|
// clone fs
|
||||||
let child_fs = clone_fs(current.fs(), clone_flags);
|
let child_fs = clone_fs(current.fs(), clone_flags);
|
||||||
|
|
||||||
// clone umask
|
// clone umask
|
||||||
let parent_umask = current.umask.read().get();
|
let child_umask = {
|
||||||
let child_umask = Arc::new(RwLock::new(FileCreationMask::new(parent_umask)));
|
let parent_umask = current.umask().read().get();
|
||||||
|
Arc::new(RwLock::new(FileCreationMask::new(parent_umask)))
|
||||||
|
};
|
||||||
|
|
||||||
// clone sig dispositions
|
// clone sig dispositions
|
||||||
let child_sig_dispositions = clone_sighand(current.sig_dispositions(), clone_flags);
|
let child_sig_dispositions = clone_sighand(current.sig_dispositions(), clone_flags);
|
||||||
|
|
||||||
// clone system V semaphore
|
// clone system V semaphore
|
||||||
clone_sysvsem(clone_flags)?;
|
clone_sysvsem(clone_flags)?;
|
||||||
|
|
||||||
let child_elf_path = current.executable_path().read().clone();
|
|
||||||
let child_thread_name = ThreadName::new_from_executable_path(&child_elf_path)?;
|
|
||||||
|
|
||||||
// inherit parent's sig mask
|
// inherit parent's sig mask
|
||||||
let current_thread = current_thread!();
|
let child_sig_mask = {
|
||||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
let current_thread = current_thread!();
|
||||||
let child_sig_mask = *posix_thread.sig_mask().lock();
|
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||||
|
let sigmask = posix_thread.sig_mask().lock();
|
||||||
|
*sigmask
|
||||||
|
};
|
||||||
|
|
||||||
let child_tid = allocate_tid();
|
let child_tid = allocate_tid();
|
||||||
let mut child_thread_builder = PosixThreadBuilder::new(child_tid, child_user_space)
|
|
||||||
.thread_name(Some(child_thread_name))
|
|
||||||
.sig_mask(child_sig_mask);
|
|
||||||
|
|
||||||
let child = Arc::new_cyclic(|child_process_ref| {
|
let child = {
|
||||||
let weak_child_process = child_process_ref.clone();
|
let child_elf_path = current.executable_path();
|
||||||
let child_pid = child_tid;
|
let child_thread_builder = {
|
||||||
child_thread_builder = child_thread_builder.process(weak_child_process);
|
let child_thread_name = ThreadName::new_from_executable_path(&child_elf_path)?;
|
||||||
let child_thread = child_thread_builder.build();
|
PosixThreadBuilder::new(child_tid, child_user_space)
|
||||||
Process::new(
|
.thread_name(Some(child_thread_name))
|
||||||
child_pid,
|
.sig_mask(child_sig_mask)
|
||||||
parent,
|
};
|
||||||
vec![child_thread],
|
|
||||||
child_elf_path,
|
let mut process_builder =
|
||||||
child_process_vm,
|
ProcessBuilder::new(child_tid, &child_elf_path, Arc::downgrade(¤t));
|
||||||
Weak::new(),
|
|
||||||
child_file_table,
|
process_builder
|
||||||
child_fs,
|
.main_thread_builder(child_thread_builder)
|
||||||
child_umask,
|
.process_vm(child_process_vm)
|
||||||
child_sig_dispositions,
|
.file_table(child_file_table)
|
||||||
)
|
.fs(child_fs)
|
||||||
});
|
.umask(child_umask)
|
||||||
// Inherit parent's process group
|
.sig_dispositions(child_sig_dispositions)
|
||||||
let parent_process_group = current.process_group().lock().upgrade().unwrap();
|
.process_group(current.process_group().unwrap());
|
||||||
parent_process_group.add_process(child.clone());
|
|
||||||
child.set_process_group(Arc::downgrade(&parent_process_group));
|
process_builder.build()?
|
||||||
|
};
|
||||||
|
|
||||||
current!().add_child(child.clone());
|
current!().add_child(child.clone());
|
||||||
process_table::add_process(child.clone());
|
process_table::add_process(child.clone());
|
||||||
@ -278,8 +288,10 @@ fn clone_child_process(parent_context: UserContext, clone_args: CloneArgs) -> Re
|
|||||||
let child_posix_thread = child_thread.as_posix_thread().unwrap();
|
let child_posix_thread = child_thread.as_posix_thread().unwrap();
|
||||||
clone_parent_settid(child_tid, clone_args.parent_tidptr, clone_flags)?;
|
clone_parent_settid(child_tid, clone_args.parent_tidptr, clone_flags)?;
|
||||||
clone_child_cleartid(child_posix_thread, clone_args.child_tidptr, clone_flags)?;
|
clone_child_cleartid(child_posix_thread, clone_args.child_tidptr, clone_flags)?;
|
||||||
|
|
||||||
|
let child_root_vmar = child.root_vmar();
|
||||||
clone_child_settid(
|
clone_child_settid(
|
||||||
&child_root_vmar,
|
child_root_vmar,
|
||||||
child_tid,
|
child_tid,
|
||||||
clone_args.child_tidptr,
|
clone_args.child_tidptr,
|
||||||
clone_flags,
|
clone_flags,
|
||||||
@ -322,13 +334,15 @@ fn clone_parent_settid(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// clone child vmar. If CLONE_VM is set, both threads share the same root vmar.
|
/// Clone child process vm. If CLONE_VM is set, both threads share the same root vmar.
|
||||||
/// Otherwise, fork a new copy-on-write vmar.
|
/// Otherwise, fork a new copy-on-write vmar.
|
||||||
fn clone_vm(parent_root_vmar: &Vmar<Full>, clone_flags: CloneFlags) -> Result<Vmar<Full>> {
|
fn clone_vm(parent_process_vm: &ProcessVm, clone_flags: CloneFlags) -> Result<ProcessVm> {
|
||||||
if clone_flags.contains(CloneFlags::CLONE_VM) {
|
if clone_flags.contains(CloneFlags::CLONE_VM) {
|
||||||
Ok(parent_root_vmar.dup()?)
|
Ok(parent_process_vm.clone())
|
||||||
} else {
|
} else {
|
||||||
Ok(parent_root_vmar.fork_vmar()?)
|
let root_vmar = parent_process_vm.root_vmar().fork_vmar()?;
|
||||||
|
let user_heap = parent_process_vm.user_heap().clone();
|
||||||
|
Ok(ProcessVm::new(user_heap, root_vmar))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,19 +414,3 @@ fn clone_sysvsem(clone_flags: CloneFlags) -> Result<()> {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// debug use. check clone vm space corrent.
|
|
||||||
fn debug_check_clone_vm_space(parent_vm_space: &VmSpace, child_vm_space: &VmSpace) {
|
|
||||||
let mut buffer1 = vec![0u8; 0x78];
|
|
||||||
let mut buffer2 = vec![0u8; 0x78];
|
|
||||||
parent_vm_space
|
|
||||||
.read_bytes(0x401000, &mut buffer1)
|
|
||||||
.expect("read buffer1 failed");
|
|
||||||
child_vm_space
|
|
||||||
.read_bytes(0x401000, &mut buffer2)
|
|
||||||
.expect("read buffer1 failed");
|
|
||||||
for len in 0..buffer1.len() {
|
|
||||||
assert_eq!(buffer1[len], buffer2[len]);
|
|
||||||
}
|
|
||||||
debug!("check clone vm space succeed.");
|
|
||||||
}
|
|
||||||
|
64
services/libs/jinux-std/src/process/exit.rs
Normal file
64
services/libs/jinux-std/src/process/exit.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use crate::process::posix_thread::PosixThreadExt;
|
||||||
|
use crate::process::signal::signals::kernel::KernelSignal;
|
||||||
|
use crate::{prelude::*, process::signal::constants::SIGCHLD};
|
||||||
|
|
||||||
|
use super::{process_table, Pid, Process, TermStatus};
|
||||||
|
|
||||||
|
pub fn do_exit_group(term_status: TermStatus) {
|
||||||
|
let current = current!();
|
||||||
|
debug!("exit group was called");
|
||||||
|
if current.is_zombie() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
current.set_zombie(term_status);
|
||||||
|
|
||||||
|
// Exit all threads
|
||||||
|
let threads = current.threads().lock().clone();
|
||||||
|
for thread in threads {
|
||||||
|
if thread.is_exited() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread.exit();
|
||||||
|
if let Some(posix_thread) = thread.as_posix_thread() {
|
||||||
|
let tid = thread.tid();
|
||||||
|
if let Err(e) = posix_thread.exit(tid, term_status) {
|
||||||
|
debug!("Ignore error when call exit: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close all files then exit the process
|
||||||
|
let files = current.file_table().lock().close_all();
|
||||||
|
for file in files {
|
||||||
|
let _ = file.clean_for_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move children to the init process
|
||||||
|
if !is_init_process(¤t) {
|
||||||
|
if let Some(init_process) = get_init_process() {
|
||||||
|
for (_, child_process) in current.children().lock().extract_if(|_, _| true) {
|
||||||
|
child_process.set_parent(Arc::downgrade(&init_process));
|
||||||
|
init_process.add_child(child_process);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(parent) = current.parent() {
|
||||||
|
// Notify parent
|
||||||
|
let signal = Box::new(KernelSignal::new(SIGCHLD));
|
||||||
|
parent.enqueue_signal(signal);
|
||||||
|
parent.waiting_children().wake_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const INIT_PROCESS_PID: Pid = 1;
|
||||||
|
|
||||||
|
/// Get the init process
|
||||||
|
fn get_init_process() -> Option<Arc<Process>> {
|
||||||
|
process_table::pid_to_process(INIT_PROCESS_PID)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_init_process(process: &Process) -> bool {
|
||||||
|
process.pid() == INIT_PROCESS_PID
|
||||||
|
}
|
@ -1,402 +1,27 @@
|
|||||||
use self::posix_thread::posix_thread_ext::PosixThreadExt;
|
mod clone;
|
||||||
use self::process_group::ProcessGroup;
|
mod exit;
|
||||||
use self::process_vm::user_heap::UserHeap;
|
|
||||||
use self::process_vm::ProcessVm;
|
|
||||||
use self::rlimit::ResourceLimits;
|
|
||||||
use self::signal::constants::SIGCHLD;
|
|
||||||
use self::signal::sig_disposition::SigDispositions;
|
|
||||||
use self::signal::sig_queues::SigQueues;
|
|
||||||
use self::signal::signals::kernel::KernelSignal;
|
|
||||||
use self::signal::signals::Signal;
|
|
||||||
use self::status::ProcessStatus;
|
|
||||||
use crate::device::tty::get_n_tty;
|
|
||||||
use crate::fs::file_table::FileTable;
|
|
||||||
use crate::fs::fs_resolver::FsResolver;
|
|
||||||
use crate::fs::utils::FileCreationMask;
|
|
||||||
use crate::prelude::*;
|
|
||||||
use crate::thread::{allocate_tid, thread_table, Thread};
|
|
||||||
use crate::vm::vmar::Vmar;
|
|
||||||
use jinux_frame::sync::WaitQueue;
|
|
||||||
use jinux_rights::Full;
|
|
||||||
|
|
||||||
pub mod clone;
|
|
||||||
pub mod fifo_scheduler;
|
pub mod fifo_scheduler;
|
||||||
pub mod posix_thread;
|
pub mod posix_thread;
|
||||||
pub mod process_filter;
|
#[allow(clippy::module_inception)]
|
||||||
pub mod process_group;
|
mod process;
|
||||||
|
mod process_filter;
|
||||||
|
mod process_group;
|
||||||
pub mod process_table;
|
pub mod process_table;
|
||||||
pub mod process_vm;
|
mod process_vm;
|
||||||
pub mod program_loader;
|
mod program_loader;
|
||||||
pub mod rlimit;
|
mod rlimit;
|
||||||
pub mod signal;
|
pub mod signal;
|
||||||
pub mod status;
|
mod status;
|
||||||
mod term_status;
|
mod term_status;
|
||||||
pub mod wait;
|
mod wait;
|
||||||
|
|
||||||
|
pub use clone::{clone_child, CloneArgs, CloneFlags};
|
||||||
|
pub use exit::do_exit_group;
|
||||||
|
pub use process::ProcessBuilder;
|
||||||
|
pub use process::{current, ExitCode, Pgid, Pid, Process};
|
||||||
|
pub use process_filter::ProcessFilter;
|
||||||
|
pub use process_group::ProcessGroup;
|
||||||
|
pub use program_loader::{check_executable_file, load_program_to_vm};
|
||||||
|
pub use rlimit::ResourceType;
|
||||||
pub use term_status::TermStatus;
|
pub use term_status::TermStatus;
|
||||||
|
pub use wait::{wait_child_exit, WaitOptions};
|
||||||
pub type Pid = i32;
|
|
||||||
pub type Pgid = i32;
|
|
||||||
pub type ExitCode = i32;
|
|
||||||
|
|
||||||
const INIT_PROCESS_PID: Pid = 1;
|
|
||||||
|
|
||||||
/// Process stands for a set of threads that shares the same userspace.
|
|
||||||
pub struct Process {
|
|
||||||
// Immutable Part
|
|
||||||
pid: Pid,
|
|
||||||
|
|
||||||
process_vm: ProcessVm,
|
|
||||||
/// wait for child status changed
|
|
||||||
waiting_children: WaitQueue,
|
|
||||||
|
|
||||||
// Mutable Part
|
|
||||||
/// The executable path.
|
|
||||||
executable_path: RwLock<String>,
|
|
||||||
/// The threads
|
|
||||||
threads: Mutex<Vec<Arc<Thread>>>,
|
|
||||||
/// Process status
|
|
||||||
status: Mutex<ProcessStatus>,
|
|
||||||
/// Parent process
|
|
||||||
parent: Mutex<Weak<Process>>,
|
|
||||||
/// Children processes
|
|
||||||
children: Mutex<BTreeMap<Pid, Arc<Process>>>,
|
|
||||||
/// Process group
|
|
||||||
process_group: Mutex<Weak<ProcessGroup>>,
|
|
||||||
/// File table
|
|
||||||
file_table: Arc<Mutex<FileTable>>,
|
|
||||||
/// FsResolver
|
|
||||||
fs: Arc<RwLock<FsResolver>>,
|
|
||||||
/// umask
|
|
||||||
umask: Arc<RwLock<FileCreationMask>>,
|
|
||||||
/// resource limits
|
|
||||||
resource_limits: Mutex<ResourceLimits>,
|
|
||||||
|
|
||||||
// Signal
|
|
||||||
/// sig dispositions
|
|
||||||
sig_dispositions: Arc<Mutex<SigDispositions>>,
|
|
||||||
/// Process-level signal queues
|
|
||||||
sig_queues: Mutex<SigQueues>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Process {
|
|
||||||
/// returns the current process
|
|
||||||
pub fn current() -> Arc<Process> {
|
|
||||||
let current_thread = Thread::current();
|
|
||||||
if let Some(posix_thread) = current_thread.as_posix_thread() {
|
|
||||||
posix_thread.process()
|
|
||||||
} else {
|
|
||||||
panic!("[Internal error]The current thread does not belong to a process");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// create a new process(not schedule it)
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub fn new(
|
|
||||||
pid: Pid,
|
|
||||||
parent: Weak<Process>,
|
|
||||||
threads: Vec<Arc<Thread>>,
|
|
||||||
executable_path: String,
|
|
||||||
process_vm: ProcessVm,
|
|
||||||
process_group: Weak<ProcessGroup>,
|
|
||||||
file_table: Arc<Mutex<FileTable>>,
|
|
||||||
fs: Arc<RwLock<FsResolver>>,
|
|
||||||
umask: Arc<RwLock<FileCreationMask>>,
|
|
||||||
sig_dispositions: Arc<Mutex<SigDispositions>>,
|
|
||||||
) -> Self {
|
|
||||||
let children = BTreeMap::new();
|
|
||||||
let waiting_children = WaitQueue::new();
|
|
||||||
let resource_limits = ResourceLimits::default();
|
|
||||||
Self {
|
|
||||||
pid,
|
|
||||||
threads: Mutex::new(threads),
|
|
||||||
executable_path: RwLock::new(executable_path),
|
|
||||||
process_vm,
|
|
||||||
waiting_children,
|
|
||||||
status: Mutex::new(ProcessStatus::Runnable),
|
|
||||||
parent: Mutex::new(parent),
|
|
||||||
children: Mutex::new(children),
|
|
||||||
process_group: Mutex::new(process_group),
|
|
||||||
file_table,
|
|
||||||
fs,
|
|
||||||
umask,
|
|
||||||
sig_dispositions,
|
|
||||||
sig_queues: Mutex::new(SigQueues::new()),
|
|
||||||
resource_limits: Mutex::new(resource_limits),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn waiting_children(&self) -> &WaitQueue {
|
|
||||||
&self.waiting_children
|
|
||||||
}
|
|
||||||
|
|
||||||
/// init a user process and run the process
|
|
||||||
pub fn spawn_user_process(
|
|
||||||
executable_path: &str,
|
|
||||||
argv: Vec<CString>,
|
|
||||||
envp: Vec<CString>,
|
|
||||||
) -> Result<Arc<Self>> {
|
|
||||||
// spawn user process should give an absolute path
|
|
||||||
debug_assert!(executable_path.starts_with('/'));
|
|
||||||
let process = Process::create_user_process(executable_path, argv, envp)?;
|
|
||||||
// FIXME: How to determine the fg process group?
|
|
||||||
let process_group = Weak::clone(&process.process_group.lock());
|
|
||||||
// FIXME: tty should be a parameter?
|
|
||||||
let tty = get_n_tty();
|
|
||||||
tty.set_fg(process_group);
|
|
||||||
process.run();
|
|
||||||
Ok(process)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_user_process(
|
|
||||||
executable_path: &str,
|
|
||||||
argv: Vec<CString>,
|
|
||||||
envp: Vec<CString>,
|
|
||||||
) -> Result<Arc<Self>> {
|
|
||||||
let fs = FsResolver::new();
|
|
||||||
let umask = FileCreationMask::default();
|
|
||||||
let pid = allocate_tid();
|
|
||||||
let parent = Weak::new();
|
|
||||||
let process_group = Weak::new();
|
|
||||||
let process_vm = ProcessVm::alloc()?;
|
|
||||||
let file_table = FileTable::new_with_stdio();
|
|
||||||
let sig_dispositions = SigDispositions::new();
|
|
||||||
let user_process = Arc::new(Process::new(
|
|
||||||
pid,
|
|
||||||
parent,
|
|
||||||
vec![],
|
|
||||||
executable_path.to_string(),
|
|
||||||
process_vm,
|
|
||||||
process_group,
|
|
||||||
Arc::new(Mutex::new(file_table)),
|
|
||||||
Arc::new(RwLock::new(fs)),
|
|
||||||
Arc::new(RwLock::new(umask)),
|
|
||||||
Arc::new(Mutex::new(sig_dispositions)),
|
|
||||||
));
|
|
||||||
|
|
||||||
let thread = Thread::new_posix_thread_from_executable(
|
|
||||||
pid,
|
|
||||||
&user_process.process_vm,
|
|
||||||
&user_process.fs().read(),
|
|
||||||
executable_path,
|
|
||||||
Arc::downgrade(&user_process),
|
|
||||||
argv,
|
|
||||||
envp,
|
|
||||||
)?;
|
|
||||||
user_process.threads().lock().push(thread);
|
|
||||||
|
|
||||||
// Set process group
|
|
||||||
user_process.create_and_set_process_group();
|
|
||||||
process_table::add_process(user_process.clone());
|
|
||||||
Ok(user_process)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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 {
|
|
||||||
if let Some(process_group) = self.process_group.lock().upgrade() {
|
|
||||||
process_group.pgid()
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_group(&self) -> &Mutex<Weak<ProcessGroup>> {
|
|
||||||
&self.process_group
|
|
||||||
}
|
|
||||||
|
|
||||||
/// add a child process
|
|
||||||
pub fn add_child(&self, child: Arc<Process>) {
|
|
||||||
let child_pid = child.pid();
|
|
||||||
self.children.lock().insert(child_pid, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_parent(&self, parent: Weak<Process>) {
|
|
||||||
*self.parent.lock() = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set process group for current process. If old process group exists,
|
|
||||||
/// remove current process from old process group.
|
|
||||||
pub fn set_process_group(&self, process_group: Weak<ProcessGroup>) {
|
|
||||||
if let Some(old_process_group) = self.process_group.lock().upgrade() {
|
|
||||||
old_process_group.remove_process(self.pid());
|
|
||||||
}
|
|
||||||
*self.process_group.lock() = process_group;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn file_table(&self) -> &Arc<Mutex<FileTable>> {
|
|
||||||
&self.file_table
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fs(&self) -> &Arc<RwLock<FsResolver>> {
|
|
||||||
&self.fs
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn umask(&self) -> &Arc<RwLock<FileCreationMask>> {
|
|
||||||
&self.umask
|
|
||||||
}
|
|
||||||
|
|
||||||
/// create a new process group for the process and add it to globle table.
|
|
||||||
/// Then set the process group for current process.
|
|
||||||
fn create_and_set_process_group(self: &Arc<Self>) {
|
|
||||||
let process_group = Arc::new(ProcessGroup::new(self.clone()));
|
|
||||||
let pgid = process_group.pgid();
|
|
||||||
self.set_process_group(Arc::downgrade(&process_group));
|
|
||||||
process_table::add_process_group(process_group);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parent(&self) -> Option<Arc<Process>> {
|
|
||||||
self.parent.lock().upgrade()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Exit thread group(the 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_group(&self, term_status: TermStatus) {
|
|
||||||
debug!("exit group was called");
|
|
||||||
if self.status.lock().is_zombie() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.status.lock().set_zombie(term_status);
|
|
||||||
|
|
||||||
let threads = self.threads.lock().clone();
|
|
||||||
for thread in threads {
|
|
||||||
if thread.is_exited() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
thread.exit();
|
|
||||||
if let Some(posix_thread) = thread.as_posix_thread() {
|
|
||||||
let tid = thread.tid();
|
|
||||||
if let Err(e) = posix_thread.exit(tid, term_status) {
|
|
||||||
debug!("Ignore error when call exit: {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// close all files then exit the process
|
|
||||||
let files = self.file_table().lock().close_all();
|
|
||||||
for file in files {
|
|
||||||
let _ = file.clean_for_close();
|
|
||||||
}
|
|
||||||
// move children to the init process
|
|
||||||
if !self.is_init_process() {
|
|
||||||
if let Some(init_process) = get_init_process() {
|
|
||||||
for (_, child_process) in self.children.lock().extract_if(|_, _| true) {
|
|
||||||
child_process.set_parent(Arc::downgrade(&init_process));
|
|
||||||
init_process.add_child(child_process);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// if the current process is init process
|
|
||||||
pub fn is_init_process(&self) -> bool {
|
|
||||||
self.pid == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// start to run current process
|
|
||||||
pub fn run(&self) {
|
|
||||||
let threads = self.threads.lock();
|
|
||||||
// when run the process, the process should has only one thread
|
|
||||||
debug_assert!(threads.len() == 1);
|
|
||||||
let thread = threads[0].clone();
|
|
||||||
// should not hold the lock when run thread
|
|
||||||
drop(threads);
|
|
||||||
thread.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn threads(&self) -> &Mutex<Vec<Arc<Thread>>> {
|
|
||||||
&self.threads
|
|
||||||
}
|
|
||||||
|
|
||||||
/// returns the user_vm
|
|
||||||
pub fn process_vm(&self) -> &ProcessVm {
|
|
||||||
&self.process_vm
|
|
||||||
}
|
|
||||||
|
|
||||||
/// returns the root vmar
|
|
||||||
pub fn root_vmar(&self) -> &Vmar<Full> {
|
|
||||||
self.process_vm.root_vmar()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// returns the user heap if the process does have, otherwise None
|
|
||||||
pub fn user_heap(&self) -> &UserHeap {
|
|
||||||
self.process_vm.user_heap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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) -> u32 {
|
|
||||||
let child_process = self.children.lock().remove(&pid).unwrap();
|
|
||||||
assert!(child_process.status().lock().is_zombie());
|
|
||||||
child_process.root_vmar().destroy_all().unwrap();
|
|
||||||
for thread in &*child_process.threads.lock() {
|
|
||||||
thread_table::remove_thread(thread.tid());
|
|
||||||
}
|
|
||||||
process_table::remove_process(child_process.pid());
|
|
||||||
if let Some(process_group) = child_process.process_group().lock().upgrade() {
|
|
||||||
process_group.remove_process(child_process.pid);
|
|
||||||
}
|
|
||||||
child_process.exit_code().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn children(&self) -> &Mutex<BTreeMap<Pid, Arc<Process>>> {
|
|
||||||
&self.children
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exit_code(&self) -> Option<u32> {
|
|
||||||
match &*self.status.lock() {
|
|
||||||
ProcessStatus::Runnable => None,
|
|
||||||
ProcessStatus::Zombie(term_status) => Some(term_status.as_u32()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// whether the process has child process
|
|
||||||
pub fn has_child(&self) -> bool {
|
|
||||||
self.children.lock().len() != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn executable_path(&self) -> &RwLock<String> {
|
|
||||||
&self.executable_path
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn status(&self) -> &Mutex<ProcessStatus> {
|
|
||||||
&self.status
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resource_limits(&self) -> &Mutex<ResourceLimits> {
|
|
||||||
&self.resource_limits
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sig_dispositions(&self) -> &Arc<Mutex<SigDispositions>> {
|
|
||||||
&self.sig_dispositions
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sig_queues(&self) -> &Mutex<SigQueues> {
|
|
||||||
&self.sig_queues
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enqueue_signal(&self, signal: Box<dyn Signal>) {
|
|
||||||
if !self.status().lock().is_zombie() {
|
|
||||||
self.sig_queues.lock().enqueue(signal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the init process
|
|
||||||
pub fn get_init_process() -> Option<Arc<Process>> {
|
|
||||||
process_table::pid_to_process(INIT_PROCESS_PID)
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::{
|
process::{
|
||||||
|
do_exit_group,
|
||||||
posix_thread::{futex::futex_wake, robust_list::wake_robust_futex},
|
posix_thread::{futex::futex_wake, robust_list::wake_robust_futex},
|
||||||
TermStatus,
|
TermStatus,
|
||||||
},
|
},
|
||||||
@ -8,18 +9,21 @@ use crate::{
|
|||||||
util::write_val_to_user,
|
util::write_val_to_user,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::{name::ThreadName, robust_list::RobustListHead};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
signal::{sig_mask::SigMask, sig_queues::SigQueues},
|
signal::{sig_mask::SigMask, sig_queues::SigQueues, signals::Signal},
|
||||||
Process,
|
Process,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod builder;
|
mod builder;
|
||||||
pub mod futex;
|
pub mod futex;
|
||||||
pub mod name;
|
mod name;
|
||||||
pub mod posix_thread_ext;
|
mod posix_thread_ext;
|
||||||
pub mod robust_list;
|
mod robust_list;
|
||||||
|
|
||||||
|
pub use builder::PosixThreadBuilder;
|
||||||
|
pub use name::{ThreadName, MAX_THREAD_NAME_LEN};
|
||||||
|
pub use posix_thread_ext::PosixThreadExt;
|
||||||
|
pub use robust_list::RobustListHead;
|
||||||
|
|
||||||
pub struct PosixThread {
|
pub struct PosixThread {
|
||||||
// Immutable part
|
// Immutable part
|
||||||
@ -71,6 +75,18 @@ impl PosixThread {
|
|||||||
&self.sig_queues
|
&self.sig_queues
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_pending_signal(&self) -> bool {
|
||||||
|
self.sig_queues.lock().is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueue_signal(&self, signal: Box<dyn Signal>) {
|
||||||
|
self.sig_queues.lock().enqueue(signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeue_signal(&self, mask: &SigMask) -> Option<Box<dyn Signal>> {
|
||||||
|
self.sig_queues.lock().dequeue(mask)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sig_context(&self) -> &Mutex<Option<Vaddr>> {
|
pub fn sig_context(&self) -> &Mutex<Option<Vaddr>> {
|
||||||
&self.sig_context
|
&self.sig_context
|
||||||
}
|
}
|
||||||
@ -133,7 +149,7 @@ impl PosixThread {
|
|||||||
// exit the robust list: walk the robust list; mark futex words as dead and do futex wake
|
// exit the robust list: walk the robust list; mark futex words as dead and do futex wake
|
||||||
self.wake_robust_list(tid);
|
self.wake_robust_list(tid);
|
||||||
|
|
||||||
if tid != self.process().pid {
|
if tid != self.process().pid() {
|
||||||
// If the thread is not main thread. We don't remove main thread.
|
// If the thread is not main thread. We don't remove main thread.
|
||||||
// Main thread are removed when the whole process is reaped.
|
// Main thread are removed when the whole process is reaped.
|
||||||
thread_table::remove_thread(tid);
|
thread_table::remove_thread(tid);
|
||||||
@ -144,7 +160,7 @@ impl PosixThread {
|
|||||||
debug!("self is main thread or last thread");
|
debug!("self is main thread or last thread");
|
||||||
debug!("main thread: {}", self.is_main_thread());
|
debug!("main thread: {}", self.is_main_thread());
|
||||||
debug!("last thread: {}", self.is_last_thread());
|
debug!("last thread: {}", self.is_last_thread());
|
||||||
current!().exit_group(term_status);
|
do_exit_group(term_status);
|
||||||
}
|
}
|
||||||
debug!("perform futex wake");
|
debug!("perform futex wake");
|
||||||
futex_wake(Arc::as_ptr(&self.process()) as Vaddr, 1)?;
|
futex_wake(Arc::as_ptr(&self.process()) as Vaddr, 1)?;
|
||||||
|
@ -132,7 +132,7 @@ pub fn wake_robust_futex(futex_addr: Vaddr, tid: Pid) -> Result<()> {
|
|||||||
let mut old_val = futex_val;
|
let mut old_val = futex_val;
|
||||||
loop {
|
loop {
|
||||||
// This futex may held by another thread, do nothing
|
// This futex may held by another thread, do nothing
|
||||||
if old_val & FUTEX_TID_MASK != tid as u32 {
|
if old_val & FUTEX_TID_MASK != tid {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let new_val = (old_val & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
|
let new_val = (old_val & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
|
||||||
|
212
services/libs/jinux-std/src/process/process/builder.rs
Normal file
212
services/libs/jinux-std/src/process/process/builder.rs
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
use crate::fs::file_table::FileTable;
|
||||||
|
use crate::fs::fs_resolver::FsResolver;
|
||||||
|
use crate::fs::utils::FileCreationMask;
|
||||||
|
use crate::process::posix_thread::PosixThreadBuilder;
|
||||||
|
use crate::process::process_group::ProcessGroup;
|
||||||
|
use crate::process::process_table;
|
||||||
|
use crate::process::process_vm::ProcessVm;
|
||||||
|
use crate::process::rlimit::ResourceLimits;
|
||||||
|
use crate::process::{posix_thread::PosixThreadExt, signal::sig_disposition::SigDispositions};
|
||||||
|
use crate::thread::Thread;
|
||||||
|
|
||||||
|
use super::{Pid, Process};
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub struct ProcessBuilder<'a> {
|
||||||
|
// Essential parts
|
||||||
|
pid: Pid,
|
||||||
|
executable_path: &'a str,
|
||||||
|
parent: Weak<Process>,
|
||||||
|
|
||||||
|
// Optional parts
|
||||||
|
main_thread_builder: Option<PosixThreadBuilder>,
|
||||||
|
argv: Option<Vec<CString>>,
|
||||||
|
envp: Option<Vec<CString>>,
|
||||||
|
process_vm: Option<ProcessVm>,
|
||||||
|
process_group: Option<Arc<ProcessGroup>>,
|
||||||
|
file_table: Option<Arc<Mutex<FileTable>>>,
|
||||||
|
fs: Option<Arc<RwLock<FsResolver>>>,
|
||||||
|
umask: Option<Arc<RwLock<FileCreationMask>>>,
|
||||||
|
resource_limits: Option<ResourceLimits>,
|
||||||
|
sig_dispositions: Option<Arc<Mutex<SigDispositions>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ProcessBuilder<'a> {
|
||||||
|
pub fn new(pid: Pid, executable_path: &'a str, parent: Weak<Process>) -> Self {
|
||||||
|
ProcessBuilder {
|
||||||
|
pid,
|
||||||
|
executable_path,
|
||||||
|
parent,
|
||||||
|
main_thread_builder: None,
|
||||||
|
argv: None,
|
||||||
|
envp: None,
|
||||||
|
process_vm: None,
|
||||||
|
process_group: None,
|
||||||
|
file_table: None,
|
||||||
|
fs: None,
|
||||||
|
umask: None,
|
||||||
|
resource_limits: None,
|
||||||
|
sig_dispositions: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main_thread_builder(&mut self, builder: PosixThreadBuilder) -> &mut Self {
|
||||||
|
self.main_thread_builder = Some(builder);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_vm(&mut self, process_vm: ProcessVm) -> &mut Self {
|
||||||
|
self.process_vm = Some(process_vm);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_group(&mut self, process_group: Arc<ProcessGroup>) -> &mut Self {
|
||||||
|
self.process_group = Some(process_group);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_table(&mut self, file_table: Arc<Mutex<FileTable>>) -> &mut Self {
|
||||||
|
self.file_table = Some(file_table);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fs(&mut self, fs: Arc<RwLock<FsResolver>>) -> &mut Self {
|
||||||
|
self.fs = Some(fs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn umask(&mut self, umask: Arc<RwLock<FileCreationMask>>) -> &mut Self {
|
||||||
|
self.umask = Some(umask);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resource_limits(&mut self, resource_limits: ResourceLimits) -> &mut Self {
|
||||||
|
self.resource_limits = Some(resource_limits);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sig_dispositions(&mut self, sig_dispositions: Arc<Mutex<SigDispositions>>) -> &mut Self {
|
||||||
|
self.sig_dispositions = Some(sig_dispositions);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn argv(&mut self, argv: Vec<CString>) -> &mut Self {
|
||||||
|
self.argv = Some(argv);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn envp(&mut self, envp: Vec<CString>) -> &mut Self {
|
||||||
|
self.envp = Some(envp);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_build(&self) -> Result<()> {
|
||||||
|
if self.main_thread_builder.is_some() {
|
||||||
|
debug_assert!(self.parent.upgrade().is_some());
|
||||||
|
debug_assert!(self.argv.is_none());
|
||||||
|
debug_assert!(self.envp.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.main_thread_builder.is_none() {
|
||||||
|
debug_assert!(self.parent.upgrade().is_none());
|
||||||
|
debug_assert!(self.argv.is_some());
|
||||||
|
debug_assert!(self.envp.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Result<Arc<Process>> {
|
||||||
|
self.check_build()?;
|
||||||
|
let Self {
|
||||||
|
pid,
|
||||||
|
executable_path,
|
||||||
|
parent,
|
||||||
|
main_thread_builder,
|
||||||
|
argv,
|
||||||
|
envp,
|
||||||
|
process_vm,
|
||||||
|
process_group,
|
||||||
|
file_table,
|
||||||
|
fs,
|
||||||
|
umask,
|
||||||
|
resource_limits,
|
||||||
|
sig_dispositions,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
let process_vm = process_vm
|
||||||
|
.or_else(|| Some(ProcessVm::alloc().unwrap()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let process_group_ref = process_group
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(Weak::new, Arc::downgrade);
|
||||||
|
|
||||||
|
let file_table = file_table
|
||||||
|
.or_else(|| Some(Arc::new(Mutex::new(FileTable::new_with_stdio()))))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let fs = fs
|
||||||
|
.or_else(|| Some(Arc::new(RwLock::new(FsResolver::new()))))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let umask = umask
|
||||||
|
.or_else(|| Some(Arc::new(RwLock::new(FileCreationMask::default()))))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let resource_limits = resource_limits
|
||||||
|
.or_else(|| Some(ResourceLimits::default()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let sig_dispositions = sig_dispositions
|
||||||
|
.or_else(|| Some(Arc::new(Mutex::new(SigDispositions::new()))))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let process = {
|
||||||
|
let threads = Vec::new();
|
||||||
|
Arc::new(Process::new(
|
||||||
|
pid,
|
||||||
|
parent,
|
||||||
|
threads,
|
||||||
|
executable_path.to_string(),
|
||||||
|
process_vm,
|
||||||
|
process_group_ref,
|
||||||
|
file_table,
|
||||||
|
fs,
|
||||||
|
umask,
|
||||||
|
sig_dispositions,
|
||||||
|
resource_limits,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
|
||||||
|
let thread = if let Some(thread_builder) = main_thread_builder {
|
||||||
|
let builder = thread_builder.process(Arc::downgrade(&process));
|
||||||
|
builder.build()
|
||||||
|
} else {
|
||||||
|
Thread::new_posix_thread_from_executable(
|
||||||
|
pid,
|
||||||
|
process.vm(),
|
||||||
|
&process.fs().read(),
|
||||||
|
executable_path,
|
||||||
|
Arc::downgrade(&process),
|
||||||
|
argv.unwrap(),
|
||||||
|
envp.unwrap(),
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
|
process.threads().lock().push(thread);
|
||||||
|
|
||||||
|
if let Some(process_group) = process_group {
|
||||||
|
process_group.add_process(process.clone());
|
||||||
|
} else {
|
||||||
|
let new_process_group = Arc::new(ProcessGroup::new(process.clone()));
|
||||||
|
let pgid = new_process_group.pgid();
|
||||||
|
process.set_process_group(Arc::downgrade(&new_process_group));
|
||||||
|
process_table::add_process_group(new_process_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.set_runnable();
|
||||||
|
|
||||||
|
Ok(process)
|
||||||
|
}
|
||||||
|
}
|
299
services/libs/jinux-std/src/process/process/mod.rs
Normal file
299
services/libs/jinux-std/src/process/process/mod.rs
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
mod builder;
|
||||||
|
|
||||||
|
use super::posix_thread::PosixThreadExt;
|
||||||
|
use super::process_group::ProcessGroup;
|
||||||
|
use super::process_vm::user_heap::UserHeap;
|
||||||
|
use super::process_vm::ProcessVm;
|
||||||
|
use super::rlimit::ResourceLimits;
|
||||||
|
use super::signal::sig_disposition::SigDispositions;
|
||||||
|
use super::signal::sig_mask::SigMask;
|
||||||
|
use super::signal::sig_queues::SigQueues;
|
||||||
|
use super::signal::signals::Signal;
|
||||||
|
use super::status::ProcessStatus;
|
||||||
|
use super::{process_table, TermStatus};
|
||||||
|
use crate::device::tty::get_n_tty;
|
||||||
|
use crate::fs::file_table::FileTable;
|
||||||
|
use crate::fs::fs_resolver::FsResolver;
|
||||||
|
use crate::fs::utils::FileCreationMask;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::thread::{allocate_tid, Thread};
|
||||||
|
use crate::vm::vmar::Vmar;
|
||||||
|
use jinux_frame::sync::WaitQueue;
|
||||||
|
use jinux_rights::Full;
|
||||||
|
|
||||||
|
pub use builder::ProcessBuilder;
|
||||||
|
|
||||||
|
pub type Pid = u32;
|
||||||
|
pub type Pgid = u32;
|
||||||
|
pub type ExitCode = i32;
|
||||||
|
|
||||||
|
/// Process stands for a set of threads that shares the same userspace.
|
||||||
|
pub struct Process {
|
||||||
|
// Immutable Part
|
||||||
|
pid: Pid,
|
||||||
|
|
||||||
|
process_vm: ProcessVm,
|
||||||
|
/// wait for child status changed
|
||||||
|
waiting_children: WaitQueue,
|
||||||
|
|
||||||
|
// Mutable Part
|
||||||
|
/// The executable path.
|
||||||
|
executable_path: RwLock<String>,
|
||||||
|
/// The threads
|
||||||
|
threads: Mutex<Vec<Arc<Thread>>>,
|
||||||
|
/// Process status
|
||||||
|
status: Mutex<ProcessStatus>,
|
||||||
|
/// Parent process
|
||||||
|
parent: Mutex<Weak<Process>>,
|
||||||
|
/// Children processes
|
||||||
|
children: Mutex<BTreeMap<Pid, Arc<Process>>>,
|
||||||
|
/// Process group
|
||||||
|
process_group: Mutex<Weak<ProcessGroup>>,
|
||||||
|
/// File table
|
||||||
|
file_table: Arc<Mutex<FileTable>>,
|
||||||
|
/// FsResolver
|
||||||
|
fs: Arc<RwLock<FsResolver>>,
|
||||||
|
/// umask
|
||||||
|
umask: Arc<RwLock<FileCreationMask>>,
|
||||||
|
/// resource limits
|
||||||
|
resource_limits: Mutex<ResourceLimits>,
|
||||||
|
|
||||||
|
// Signal
|
||||||
|
/// sig dispositions
|
||||||
|
sig_dispositions: Arc<Mutex<SigDispositions>>,
|
||||||
|
/// Process-level signal queues
|
||||||
|
sig_queues: Mutex<SigQueues>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Process {
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn new(
|
||||||
|
pid: Pid,
|
||||||
|
parent: Weak<Process>,
|
||||||
|
threads: Vec<Arc<Thread>>,
|
||||||
|
executable_path: String,
|
||||||
|
process_vm: ProcessVm,
|
||||||
|
process_group: Weak<ProcessGroup>,
|
||||||
|
file_table: Arc<Mutex<FileTable>>,
|
||||||
|
fs: Arc<RwLock<FsResolver>>,
|
||||||
|
umask: Arc<RwLock<FileCreationMask>>,
|
||||||
|
sig_dispositions: Arc<Mutex<SigDispositions>>,
|
||||||
|
resource_limits: ResourceLimits,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
pid,
|
||||||
|
threads: Mutex::new(threads),
|
||||||
|
executable_path: RwLock::new(executable_path),
|
||||||
|
process_vm,
|
||||||
|
waiting_children: WaitQueue::new(),
|
||||||
|
status: Mutex::new(ProcessStatus::Uninit),
|
||||||
|
parent: Mutex::new(parent),
|
||||||
|
children: Mutex::new(BTreeMap::new()),
|
||||||
|
process_group: Mutex::new(process_group),
|
||||||
|
file_table,
|
||||||
|
fs,
|
||||||
|
umask,
|
||||||
|
sig_dispositions,
|
||||||
|
sig_queues: Mutex::new(SigQueues::new()),
|
||||||
|
resource_limits: Mutex::new(resource_limits),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// init a user process and run the process
|
||||||
|
pub fn spawn_user_process(
|
||||||
|
executable_path: &str,
|
||||||
|
argv: Vec<CString>,
|
||||||
|
envp: Vec<CString>,
|
||||||
|
) -> Result<Arc<Self>> {
|
||||||
|
// spawn user process should give an absolute path
|
||||||
|
debug_assert!(executable_path.starts_with('/'));
|
||||||
|
let process = Process::create_user_process(executable_path, argv, envp)?;
|
||||||
|
// FIXME: How to determine the fg process group?
|
||||||
|
let process_group = Weak::clone(&process.process_group.lock());
|
||||||
|
// FIXME: tty should be a parameter?
|
||||||
|
let tty = get_n_tty();
|
||||||
|
tty.set_fg(process_group);
|
||||||
|
process.run();
|
||||||
|
Ok(process)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_user_process(
|
||||||
|
executable_path: &str,
|
||||||
|
argv: Vec<CString>,
|
||||||
|
envp: Vec<CString>,
|
||||||
|
) -> Result<Arc<Self>> {
|
||||||
|
let process_builder = {
|
||||||
|
let pid = allocate_tid();
|
||||||
|
let parent = Weak::new();
|
||||||
|
let mut builder = ProcessBuilder::new(pid, executable_path, parent);
|
||||||
|
builder.argv(argv).envp(envp);
|
||||||
|
builder
|
||||||
|
};
|
||||||
|
|
||||||
|
let process = process_builder.build()?;
|
||||||
|
process_table::add_process(process.clone());
|
||||||
|
Ok(process)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// start to run current process
|
||||||
|
pub fn run(&self) {
|
||||||
|
let threads = self.threads.lock();
|
||||||
|
// when run the process, the process should has only one thread
|
||||||
|
debug_assert!(threads.len() == 1);
|
||||||
|
debug_assert!(self.is_runnable());
|
||||||
|
let thread = threads[0].clone();
|
||||||
|
// should not hold the lock when run thread
|
||||||
|
drop(threads);
|
||||||
|
thread.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
// *********** Basic structures ***********
|
||||||
|
|
||||||
|
pub fn pid(&self) -> Pid {
|
||||||
|
self.pid
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn threads(&self) -> &Mutex<Vec<Arc<Thread>>> {
|
||||||
|
&self.threads
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn executable_path(&self) -> String {
|
||||||
|
self.executable_path.read().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_executable_path(&self, executable_path: String) {
|
||||||
|
*self.executable_path.write() = executable_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resource_limits(&self) -> &Mutex<ResourceLimits> {
|
||||||
|
&self.resource_limits
|
||||||
|
}
|
||||||
|
|
||||||
|
// *********** Parent and child ***********
|
||||||
|
|
||||||
|
pub fn add_child(&self, child: Arc<Process>) {
|
||||||
|
let child_pid = child.pid();
|
||||||
|
self.children.lock().insert(child_pid, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_parent(&self, parent: Weak<Process>) {
|
||||||
|
*self.parent.lock() = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parent(&self) -> Option<Arc<Process>> {
|
||||||
|
self.parent.lock().upgrade()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn children(&self) -> &Mutex<BTreeMap<Pid, Arc<Process>>> {
|
||||||
|
&self.children
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn waiting_children(&self) -> &WaitQueue {
|
||||||
|
&self.waiting_children
|
||||||
|
}
|
||||||
|
|
||||||
|
// *********** Process group ***********
|
||||||
|
|
||||||
|
pub fn pgid(&self) -> Pgid {
|
||||||
|
if let Some(process_group) = self.process_group.lock().upgrade() {
|
||||||
|
process_group.pgid()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set process group for current process. If old process group exists,
|
||||||
|
/// remove current process from old process group.
|
||||||
|
pub fn set_process_group(&self, process_group: Weak<ProcessGroup>) {
|
||||||
|
if let Some(old_process_group) = self.process_group() {
|
||||||
|
old_process_group.remove_process(self.pid());
|
||||||
|
}
|
||||||
|
*self.process_group.lock() = process_group;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_group(&self) -> Option<Arc<ProcessGroup>> {
|
||||||
|
self.process_group.lock().upgrade()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************** Virtual Memory *************
|
||||||
|
|
||||||
|
pub fn vm(&self) -> &ProcessVm {
|
||||||
|
&self.process_vm
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root_vmar(&self) -> &Vmar<Full> {
|
||||||
|
self.process_vm.root_vmar()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn user_heap(&self) -> &UserHeap {
|
||||||
|
self.process_vm.user_heap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************** File system ****************
|
||||||
|
|
||||||
|
pub fn file_table(&self) -> &Arc<Mutex<FileTable>> {
|
||||||
|
&self.file_table
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fs(&self) -> &Arc<RwLock<FsResolver>> {
|
||||||
|
&self.fs
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn umask(&self) -> &Arc<RwLock<FileCreationMask>> {
|
||||||
|
&self.umask
|
||||||
|
}
|
||||||
|
|
||||||
|
// ****************** Signal ******************
|
||||||
|
|
||||||
|
pub fn sig_dispositions(&self) -> &Arc<Mutex<SigDispositions>> {
|
||||||
|
&self.sig_dispositions
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_pending_signal(&self) -> bool {
|
||||||
|
self.sig_queues.lock().is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueue_signal(&self, signal: Box<dyn Signal>) {
|
||||||
|
if !self.is_zombie() {
|
||||||
|
self.sig_queues.lock().enqueue(signal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeue_signal(&self, mask: &SigMask) -> Option<Box<dyn Signal>> {
|
||||||
|
self.sig_queues.lock().dequeue(mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******************* Status ********************
|
||||||
|
|
||||||
|
fn set_runnable(&self) {
|
||||||
|
self.status.lock().set_runnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_runnable(&self) -> bool {
|
||||||
|
self.status.lock().is_runnable()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_zombie(&self) -> bool {
|
||||||
|
self.status.lock().is_zombie()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_zombie(&self, term_status: TermStatus) {
|
||||||
|
*self.status.lock() = ProcessStatus::Zombie(term_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit_code(&self) -> Option<u32> {
|
||||||
|
match &*self.status.lock() {
|
||||||
|
ProcessStatus::Runnable | ProcessStatus::Uninit => None,
|
||||||
|
ProcessStatus::Zombie(term_status) => Some(term_status.as_u32()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current() -> Arc<Process> {
|
||||||
|
let current_thread = Thread::current();
|
||||||
|
if let Some(posix_thread) = current_thread.as_posix_thread() {
|
||||||
|
posix_thread.process()
|
||||||
|
} else {
|
||||||
|
panic!("[Internal error]The current thread does not belong to a process");
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
use super::{Pgid, Pid, Process};
|
use super::{Pgid, Pid};
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum ProcessFilter {
|
pub enum ProcessFilter {
|
||||||
@ -32,7 +33,7 @@ impl ProcessFilter {
|
|||||||
ProcessFilter::Any
|
ProcessFilter::Any
|
||||||
} else if wait_pid == 0 {
|
} else if wait_pid == 0 {
|
||||||
// wait for any child process with same process group ID
|
// wait for any child process with same process group ID
|
||||||
let pgid = Process::current().pgid();
|
let pgid = current!().pgid();
|
||||||
ProcessFilter::WithPgid(pgid)
|
ProcessFilter::WithPgid(pgid)
|
||||||
} else {
|
} else {
|
||||||
// pid > 0. wait for the child whose process ID is equal to the value of pid.
|
// pid > 0. wait for the child whose process ID is equal to the value of pid.
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
//! Definition of MMap flags, conforming to the linux mmap interface:
|
|
||||||
//! https://man7.org/linux/man-pages/man2/mmap.2.html
|
|
||||||
//!
|
|
||||||
//! The first 4 bits of the flag value represents the type of memory map,
|
|
||||||
//! while other bits are used as memory map flags.
|
|
||||||
//!
|
|
||||||
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
// The map type mask
|
|
||||||
const MAP_TYPE: u32 = 0xf;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug, TryFromInt)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum MMapType {
|
|
||||||
File = 0x0, // Invalid
|
|
||||||
Shared = 0x1,
|
|
||||||
Private = 0x2,
|
|
||||||
SharedValidate = 0x3,
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
pub struct MMapFlags : u32 {
|
|
||||||
const MAP_FIXED = 0x10;
|
|
||||||
const MAP_ANONYMOUS = 0x20;
|
|
||||||
const MAP_GROWSDOWN = 0x100;
|
|
||||||
const MAP_DENYWRITE = 0x800;
|
|
||||||
const MAP_EXECUTABLE = 0x1000;
|
|
||||||
const MAP_LOCKED = 0x2000;
|
|
||||||
const MAP_NORESERVE = 0x4000;
|
|
||||||
const MAP_POPULATE = 0x8000;
|
|
||||||
const MAP_NONBLOCK = 0x10000;
|
|
||||||
const MAP_STACK = 0x20000;
|
|
||||||
const MAP_HUGETLB = 0x40000;
|
|
||||||
const MAP_SYNC = 0x80000;
|
|
||||||
const MAP_FIXED_NOREPLACE = 0x100000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct MMapOptions {
|
|
||||||
typ: MMapType,
|
|
||||||
flags: MMapFlags,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<u32> for MMapOptions {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn try_from(value: u32) -> Result<Self> {
|
|
||||||
let typ_raw = (value & MAP_TYPE) as u8;
|
|
||||||
let typ = MMapType::try_from(typ_raw)?;
|
|
||||||
|
|
||||||
let flags_raw = value & !MAP_TYPE;
|
|
||||||
let Some(flags) = MMapFlags::from_bits(flags_raw) else {
|
|
||||||
return Err(Error::with_message(Errno::EINVAL, "unknown mmap flags"));
|
|
||||||
};
|
|
||||||
Ok(MMapOptions { typ, flags })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MMapOptions {
|
|
||||||
pub fn typ(&self) -> MMapType {
|
|
||||||
self.typ
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn flags(&self) -> MMapFlags {
|
|
||||||
self.flags
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,6 @@
|
|||||||
//! So we define a UserVm struct to store such infomation.
|
//! So we define a UserVm struct to store such infomation.
|
||||||
//! Briefly, it contains the exact usage of each segment of virtual spaces.
|
//! Briefly, it contains the exact usage of each segment of virtual spaces.
|
||||||
|
|
||||||
pub mod mmap_options;
|
|
||||||
pub mod user_heap;
|
pub mod user_heap;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
@ -46,6 +45,15 @@ pub struct ProcessVm {
|
|||||||
root_vmar: Vmar<Full>,
|
root_vmar: Vmar<Full>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Clone for ProcessVm {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
root_vmar: self.root_vmar.dup().unwrap(),
|
||||||
|
user_heap: self.user_heap.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ProcessVm {
|
impl ProcessVm {
|
||||||
pub fn alloc() -> Result<Self> {
|
pub fn alloc() -> Result<Self> {
|
||||||
let root_vmar = Vmar::<Full>::new_root()?;
|
let root_vmar = Vmar::<Full>::new_root()?;
|
||||||
|
@ -5,7 +5,7 @@ use crate::fs::fs_resolver::{FsPath, FsResolver, AT_FDCWD};
|
|||||||
use crate::fs::utils::Dentry;
|
use crate::fs::utils::Dentry;
|
||||||
use crate::process::process_vm::ProcessVm;
|
use crate::process::process_vm::ProcessVm;
|
||||||
use crate::process::program_loader::elf::init_stack::{init_aux_vec, InitStack};
|
use crate::process::program_loader::elf::init_stack::{init_aux_vec, InitStack};
|
||||||
use crate::process::TermStatus;
|
use crate::process::{do_exit_group, TermStatus};
|
||||||
use crate::vm::perms::VmPerms;
|
use crate::vm::perms::VmPerms;
|
||||||
use crate::vm::vmo::{VmoOptions, VmoRightsOp};
|
use crate::vm::vmo::{VmoOptions, VmoRightsOp};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -50,9 +50,8 @@ pub fn load_elf_to_vm(
|
|||||||
|
|
||||||
// FIXME: if `current` macro is used when creating the init process,
|
// FIXME: if `current` macro is used when creating the init process,
|
||||||
// the macro will panic. This corner case should be handled later.
|
// the macro will panic. This corner case should be handled later.
|
||||||
let current = current!();
|
|
||||||
// FIXME: how to set the correct exit status?
|
// FIXME: how to set the correct exit status?
|
||||||
current.exit_group(TermStatus::Exited(1));
|
do_exit_group(TermStatus::Exited(1));
|
||||||
Task::current().exit();
|
Task::current().exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@ use self::c_types::siginfo_t;
|
|||||||
use self::sig_mask::SigMask;
|
use self::sig_mask::SigMask;
|
||||||
use self::sig_num::SigNum;
|
use self::sig_num::SigNum;
|
||||||
use crate::current_thread;
|
use crate::current_thread;
|
||||||
use crate::process::posix_thread::posix_thread_ext::PosixThreadExt;
|
use crate::process::posix_thread::PosixThreadExt;
|
||||||
use crate::process::signal::c_types::ucontext_t;
|
use crate::process::signal::c_types::ucontext_t;
|
||||||
use crate::process::signal::sig_action::SigActionFlags;
|
use crate::process::signal::sig_action::SigActionFlags;
|
||||||
use crate::process::TermStatus;
|
use crate::process::{do_exit_group, TermStatus};
|
||||||
use crate::util::{write_bytes_to_user, write_val_to_user};
|
use crate::util::{write_bytes_to_user, write_val_to_user};
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
@ -33,13 +33,11 @@ pub fn handle_pending_signal(context: &mut UserContext) -> Result<()> {
|
|||||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||||
let pid = current.pid();
|
let pid = current.pid();
|
||||||
let sig_mask = *posix_thread.sig_mask().lock();
|
let sig_mask = *posix_thread.sig_mask().lock();
|
||||||
let mut thread_sig_queues = posix_thread.sig_queues().lock();
|
|
||||||
let mut proc_sig_queues = current.sig_queues().lock();
|
|
||||||
// We first deal with signal in current thread, then signal in current process.
|
// We first deal with signal in current thread, then signal in current process.
|
||||||
let signal = if let Some(signal) = thread_sig_queues.dequeue(&sig_mask) {
|
let signal = if let Some(signal) = posix_thread.dequeue_signal(&sig_mask) {
|
||||||
Some(signal)
|
Some(signal)
|
||||||
} else {
|
} else {
|
||||||
proc_sig_queues.dequeue(&sig_mask)
|
current.dequeue_signal(&sig_mask)
|
||||||
};
|
};
|
||||||
if let Some(signal) = signal {
|
if let Some(signal) = signal {
|
||||||
let sig_num = signal.num();
|
let sig_num = signal.num();
|
||||||
@ -71,10 +69,10 @@ pub fn handle_pending_signal(context: &mut UserContext) -> Result<()> {
|
|||||||
SigDefaultAction::Core | SigDefaultAction::Term => {
|
SigDefaultAction::Core | SigDefaultAction::Term => {
|
||||||
warn!(
|
warn!(
|
||||||
"{:?}: terminating on signal {}",
|
"{:?}: terminating on signal {}",
|
||||||
&*current.executable_path().read(),
|
current.executable_path(),
|
||||||
sig_num.sig_name()
|
sig_num.sig_name()
|
||||||
);
|
);
|
||||||
current.exit_group(TermStatus::Killed(sig_num));
|
do_exit_group(TermStatus::Killed(sig_num));
|
||||||
// We should exit current here, since we cannot restore a valid status from trap now.
|
// We should exit current here, since we cannot restore a valid status from trap now.
|
||||||
Task::current().exit();
|
Task::current().exit();
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ impl SigQueues {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.count == 0
|
self.count == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ impl SigQueues {
|
|||||||
|
|
||||||
pub fn dequeue(&mut self, blocked: &SigMask) -> Option<Box<dyn Signal>> {
|
pub fn dequeue(&mut self, blocked: &SigMask) -> Option<Box<dyn Signal>> {
|
||||||
// Fast path for the common case of no pending signals
|
// Fast path for the common case of no pending signals
|
||||||
if self.empty() {
|
if self.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ use super::TermStatus;
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum ProcessStatus {
|
pub enum ProcessStatus {
|
||||||
|
// Not ready to run
|
||||||
|
Uninit,
|
||||||
/// Can be scheduled to run
|
/// Can be scheduled to run
|
||||||
Runnable,
|
Runnable,
|
||||||
/// Exit while not reaped by parent
|
/// Exit while not reaped by parent
|
||||||
@ -18,4 +20,12 @@ impl ProcessStatus {
|
|||||||
pub fn is_zombie(&self) -> bool {
|
pub fn is_zombie(&self) -> bool {
|
||||||
matches!(self, ProcessStatus::Zombie(_))
|
matches!(self, ProcessStatus::Zombie(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_runnable(&mut self) {
|
||||||
|
*self = ProcessStatus::Runnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_runnable(&self) -> bool {
|
||||||
|
*self == ProcessStatus::Runnable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::prelude::*;
|
use crate::{prelude::*, process::process_table, thread::thread_table};
|
||||||
|
|
||||||
use super::{process_filter::ProcessFilter, ExitCode, Pid};
|
use super::{process_filter::ProcessFilter, ExitCode, Pid, Process};
|
||||||
|
|
||||||
// The definition of WaitOptions is from Occlum
|
// The definition of WaitOptions is from Occlum
|
||||||
bitflags! {
|
bitflags! {
|
||||||
@ -45,9 +45,7 @@ pub fn wait_child_exit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return immediately if we find a zombie child
|
// return immediately if we find a zombie child
|
||||||
let zombie_child = unwaited_children
|
let zombie_child = unwaited_children.iter().find(|child| child.is_zombie());
|
||||||
.iter()
|
|
||||||
.find(|child| child.status().lock().is_zombie());
|
|
||||||
|
|
||||||
if let Some(zombie_child) = zombie_child {
|
if let Some(zombie_child) = zombie_child {
|
||||||
let zombie_pid = zombie_child.pid();
|
let zombie_pid = zombie_child.pid();
|
||||||
@ -56,7 +54,7 @@ pub fn wait_child_exit(
|
|||||||
// does not reap child, directly return
|
// does not reap child, directly return
|
||||||
return Some(Ok((zombie_pid, exit_code)));
|
return Some(Ok((zombie_pid, exit_code)));
|
||||||
} else {
|
} else {
|
||||||
let exit_code = current.reap_zombie_child(zombie_pid);
|
let exit_code = reap_zombie_child(¤t, zombie_pid);
|
||||||
return Some(Ok((zombie_pid, exit_code)));
|
return Some(Ok((zombie_pid, exit_code)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,3 +69,18 @@ pub fn wait_child_exit(
|
|||||||
|
|
||||||
Ok((pid, exit_code as _))
|
Ok((pid, exit_code as _))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Free zombie child with pid, returns the exit code of child process.
|
||||||
|
fn reap_zombie_child(process: &Process, pid: Pid) -> u32 {
|
||||||
|
let child_process = process.children().lock().remove(&pid).unwrap();
|
||||||
|
assert!(child_process.is_zombie());
|
||||||
|
child_process.root_vmar().destroy_all().unwrap();
|
||||||
|
for thread in &*child_process.threads().lock() {
|
||||||
|
thread_table::remove_thread(thread.tid());
|
||||||
|
}
|
||||||
|
process_table::remove_process(child_process.pid());
|
||||||
|
if let Some(process_group) = child_process.process_group() {
|
||||||
|
process_group.remove_process(child_process.pid());
|
||||||
|
}
|
||||||
|
child_process.exit_code().unwrap()
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use jinux_frame::cpu::UserContext;
|
use jinux_frame::cpu::UserContext;
|
||||||
|
|
||||||
use crate::log_syscall_entry;
|
use crate::log_syscall_entry;
|
||||||
use crate::process::clone::{clone_child, CloneArgs, CloneFlags};
|
use crate::process::{clone_child, CloneArgs, CloneFlags};
|
||||||
use crate::{prelude::*, syscall::SYS_CLONE};
|
use crate::{prelude::*, syscall::SYS_CLONE};
|
||||||
|
|
||||||
use super::SyscallReturn;
|
use super::SyscallReturn;
|
||||||
|
@ -6,9 +6,8 @@ use crate::fs::fs_resolver::{FsPath, AT_FDCWD};
|
|||||||
use crate::fs::utils::{Dentry, InodeType};
|
use crate::fs::utils::{Dentry, InodeType};
|
||||||
use crate::log_syscall_entry;
|
use crate::log_syscall_entry;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::process::posix_thread::name::ThreadName;
|
use crate::process::posix_thread::{PosixThreadExt, ThreadName};
|
||||||
use crate::process::posix_thread::posix_thread_ext::PosixThreadExt;
|
use crate::process::{check_executable_file, load_program_to_vm};
|
||||||
use crate::process::program_loader::{check_executable_file, load_program_to_vm};
|
|
||||||
use crate::syscall::{SYS_EXECVE, SYS_EXECVEAT};
|
use crate::syscall::{SYS_EXECVE, SYS_EXECVEAT};
|
||||||
use crate::util::{read_cstring_from_user, read_val_from_user};
|
use crate::util::{read_cstring_from_user, read_val_from_user};
|
||||||
|
|
||||||
@ -100,12 +99,12 @@ fn do_execve(
|
|||||||
debug!("load program to root vmar");
|
debug!("load program to root vmar");
|
||||||
let (new_executable_path, elf_load_info) = {
|
let (new_executable_path, elf_load_info) = {
|
||||||
let fs_resolver = &*current.fs().read();
|
let fs_resolver = &*current.fs().read();
|
||||||
let process_vm = current.process_vm();
|
let process_vm = current.vm();
|
||||||
load_program_to_vm(process_vm, elf_file, argv, envp, fs_resolver, 1)?
|
load_program_to_vm(process_vm, elf_file, argv, envp, fs_resolver, 1)?
|
||||||
};
|
};
|
||||||
debug!("load elf in execve succeeds");
|
debug!("load elf in execve succeeds");
|
||||||
// set executable path
|
// set executable path
|
||||||
*current.executable_path().write() = new_executable_path;
|
current.set_executable_path(new_executable_path);
|
||||||
// set signal disposition to default
|
// set signal disposition to default
|
||||||
current.sig_dispositions().lock().inherit();
|
current.sig_dispositions().lock().inherit();
|
||||||
// set cpu context to default
|
// set cpu context to default
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::process::posix_thread::posix_thread_ext::PosixThreadExt;
|
use crate::process::posix_thread::PosixThreadExt;
|
||||||
use crate::process::TermStatus;
|
use crate::process::TermStatus;
|
||||||
use crate::{log_syscall_entry, prelude::*};
|
use crate::{log_syscall_entry, prelude::*};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::process::TermStatus;
|
use crate::process::{do_exit_group, TermStatus};
|
||||||
use crate::{log_syscall_entry, prelude::*};
|
use crate::{log_syscall_entry, prelude::*};
|
||||||
|
|
||||||
use crate::syscall::{SyscallReturn, SYS_EXIT_GROUP};
|
use crate::syscall::{SyscallReturn, SYS_EXIT_GROUP};
|
||||||
@ -8,6 +8,6 @@ pub fn sys_exit_group(exit_code: u64) -> Result<SyscallReturn> {
|
|||||||
log_syscall_entry!(SYS_EXIT_GROUP);
|
log_syscall_entry!(SYS_EXIT_GROUP);
|
||||||
// Exit all thread in current process
|
// Exit all thread in current process
|
||||||
let term_status = TermStatus::Exited(exit_code as _);
|
let term_status = TermStatus::Exited(exit_code as _);
|
||||||
current!().exit_group(term_status);
|
do_exit_group(term_status);
|
||||||
Ok(SyscallReturn::Return(0))
|
Ok(SyscallReturn::Return(0))
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
log_syscall_entry,
|
log_syscall_entry,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::clone::{clone_child, CloneArgs},
|
process::{clone_child, CloneArgs},
|
||||||
};
|
};
|
||||||
use jinux_frame::cpu::UserContext;
|
use jinux_frame::cpu::UserContext;
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use crate::{log_syscall_entry, prelude::*};
|
|||||||
use crate::process::process_table;
|
use crate::process::process_table;
|
||||||
use crate::process::signal::signals::user::{UserSignal, UserSignalKind};
|
use crate::process::signal::signals::user::{UserSignal, UserSignalKind};
|
||||||
use crate::{
|
use crate::{
|
||||||
process::{process_filter::ProcessFilter, signal::sig_num::SigNum},
|
process::{signal::sig_num::SigNum, ProcessFilter},
|
||||||
syscall::SYS_KILL,
|
syscall::SYS_KILL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
//! This mod defines mmap flags and the handler to syscall mmap
|
//! This mod defines mmap flags and the handler to syscall mmap
|
||||||
|
|
||||||
use crate::fs::file_table::FileDescripter;
|
use crate::fs::file_table::FileDescripter;
|
||||||
use crate::process::process_vm::mmap_options::{MMapFlags, MMapOptions, MMapType};
|
|
||||||
use crate::vm::perms::VmPerms;
|
use crate::vm::perms::VmPerms;
|
||||||
use crate::vm::vmo::{VmoChildOptions, VmoOptions, VmoRightsOp};
|
use crate::vm::vmo::{VmoChildOptions, VmoOptions, VmoRightsOp};
|
||||||
use crate::{log_syscall_entry, prelude::*};
|
use crate::{log_syscall_entry, prelude::*};
|
||||||
@ -131,3 +130,70 @@ fn mmap_filebacked_vmo(
|
|||||||
trace!("map range = 0x{:x} - 0x{:x}", map_addr, map_addr + len);
|
trace!("map range = 0x{:x} - 0x{:x}", map_addr, map_addr + len);
|
||||||
Ok(map_addr)
|
Ok(map_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Definition of MMap flags, conforming to the linux mmap interface:
|
||||||
|
// https://man7.org/linux/man-pages/man2/mmap.2.html
|
||||||
|
//
|
||||||
|
// The first 4 bits of the flag value represents the type of memory map,
|
||||||
|
// while other bits are used as memory map flags.
|
||||||
|
|
||||||
|
// The map type mask
|
||||||
|
const MAP_TYPE: u32 = 0xf;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Debug, TryFromInt)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum MMapType {
|
||||||
|
File = 0x0, // Invalid
|
||||||
|
Shared = 0x1,
|
||||||
|
Private = 0x2,
|
||||||
|
SharedValidate = 0x3,
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct MMapFlags : u32 {
|
||||||
|
const MAP_FIXED = 0x10;
|
||||||
|
const MAP_ANONYMOUS = 0x20;
|
||||||
|
const MAP_GROWSDOWN = 0x100;
|
||||||
|
const MAP_DENYWRITE = 0x800;
|
||||||
|
const MAP_EXECUTABLE = 0x1000;
|
||||||
|
const MAP_LOCKED = 0x2000;
|
||||||
|
const MAP_NORESERVE = 0x4000;
|
||||||
|
const MAP_POPULATE = 0x8000;
|
||||||
|
const MAP_NONBLOCK = 0x10000;
|
||||||
|
const MAP_STACK = 0x20000;
|
||||||
|
const MAP_HUGETLB = 0x40000;
|
||||||
|
const MAP_SYNC = 0x80000;
|
||||||
|
const MAP_FIXED_NOREPLACE = 0x100000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MMapOptions {
|
||||||
|
typ: MMapType,
|
||||||
|
flags: MMapFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u32> for MMapOptions {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(value: u32) -> Result<Self> {
|
||||||
|
let typ_raw = (value & MAP_TYPE) as u8;
|
||||||
|
let typ = MMapType::try_from(typ_raw)?;
|
||||||
|
|
||||||
|
let flags_raw = value & !MAP_TYPE;
|
||||||
|
let Some(flags) = MMapFlags::from_bits(flags_raw) else {
|
||||||
|
return Err(Error::with_message(Errno::EINVAL, "unknown mmap flags"));
|
||||||
|
};
|
||||||
|
Ok(MMapOptions { typ, flags })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MMapOptions {
|
||||||
|
pub fn typ(&self) -> MMapType {
|
||||||
|
self.typ
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flags(&self) -> MMapFlags {
|
||||||
|
self.flags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{prelude::*, process::posix_thread::posix_thread_ext::PosixThreadExt, thread::Thread};
|
use crate::{prelude::*, process::posix_thread::PosixThreadExt, thread::Thread};
|
||||||
|
|
||||||
use super::SyscallReturn;
|
use super::SyscallReturn;
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ pub fn sys_pause() -> Result<SyscallReturn> {
|
|||||||
// check sig_queue of current thread and process,
|
// check sig_queue of current thread and process,
|
||||||
// if there's any pending signal, break loop
|
// if there's any pending signal, break loop
|
||||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||||
if !posix_thread.sig_queues().lock().empty() || !current!().sig_queues().lock().empty() {
|
if posix_thread.has_pending_signal() || current!().has_pending_signal() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// there's no pending signal, yield execution
|
// there's no pending signal, yield execution
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::log_syscall_entry;
|
use crate::log_syscall_entry;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::process::posix_thread::name::MAX_THREAD_NAME_LEN;
|
use crate::process::posix_thread::PosixThreadExt;
|
||||||
use crate::process::posix_thread::posix_thread_ext::PosixThreadExt;
|
use crate::process::posix_thread::MAX_THREAD_NAME_LEN;
|
||||||
use crate::util::read_cstring_from_user;
|
use crate::util::read_cstring_from_user;
|
||||||
use crate::util::write_bytes_to_user;
|
use crate::util::write_bytes_to_user;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::process::rlimit::ResourceType;
|
use crate::process::ResourceType;
|
||||||
use crate::util::{read_val_from_user, write_val_to_user};
|
use crate::util::{read_val_from_user, write_val_to_user};
|
||||||
use crate::{log_syscall_entry, prelude::*, process::Pid};
|
use crate::{log_syscall_entry, prelude::*, process::Pid};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use jinux_frame::vm::VmIo;
|
use jinux_frame::vm::VmIo;
|
||||||
|
|
||||||
use crate::process::posix_thread::posix_thread_ext::PosixThreadExt;
|
use crate::process::posix_thread::PosixThreadExt;
|
||||||
use crate::process::signal::constants::{SIGKILL, SIGSTOP};
|
use crate::process::signal::constants::{SIGKILL, SIGSTOP};
|
||||||
use crate::{
|
use crate::{
|
||||||
log_syscall_entry,
|
log_syscall_entry,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
log_syscall_entry,
|
log_syscall_entry,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::{posix_thread::posix_thread_ext::PosixThreadExt, signal::c_types::ucontext_t},
|
process::{posix_thread::PosixThreadExt, signal::c_types::ucontext_t},
|
||||||
util::read_val_from_user,
|
util::read_val_from_user,
|
||||||
};
|
};
|
||||||
use jinux_frame::cpu::UserContext;
|
use jinux_frame::cpu::UserContext;
|
||||||
|
@ -2,7 +2,7 @@ use super::{SyscallReturn, SYS_SET_ROBUST_LIST};
|
|||||||
use crate::{
|
use crate::{
|
||||||
log_syscall_entry,
|
log_syscall_entry,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::posix_thread::{posix_thread_ext::PosixThreadExt, robust_list::RobustListHead},
|
process::posix_thread::{PosixThreadExt, RobustListHead},
|
||||||
util::read_val_from_user,
|
util::read_val_from_user,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use crate::process::posix_thread::posix_thread_ext::PosixThreadExt;
|
|
||||||
use crate::{log_syscall_entry, prelude::*};
|
|
||||||
|
|
||||||
use super::SyscallReturn;
|
use super::SyscallReturn;
|
||||||
use super::SYS_SET_TID_ADDRESS;
|
use super::SYS_SET_TID_ADDRESS;
|
||||||
|
use crate::process::posix_thread::PosixThreadExt;
|
||||||
|
use crate::{log_syscall_entry, prelude::*};
|
||||||
|
|
||||||
pub fn sys_set_tid_address(tidptr: Vaddr) -> Result<SyscallReturn> {
|
pub fn sys_set_tid_address(tidptr: Vaddr) -> Result<SyscallReturn> {
|
||||||
log_syscall_entry!(SYS_SET_TID_ADDRESS);
|
log_syscall_entry!(SYS_SET_TID_ADDRESS);
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
log_syscall_entry,
|
log_syscall_entry,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::{
|
process::{process_table, Pgid, Pid, ProcessGroup},
|
||||||
process_group::ProcessGroup,
|
|
||||||
process_table::{self, pid_to_process},
|
|
||||||
Pgid, Pid,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{SyscallReturn, SYS_SETPGID};
|
use super::{SyscallReturn, SYS_SETPGID};
|
||||||
@ -33,8 +29,8 @@ pub fn sys_setpgid(pid: Pid, pgid: Pgid) -> Result<SyscallReturn> {
|
|||||||
return_errno_with_message!(Errno::EPERM, "process group must exist");
|
return_errno_with_message!(Errno::EPERM, "process group must exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
let process =
|
let process = process_table::pid_to_process(pid)
|
||||||
pid_to_process(pid).ok_or(Error::with_message(Errno::ESRCH, "process does not exist"))?;
|
.ok_or(Error::with_message(Errno::ESRCH, "process does not exist"))?;
|
||||||
|
|
||||||
// if the process already belongs to the process group
|
// if the process already belongs to the process group
|
||||||
if process.pgid() == pgid {
|
if process.pgid() == pgid {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::process::posix_thread::posix_thread_ext::PosixThreadExt;
|
use crate::process::posix_thread::PosixThreadExt;
|
||||||
use crate::thread::{thread_table, Tid};
|
use crate::thread::{thread_table, Tid};
|
||||||
use crate::{log_syscall_entry, prelude::*};
|
use crate::{log_syscall_entry, prelude::*};
|
||||||
|
|
||||||
@ -39,7 +39,6 @@ pub fn sys_tgkill(tgid: Pid, tid: Tid, sig_num: u8) -> Result<SyscallReturn> {
|
|||||||
src_uid,
|
src_uid,
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
let mut sig_queue = posix_thread.sig_queues().lock();
|
posix_thread.enqueue_signal(signal);
|
||||||
sig_queue.enqueue(signal);
|
|
||||||
Ok(SyscallReturn::Return(0))
|
Ok(SyscallReturn::Return(0))
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
log_syscall_entry,
|
log_syscall_entry,
|
||||||
process::{process_filter::ProcessFilter, wait::wait_child_exit},
|
process::{wait_child_exit, ProcessFilter},
|
||||||
syscall::SYS_WAIT4,
|
syscall::SYS_WAIT4,
|
||||||
util::write_val_to_user,
|
util::write_val_to_user,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::process::wait::WaitOptions;
|
use crate::process::WaitOptions;
|
||||||
|
|
||||||
use super::SyscallReturn;
|
use super::SyscallReturn;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::process::{process_filter::ProcessFilter, wait::wait_child_exit};
|
use crate::process::{wait_child_exit, ProcessFilter};
|
||||||
use crate::{log_syscall_entry, prelude::*};
|
use crate::{log_syscall_entry, prelude::*};
|
||||||
|
|
||||||
use crate::process::wait::WaitOptions;
|
use crate::process::WaitOptions;
|
||||||
|
|
||||||
use super::SyscallReturn;
|
use super::SyscallReturn;
|
||||||
use super::SYS_WAITID;
|
use super::SYS_WAITID;
|
||||||
|
@ -57,7 +57,7 @@ fn handle_page_fault(trap_info: &TrapInformation) {
|
|||||||
fn generate_fault_signal(trap_info: &TrapInformation) {
|
fn generate_fault_signal(trap_info: &TrapInformation) {
|
||||||
let current = current!();
|
let current = current!();
|
||||||
let signal = Box::new(FaultSignal::new(trap_info));
|
let signal = Box::new(FaultSignal::new(trap_info));
|
||||||
current.sig_queues().lock().enqueue(signal);
|
current.enqueue_signal(signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! log_trap_common {
|
macro_rules! log_trap_common {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use core::{
|
use core::{
|
||||||
any::Any,
|
any::Any,
|
||||||
sync::atomic::{AtomicI32, Ordering},
|
sync::atomic::{AtomicU32, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
use jinux_frame::task::Task;
|
use jinux_frame::task::Task;
|
||||||
@ -17,9 +17,9 @@ pub mod status;
|
|||||||
pub mod task;
|
pub mod task;
|
||||||
pub mod thread_table;
|
pub mod thread_table;
|
||||||
|
|
||||||
pub type Tid = i32;
|
pub type Tid = u32;
|
||||||
|
|
||||||
static TID_ALLOCATOR: AtomicI32 = AtomicI32::new(0);
|
static TID_ALLOCATOR: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|
||||||
/// A thread is a wrapper on top of task.
|
/// A thread is a wrapper on top of task.
|
||||||
pub struct Thread {
|
pub struct Thread {
|
||||||
|
Reference in New Issue
Block a user