Fix incorrent exit status

This commit is contained in:
Jianfeng Jiang
2023-09-01 11:40:22 +08:00
committed by Tate, Hongliang Tian
parent dbc1e79e56
commit 25c4f0f2bc
10 changed files with 79 additions and 37 deletions

View File

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

View File

@ -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<String>,
/// The threads
threads: Mutex<Vec<Arc<Thread>>>,
/// The exit code
exit_code: AtomicI32,
/// Process status
status: Mutex<ProcessStatus>,
/// 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<BTreeMap<Pid, Arc<Process>>> {
&self.children
}
pub fn exit_code(&self) -> &AtomicI32 {
&self.exit_code
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -75,6 +75,10 @@ impl Thread {
}
}
pub fn is_exited(&self) -> bool {
self.status.lock().is_exited()
}
pub fn status(&self) -> &Mutex<ThreadStatus> {
&self.status
}