Skip to content

Commit

Permalink
Remove impl TryFrom<ProcessState> for ExitStatus
Browse files Browse the repository at this point in the history
The conversion from ProcessState to ExitStatus is now done by the
System trait as it depends on the system implementation. This commit
removes the TryFrom implementation and replaces it with a call to
System::exit_status_for_process_state.
  • Loading branch information
magicant committed May 19, 2024
1 parent 7dcbabb commit bbd4a46
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 70 deletions.
8 changes: 6 additions & 2 deletions yash-builtin/src/fg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ use yash_env::job::id::parse;
use yash_env::job::JobList;
use yash_env::job::Pid;
use yash_env::job::ProcessState;
use yash_env::semantics::ExitStatus;
use yash_env::semantics::Field;
use yash_env::system::Errno;
use yash_env::system::System as _;
Expand Down Expand Up @@ -189,7 +188,11 @@ pub async fn main(env: &mut Env, args: Vec<Field>) -> crate::Result {
};

match result {
Ok(state) => ExitStatus::try_from(state).unwrap().into(),
Ok(state) => env
.system
.exit_status_for_process_state(state)
.unwrap()
.into(),
Err(error) => report_simple_failure(env, &error.to_string()).await,
}
}
Expand All @@ -208,6 +211,7 @@ mod tests {
use yash_env::job::ProcessState;
use yash_env::option::Option::Monitor;
use yash_env::option::State::On;
use yash_env::semantics::ExitStatus;
use yash_env::subshell::JobControl;
use yash_env::subshell::Subshell;
use yash_env::system::r#virtual::Process;
Expand Down
80 changes: 40 additions & 40 deletions yash-builtin/src/wait/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,21 @@ use yash_env::job::JobList;
use yash_env::job::ProcessState;
use yash_env::option::State;
use yash_env::semantics::ExitStatus;
use yash_env::system::SystemEx as _;
use yash_env::Env;

/// Waits while the given job is running.
///
/// This function keeps calling [`wait_for_any_job_or_trap`] until the given
/// closure returns [`ControlFlow::Break`], whose value is returned from this
/// function.
/// closure returns [`ControlFlow::Break`], then returns the exit status
/// corresponding to the final state of the job.
pub async fn wait_while_running(
env: &mut Env,
job_status: &mut dyn FnMut(&mut JobList) -> ControlFlow<ExitStatus>,
job_status: &mut dyn FnMut(&mut JobList) -> ControlFlow<ProcessState>,
) -> Result<ExitStatus, Error> {
loop {
if let ControlFlow::Break(exit_status) = job_status(&mut env.jobs) {
return Ok(exit_status);
if let ControlFlow::Break(state) = job_status(&mut env.jobs) {
return Ok(env.system.exit_status_for_process_state(state).unwrap());
}
wait_for_any_job_or_trap(env).await?;
}
Expand All @@ -58,37 +59,30 @@ pub async fn wait_while_running(
/// The disowned job is removed from the job list.
///
/// If the job has finished (either exited or signaled), the closure removes the
/// job from the job list and returns [`ControlFlow::Break`] with the job's exit
/// status. If `job_control` is `On` and the job has been stopped, the closure
/// returns [`ControlFlow::Break`] with an exit status that indicates the signal
/// that stopped the job.
/// Otherwise, the closure returns [`ControlFlow::Continue`].
/// job from the job list and returns [`ControlFlow::Break`] with the job's
/// final state. The closure returns also if `job_control` is `On` and the job
/// has been stopped. Otherwise, the closure returns [`ControlFlow::Continue`].
pub fn job_status(
index: usize,
job_control: State,
) -> impl FnMut(&mut JobList) -> ControlFlow<ExitStatus> {
) -> impl FnMut(&mut JobList) -> ControlFlow<ProcessState> {
move |jobs| {
let Some(job) = jobs.get(index) else {
return ControlFlow::Break(ExitStatus::NOT_FOUND);
return ControlFlow::Break(ProcessState::Exited(ExitStatus::NOT_FOUND));
};

if !job.is_owned {
jobs.remove(index);
return ControlFlow::Break(ExitStatus::NOT_FOUND);
return ControlFlow::Break(ProcessState::Exited(ExitStatus::NOT_FOUND));
}

match job.state {
ProcessState::Exited(exit_status) => {
let state = job.state;
match state {
ProcessState::Exited(_) | ProcessState::Signaled { .. } => {
jobs.remove(index);
ControlFlow::Break(exit_status)
}
ProcessState::Signaled { signal, .. } => {
jobs.remove(index);
ControlFlow::Break(ExitStatus::from(signal))
}
ProcessState::Stopped(signal) if job_control.into() => {
ControlFlow::Break(ExitStatus::from(signal))
ControlFlow::Break(state)
}
ProcessState::Stopped(_) if job_control.into() => ControlFlow::Break(state),
_ => ControlFlow::Continue(()),
}
}
Expand All @@ -101,14 +95,14 @@ pub fn job_status(
/// status of 0. Otherwise, the closure returns [`ControlFlow::Continue`].
pub fn any_job_is_running(
job_control: State,
) -> impl FnMut(&mut JobList) -> ControlFlow<ExitStatus> {
) -> impl FnMut(&mut JobList) -> ControlFlow<ProcessState> {
move |jobs| {
let Some((max_index, _)) = jobs.iter().next_back() else {
return ControlFlow::Break(ExitStatus::SUCCESS);
return ControlFlow::Break(ProcessState::Exited(ExitStatus::SUCCESS));
};

if (0..=max_index).all(|index| job_status(index, job_control)(jobs).is_break()) {
ControlFlow::Break(ExitStatus::SUCCESS)
ControlFlow::Break(ProcessState::Exited(ExitStatus::SUCCESS))
} else {
ControlFlow::Continue(())
}
Expand All @@ -127,15 +121,15 @@ mod tests {
let mut jobs = JobList::new();
assert_eq!(
job_status(0, Off)(&mut jobs),
ControlFlow::Break(ExitStatus::NOT_FOUND),
ControlFlow::Break(ProcessState::Exited(ExitStatus::NOT_FOUND)),
);
assert_eq!(
job_status(1, Off)(&mut jobs),
ControlFlow::Break(ExitStatus::NOT_FOUND),
ControlFlow::Break(ProcessState::Exited(ExitStatus::NOT_FOUND)),
);
assert_eq!(
job_status(0, On)(&mut jobs),
ControlFlow::Break(ExitStatus::NOT_FOUND),
ControlFlow::Break(ProcessState::Exited(ExitStatus::NOT_FOUND)),
);
assert_eq!(jobs.len(), 0);
}
Expand All @@ -149,7 +143,7 @@ mod tests {

assert_eq!(
job_status(index, Off)(&mut jobs),
ControlFlow::Break(ExitStatus::SUCCESS),
ControlFlow::Break(ProcessState::Exited(ExitStatus::SUCCESS)),
);
assert_eq!(jobs.get(index), None);

Expand All @@ -159,7 +153,7 @@ mod tests {

assert_eq!(
job_status(index, On)(&mut jobs),
ControlFlow::Break(ExitStatus(42)),
ControlFlow::Break(ProcessState::Exited(ExitStatus(42))),
);
assert_eq!(jobs.get(index), None);
}
Expand All @@ -176,7 +170,10 @@ mod tests {

assert_eq!(
job_status(index, Off)(&mut jobs),
ControlFlow::Break(ExitStatus::from(Signal::SIGHUP)),
ControlFlow::Break(ProcessState::Signaled {
signal: Signal::SIGHUP,
core_dump: false
}),
);
assert_eq!(jobs.get(index), None);

Expand All @@ -189,7 +186,10 @@ mod tests {

assert_eq!(
job_status(index, On)(&mut jobs),
ControlFlow::Break(ExitStatus::from(Signal::SIGABRT)),
ControlFlow::Break(ProcessState::Signaled {
signal: Signal::SIGABRT,
core_dump: true,
}),
);
assert_eq!(jobs.get(index), None);
}
Expand Down Expand Up @@ -221,7 +221,7 @@ mod tests {

assert_eq!(
job_status(index, On)(&mut jobs),
ControlFlow::Break(ExitStatus::from(Signal::SIGTSTP)),
ControlFlow::Break(ProcessState::Stopped(Signal::SIGTSTP)),
);
assert_eq!(jobs[index].pid, Pid(123));

Expand All @@ -231,7 +231,7 @@ mod tests {

assert_eq!(
job_status(index, On)(&mut jobs),
ControlFlow::Break(ExitStatus::from(Signal::SIGSTOP)),
ControlFlow::Break(ProcessState::Stopped(Signal::SIGSTOP)),
);
assert_eq!(jobs[index].pid, Pid(456));
}
Expand Down Expand Up @@ -263,7 +263,7 @@ mod tests {

assert_eq!(
job_status(index, Off)(&mut jobs),
ControlFlow::Break(ExitStatus::NOT_FOUND),
ControlFlow::Break(ProcessState::Exited(ExitStatus::NOT_FOUND)),
);
assert_eq!(jobs.get(index), None);
}
Expand All @@ -273,11 +273,11 @@ mod tests {
let mut jobs = JobList::new();
assert_eq!(
any_job_is_running(Off)(&mut jobs),
ControlFlow::Break(ExitStatus::SUCCESS),
ControlFlow::Break(ProcessState::Exited(ExitStatus::SUCCESS)),
);
assert_eq!(
any_job_is_running(On)(&mut jobs),
ControlFlow::Break(ExitStatus::SUCCESS),
ControlFlow::Break(ProcessState::Exited(ExitStatus::SUCCESS)),
);
}

Expand All @@ -290,7 +290,7 @@ mod tests {

assert_eq!(
any_job_is_running(Off)(&mut jobs),
ControlFlow::Break(ExitStatus::SUCCESS),
ControlFlow::Break(ProcessState::Exited(ExitStatus::SUCCESS)),
);

let mut job = Job::new(Pid(456));
Expand All @@ -299,7 +299,7 @@ mod tests {

assert_eq!(
any_job_is_running(On)(&mut jobs),
ControlFlow::Break(ExitStatus::SUCCESS),
ControlFlow::Break(ProcessState::Exited(ExitStatus::SUCCESS)),
);
}

Expand Down
22 changes: 0 additions & 22 deletions yash-env/src/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,28 +141,6 @@ impl ProcessState {
}
}

/// Error value indicating that the process is running.
///
/// This error value may be returned by [`TryFrom<ProcessState>::try_from`].
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct RunningProcess;

/// Converts `ProcessState` to `ExitStatus`.
///
/// For the `Running` state, the conversion fails with [`RunningProcess`].
impl TryFrom<ProcessState> for ExitStatus {
type Error = RunningProcess;
fn try_from(state: ProcessState) -> Result<Self, RunningProcess> {
match state {
ProcessState::Exited(exit_status) => Ok(exit_status),
ProcessState::Signaled { signal, .. } | ProcessState::Stopped(signal) => {
Ok(ExitStatus::from(signal))
}
ProcessState::Running => Err(RunningProcess),
}
}
}

/// Set of one or more processes executing a pipeline
///
/// In the current implementation, a job contains the process ID of one child
Expand Down
3 changes: 2 additions & 1 deletion yash-env/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,8 @@ impl Env {
loop {
let (pid, state) = self.wait_for_subshell(target).await?;
if !state.is_alive() {
return Ok((pid, state.try_into().unwrap()));
let exit_status = self.system.exit_status_for_process_state(state).unwrap();
return Ok((pid, exit_status));
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion yash-semantics/src/command/compound_command/subshell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use yash_env::semantics::ExitStatus;
use yash_env::semantics::Result;
use yash_env::subshell::JobControl;
use yash_env::subshell::Subshell;
use yash_env::system::SystemEx as _;
use yash_env::Env;
use yash_syntax::source::Location;
use yash_syntax::syntax::List;
Expand All @@ -47,7 +48,7 @@ pub async fn execute(env: &mut Env, body: Rc<List>, location: &Location) -> Resu
env.jobs.add(job);
}

env.exit_status = state.try_into().unwrap();
env.exit_status = env.system.exit_status_for_process_state(state).unwrap();
env.apply_errexit()
}
Err(errno) => {
Expand Down
4 changes: 2 additions & 2 deletions yash-semantics/src/command/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use yash_env::subshell::JobControl;
use yash_env::subshell::Subshell;
use yash_env::system::Errno;
use yash_env::system::FdFlag;
use yash_env::system::SystemEx;
use yash_env::system::SystemEx as _;
use yash_env::Env;
use yash_env::System;
use yash_syntax::syntax;
Expand Down Expand Up @@ -152,7 +152,7 @@ async fn execute_job_controlled_pipeline(
env.jobs.add(job);
}

env.exit_status = state.try_into().unwrap();
env.exit_status = env.system.exit_status_for_process_state(state).unwrap();
Continue(())
}
Err(errno) => {
Expand Down
3 changes: 2 additions & 1 deletion yash-semantics/src/command/simple_command/absent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use yash_env::semantics::ExitStatus;
use yash_env::semantics::Result;
use yash_env::subshell::JobControl;
use yash_env::subshell::Subshell;
use yash_env::system::SystemEx as _;
use yash_env::Env;
use yash_syntax::syntax::Assign;
use yash_syntax::syntax::Redir;
Expand Down Expand Up @@ -81,7 +82,7 @@ pub async fn execute_absent_target(
env.jobs.add(job);
}

state.try_into().unwrap()
env.system.exit_status_for_process_state(state).unwrap()
}
Err(errno) => {
print_error(
Expand Down
3 changes: 2 additions & 1 deletion yash-semantics/src/command/simple_command/external.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use yash_env::semantics::Result;
use yash_env::subshell::JobControl;
use yash_env::subshell::Subshell;
use yash_env::system::Errno;
use yash_env::system::SystemEx as _;
use yash_env::variable::Context;
use yash_env::Env;
use yash_env::System;
Expand Down Expand Up @@ -120,7 +121,7 @@ pub async fn start_external_utility_in_subshell_and_wait(
env.jobs.add(job);
}

state.try_into().unwrap()
env.system.exit_status_for_process_state(state).unwrap()
}
Err(errno) => {
print_error(
Expand Down

0 comments on commit bbd4a46

Please sign in to comment.