mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 17:03:23 +00:00
Fix incorrent exit status
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
dbc1e79e56
commit
25c4f0f2bc
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)?;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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(_))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
services/libs/jinux-std/src/process/term_status.rs
Normal file
17
services/libs/jinux-std/src/process/term_status.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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 _))
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user