diff --git a/services/libs/jinux-std/src/lib.rs b/services/libs/jinux-std/src/lib.rs index 4b91b31f6..65114b7c0 100644 --- a/services/libs/jinux-std/src/lib.rs +++ b/services/libs/jinux-std/src/lib.rs @@ -22,10 +22,8 @@ use crate::{ prelude::*, - process::status::ProcessStatus, thread::{kernel_thread::KernelThreadExt, Thread}, }; -use core::sync::atomic::Ordering; use jinux_frame::{boot, exit_qemu, QemuExitCode}; use process::Process; @@ -87,14 +85,14 @@ fn init_thread() { .expect("Run init process failed."); // Wait till initproc become zombie. - while *initproc.status().lock() != ProcessStatus::Zombie { + while !initproc.status().lock().is_zombie() { // We don't have preemptive scheduler now. // The long running init thread should yield its own execution to allow other tasks to go on. Thread::yield_now(); } // TODO: exit via qemu isa debug device should not be the only way. - let exit_code = if initproc.exit_code().load(Ordering::Relaxed) == 0 { + let exit_code = if initproc.exit_code().unwrap() == 0 { QemuExitCode::Success } else { QemuExitCode::Failed diff --git a/services/libs/jinux-std/src/process/mod.rs b/services/libs/jinux-std/src/process/mod.rs index e4f9263b9..cb333e638 100644 --- a/services/libs/jinux-std/src/process/mod.rs +++ b/services/libs/jinux-std/src/process/mod.rs @@ -1,5 +1,3 @@ -use core::sync::atomic::{AtomicI32, Ordering}; - use self::posix_thread::posix_thread_ext::PosixThreadExt; use self::process_group::ProcessGroup; use self::process_vm::user_heap::UserHeap; @@ -32,8 +30,11 @@ pub mod program_loader; pub mod rlimit; pub mod signal; pub mod status; +mod term_status; pub mod wait; +pub use term_status::TermStatus; + pub type Pid = i32; pub type Pgid = i32; pub type ExitCode = i32; @@ -54,8 +55,6 @@ pub struct Process { executable_path: RwLock, /// The threads threads: Mutex>>, - /// The exit code - exit_code: AtomicI32, /// Process status status: Mutex, /// Parent process @@ -113,7 +112,6 @@ impl Process { executable_path: RwLock::new(executable_path), process_vm, waiting_children, - exit_code: AtomicI32::new(0), status: Mutex::new(ProcessStatus::Runnable), parent: Mutex::new(parent), children: Mutex::new(children), @@ -258,12 +256,26 @@ impl 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, exit_code: i32) { + pub fn exit_group(&self, term_status: TermStatus) { debug!("exit group was called"); - self.status.lock().set_zombie(); - self.exit_code.store(exit_code, Ordering::Relaxed); - for thread in &*self.threads.lock() { + 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(); @@ -326,7 +338,7 @@ impl Process { /// free zombie child with pid, returns the exit code of child process. /// remove process from process group. - pub fn reap_zombie_child(&self, pid: Pid) -> i32 { + 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(); @@ -337,15 +349,18 @@ impl Process { if let Some(process_group) = child_process.process_group().lock().upgrade() { process_group.remove_process(child_process.pid); } - child_process.exit_code().load(Ordering::SeqCst) + child_process.exit_code().unwrap() } pub fn children(&self) -> &Mutex>> { &self.children } - pub fn exit_code(&self) -> &AtomicI32 { - &self.exit_code + pub fn exit_code(&self) -> Option { + match &*self.status.lock() { + ProcessStatus::Runnable => None, + ProcessStatus::Zombie(term_status) => Some(term_status.as_u32()), + } } /// whether the process has child process diff --git a/services/libs/jinux-std/src/process/posix_thread/mod.rs b/services/libs/jinux-std/src/process/posix_thread/mod.rs index c9d31d893..04254e484 100644 --- a/services/libs/jinux-std/src/process/posix_thread/mod.rs +++ b/services/libs/jinux-std/src/process/posix_thread/mod.rs @@ -1,6 +1,9 @@ use crate::{ prelude::*, - process::posix_thread::{futex::futex_wake, robust_list::wake_robust_futex}, + process::{ + posix_thread::{futex::futex_wake, robust_list::wake_robust_futex}, + TermStatus, + }, thread::{thread_table, Tid}, util::write_val_to_user, }; @@ -112,7 +115,7 @@ impl PosixThread { } /// Posix thread does not contains tid info. So we require tid as a parameter. - pub fn exit(&self, tid: Tid, exit_code: i32) -> Result<()> { + pub fn exit(&self, tid: Tid, term_status: TermStatus) -> Result<()> { let mut clear_ctid = self.clear_child_tid().lock(); // If clear_ctid !=0 ,do a futex wake and write zero to the clear_ctid addr. debug!("wake up ctid"); @@ -141,7 +144,7 @@ impl PosixThread { debug!("self is main thread or last thread"); debug!("main thread: {}", self.is_main_thread()); debug!("last thread: {}", self.is_last_thread()); - current!().exit_group(exit_code); + current!().exit_group(term_status); } debug!("perform futex wake"); futex_wake(Arc::as_ptr(&self.process()) as Vaddr, 1)?; diff --git a/services/libs/jinux-std/src/process/signal/mod.rs b/services/libs/jinux-std/src/process/signal/mod.rs index 8bcdf913b..136926ea8 100644 --- a/services/libs/jinux-std/src/process/signal/mod.rs +++ b/services/libs/jinux-std/src/process/signal/mod.rs @@ -19,6 +19,7 @@ use crate::current_thread; use crate::process::posix_thread::posix_thread_ext::PosixThreadExt; use crate::process::signal::c_types::ucontext_t; use crate::process::signal::sig_action::SigActionFlags; +use crate::process::TermStatus; use crate::util::{write_bytes_to_user, write_val_to_user}; use crate::{ prelude::*, @@ -75,8 +76,7 @@ pub fn handle_pending_signal(context: &mut UserContext) -> Result<()> { &*current.executable_path().read(), sig_num.sig_name() ); - // FIXME: How to set correct status if process is terminated - current.exit_group(1); + current.exit_group(TermStatus::Killed(sig_num)); // We should exit current here, since we cannot restore a valid status from trap now. Task::current().exit(); } diff --git a/services/libs/jinux-std/src/process/status.rs b/services/libs/jinux-std/src/process/status.rs index 0243499eb..c84e25913 100644 --- a/services/libs/jinux-std/src/process/status.rs +++ b/services/libs/jinux-std/src/process/status.rs @@ -1,19 +1,21 @@ //! The process status +use super::TermStatus; + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ProcessStatus { /// Can be scheduled to run Runnable, /// Exit while not reaped by parent - Zombie, + Zombie(TermStatus), } impl ProcessStatus { - pub fn set_zombie(&mut self) { - *self = ProcessStatus::Zombie; + pub fn set_zombie(&mut self, term_status: TermStatus) { + *self = ProcessStatus::Zombie(term_status); } pub fn is_zombie(&self) -> bool { - *self == ProcessStatus::Zombie + matches!(self, ProcessStatus::Zombie(_)) } } diff --git a/services/libs/jinux-std/src/process/term_status.rs b/services/libs/jinux-std/src/process/term_status.rs new file mode 100644 index 000000000..5e0e51261 --- /dev/null +++ b/services/libs/jinux-std/src/process/term_status.rs @@ -0,0 +1,17 @@ +use super::signal::sig_num::SigNum; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TermStatus { + Exited(u8), + Killed(SigNum), +} + +impl TermStatus { + /// Return as a 32-bit integer encoded as specified in wait(2) man page. + pub fn as_u32(&self) -> u32 { + match self { + TermStatus::Exited(status) => (*status as u32) << 8, + TermStatus::Killed(signum) => signum.as_u8() as u32, + } + } +} diff --git a/services/libs/jinux-std/src/process/wait.rs b/services/libs/jinux-std/src/process/wait.rs index d8c6b3235..d2c6f5cba 100644 --- a/services/libs/jinux-std/src/process/wait.rs +++ b/services/libs/jinux-std/src/process/wait.rs @@ -1,5 +1,3 @@ -use core::sync::atomic::Ordering; - use crate::prelude::*; use super::{process_filter::ProcessFilter, ExitCode, Pid}; @@ -53,7 +51,7 @@ pub fn wait_child_exit( if let Some(zombie_child) = zombie_child { let zombie_pid = zombie_child.pid(); - let exit_code = zombie_child.exit_code().load(Ordering::SeqCst); + let exit_code = zombie_child.exit_code().unwrap(); if wait_options.contains(WaitOptions::WNOWAIT) { // does not reap child, directly return return Some(Ok((zombie_pid, exit_code))); @@ -71,5 +69,5 @@ pub fn wait_child_exit( None })?; - Ok((pid, exit_code)) + Ok((pid, exit_code as _)) } diff --git a/services/libs/jinux-std/src/syscall/exit.rs b/services/libs/jinux-std/src/syscall/exit.rs index 1e1df1a93..2de623725 100644 --- a/services/libs/jinux-std/src/syscall/exit.rs +++ b/services/libs/jinux-std/src/syscall/exit.rs @@ -1,4 +1,5 @@ use crate::process::posix_thread::posix_thread_ext::PosixThreadExt; +use crate::process::TermStatus; use crate::{log_syscall_entry, prelude::*}; use crate::syscall::{SyscallReturn, SYS_EXIT}; @@ -6,14 +7,16 @@ use crate::syscall::{SyscallReturn, SYS_EXIT}; pub fn sys_exit(exit_code: i32) -> Result { log_syscall_entry!(SYS_EXIT); debug!("exid code = {}", exit_code); + let current_thread = current_thread!(); - let tid = current_thread.tid(); - let current = current!(); - let pid = current.pid(); - debug!("tid = {}, pid = {}", tid, pid); - let posix_thread = current_thread.as_posix_thread().unwrap(); current_thread.exit(); - posix_thread.exit(tid, exit_code)?; + + let tid = current_thread.tid(); + let pid = current!().pid(); + debug!("tid = {}, pid = {}", tid, pid); + + let posix_thread = current_thread.as_posix_thread().unwrap(); + posix_thread.exit(tid, TermStatus::Exited(exit_code as _))?; Ok(SyscallReturn::Return(0)) } diff --git a/services/libs/jinux-std/src/syscall/exit_group.rs b/services/libs/jinux-std/src/syscall/exit_group.rs index 0f961d2c2..f67ff12bb 100644 --- a/services/libs/jinux-std/src/syscall/exit_group.rs +++ b/services/libs/jinux-std/src/syscall/exit_group.rs @@ -1,3 +1,4 @@ +use crate::process::TermStatus; use crate::{log_syscall_entry, prelude::*}; use crate::syscall::{SyscallReturn, SYS_EXIT_GROUP}; @@ -6,6 +7,7 @@ use crate::syscall::{SyscallReturn, SYS_EXIT_GROUP}; pub fn sys_exit_group(exit_code: u64) -> Result { log_syscall_entry!(SYS_EXIT_GROUP); // Exit all thread in current process - current!().exit_group(exit_code as _); + let term_status = TermStatus::Exited(exit_code as _); + current!().exit_group(term_status); Ok(SyscallReturn::Return(0)) } diff --git a/services/libs/jinux-std/src/thread/mod.rs b/services/libs/jinux-std/src/thread/mod.rs index c60bd7e20..bda751824 100644 --- a/services/libs/jinux-std/src/thread/mod.rs +++ b/services/libs/jinux-std/src/thread/mod.rs @@ -75,6 +75,10 @@ impl Thread { } } + pub fn is_exited(&self) -> bool { + self.status.lock().is_exited() + } + pub fn status(&self) -> &Mutex { &self.status }