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::{ use crate::{
prelude::*, prelude::*,
process::status::ProcessStatus,
thread::{kernel_thread::KernelThreadExt, Thread}, thread::{kernel_thread::KernelThreadExt, Thread},
}; };
use core::sync::atomic::Ordering;
use jinux_frame::{boot, exit_qemu, QemuExitCode}; use jinux_frame::{boot, exit_qemu, QemuExitCode};
use process::Process; use process::Process;
@ -87,14 +85,14 @@ 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() != ProcessStatus::Zombie { while !initproc.status().lock().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();
} }
// TODO: exit via qemu isa debug device should not be the only way. // 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 QemuExitCode::Success
} else { } else {
QemuExitCode::Failed QemuExitCode::Failed

View File

@ -1,5 +1,3 @@
use core::sync::atomic::{AtomicI32, Ordering};
use self::posix_thread::posix_thread_ext::PosixThreadExt; use self::posix_thread::posix_thread_ext::PosixThreadExt;
use self::process_group::ProcessGroup; use self::process_group::ProcessGroup;
use self::process_vm::user_heap::UserHeap; use self::process_vm::user_heap::UserHeap;
@ -32,8 +30,11 @@ pub mod program_loader;
pub mod rlimit; pub mod rlimit;
pub mod signal; pub mod signal;
pub mod status; pub mod status;
mod term_status;
pub mod wait; pub mod wait;
pub use term_status::TermStatus;
pub type Pid = i32; pub type Pid = i32;
pub type Pgid = i32; pub type Pgid = i32;
pub type ExitCode = i32; pub type ExitCode = i32;
@ -54,8 +55,6 @@ pub struct Process {
executable_path: RwLock<String>, executable_path: RwLock<String>,
/// The threads /// The threads
threads: Mutex<Vec<Arc<Thread>>>, threads: Mutex<Vec<Arc<Thread>>>,
/// The exit code
exit_code: AtomicI32,
/// Process status /// Process status
status: Mutex<ProcessStatus>, status: Mutex<ProcessStatus>,
/// Parent process /// Parent process
@ -113,7 +112,6 @@ impl Process {
executable_path: RwLock::new(executable_path), executable_path: RwLock::new(executable_path),
process_vm, process_vm,
waiting_children, waiting_children,
exit_code: AtomicI32::new(0),
status: Mutex::new(ProcessStatus::Runnable), status: Mutex::new(ProcessStatus::Runnable),
parent: Mutex::new(parent), parent: Mutex::new(parent),
children: Mutex::new(children), children: Mutex::new(children),
@ -258,12 +256,26 @@ impl Process {
/// Set the status of the process as Zombie and set exit code. /// Set the status of the process as Zombie and set exit code.
/// Move all children to init process. /// Move all children to init process.
/// Wake up the parent wait queue if parent is waiting for self. /// 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"); debug!("exit group was called");
self.status.lock().set_zombie(); if self.status.lock().is_zombie() {
self.exit_code.store(exit_code, Ordering::Relaxed); return;
for thread in &*self.threads.lock() { }
self.status.lock().set_zombie(term_status);
let threads = self.threads.lock().clone();
for thread in threads {
if thread.is_exited() {
continue;
}
thread.exit(); 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 // close all files then exit the process
let files = self.file_table().lock().close_all(); 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. /// free zombie child with pid, returns the exit code of child process.
/// remove process from process group. /// 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(); let child_process = self.children.lock().remove(&pid).unwrap();
assert!(child_process.status().lock().is_zombie()); assert!(child_process.status().lock().is_zombie());
child_process.root_vmar().destroy_all().unwrap(); child_process.root_vmar().destroy_all().unwrap();
@ -337,15 +349,18 @@ impl Process {
if let Some(process_group) = child_process.process_group().lock().upgrade() { if let Some(process_group) = child_process.process_group().lock().upgrade() {
process_group.remove_process(child_process.pid); 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>>> { pub fn children(&self) -> &Mutex<BTreeMap<Pid, Arc<Process>>> {
&self.children &self.children
} }
pub fn exit_code(&self) -> &AtomicI32 { pub fn exit_code(&self) -> Option<u32> {
&self.exit_code match &*self.status.lock() {
ProcessStatus::Runnable => None,
ProcessStatus::Zombie(term_status) => Some(term_status.as_u32()),
}
} }
/// whether the process has child process /// whether the process has child process

View File

@ -1,6 +1,9 @@
use crate::{ use crate::{
prelude::*, 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}, thread::{thread_table, Tid},
util::write_val_to_user, 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. /// 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(); 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. // If clear_ctid !=0 ,do a futex wake and write zero to the clear_ctid addr.
debug!("wake up ctid"); debug!("wake up ctid");
@ -141,7 +144,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(exit_code); current!().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)?;

View File

@ -19,6 +19,7 @@ use crate::current_thread;
use crate::process::posix_thread::posix_thread_ext::PosixThreadExt; use crate::process::posix_thread::posix_thread_ext::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::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::*,
@ -75,8 +76,7 @@ pub fn handle_pending_signal(context: &mut UserContext) -> Result<()> {
&*current.executable_path().read(), &*current.executable_path().read(),
sig_num.sig_name() sig_num.sig_name()
); );
// FIXME: How to set correct status if process is terminated current.exit_group(TermStatus::Killed(sig_num));
current.exit_group(1);
// 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();
} }

View File

@ -1,19 +1,21 @@
//! The process status //! The process status
use super::TermStatus;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProcessStatus { pub enum ProcessStatus {
/// Can be scheduled to run /// Can be scheduled to run
Runnable, Runnable,
/// Exit while not reaped by parent /// Exit while not reaped by parent
Zombie, Zombie(TermStatus),
} }
impl ProcessStatus { impl ProcessStatus {
pub fn set_zombie(&mut self) { pub fn set_zombie(&mut self, term_status: TermStatus) {
*self = ProcessStatus::Zombie; *self = ProcessStatus::Zombie(term_status);
} }
pub fn is_zombie(&self) -> bool { 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 crate::prelude::*;
use super::{process_filter::ProcessFilter, ExitCode, Pid}; use super::{process_filter::ProcessFilter, ExitCode, Pid};
@ -53,7 +51,7 @@ pub fn wait_child_exit(
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();
let exit_code = zombie_child.exit_code().load(Ordering::SeqCst); let exit_code = zombie_child.exit_code().unwrap();
if wait_options.contains(WaitOptions::WNOWAIT) { if wait_options.contains(WaitOptions::WNOWAIT) {
// 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)));
@ -71,5 +69,5 @@ pub fn wait_child_exit(
None 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::posix_thread::posix_thread_ext::PosixThreadExt;
use crate::process::TermStatus;
use crate::{log_syscall_entry, prelude::*}; use crate::{log_syscall_entry, prelude::*};
use crate::syscall::{SyscallReturn, SYS_EXIT}; 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> { pub fn sys_exit(exit_code: i32) -> Result<SyscallReturn> {
log_syscall_entry!(SYS_EXIT); log_syscall_entry!(SYS_EXIT);
debug!("exid code = {}", exit_code); debug!("exid code = {}", exit_code);
let current_thread = current_thread!(); 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(); 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)) Ok(SyscallReturn::Return(0))
} }

View File

@ -1,3 +1,4 @@
use crate::process::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};
@ -6,6 +7,7 @@ use crate::syscall::{SyscallReturn, SYS_EXIT_GROUP};
pub fn sys_exit_group(exit_code: u64) -> Result<SyscallReturn> { 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
current!().exit_group(exit_code as _); let term_status = TermStatus::Exited(exit_code as _);
current!().exit_group(term_status);
Ok(SyscallReturn::Return(0)) 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> { pub fn status(&self) -> &Mutex<ThreadStatus> {
&self.status &self.status
} }