Skip to content

Commit

Permalink
Don't abort on child process suspended
Browse files Browse the repository at this point in the history
The shell should ignore WaitStatus::{Stopped, Continued} because it does
not (yet) support job control.
  • Loading branch information
magicant committed May 8, 2022
1 parent bfb8358 commit 856a30d
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 21 deletions.
37 changes: 23 additions & 14 deletions yash-env/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ use self::io::Fd;
use self::job::JobSet;
use self::job::Pid;
use self::job::WaitStatus;
use self::job::WaitStatusEx;
use self::option::OptionSet;
use self::semantics::ExitStatus;
use self::stack::Stack;
Expand Down Expand Up @@ -320,20 +321,9 @@ impl Env {
// TODO Use a virtual subshell when possible
let child_pid = self.start_subshell(f).await?;

loop {
use nix::sys::wait::WaitStatus::*;
match self.wait_for_subshell(child_pid).await? {
Exited(pid, exit_status) => {
assert_eq!(pid, child_pid);
break Ok(ExitStatus(exit_status));
}
Signaled(pid, signal, _core_dumped) => {
assert_eq!(pid, child_pid);
break Ok(ExitStatus::from(signal));
}
_ => (),
}
}
let (awaited_pid, exit_status) = self.wait_for_subshell_to_finish(child_pid).await?;
assert_eq!(awaited_pid, child_pid);
Ok(exit_status)
}

/// Waits for a subshell to terminate, suspend, or resume.
Expand Down Expand Up @@ -370,6 +360,25 @@ impl Env {
}
}

/// Wait for a subshell to terminate.
///
/// This function is similar to
/// [`wait_for_subshell`](Self::wait_for_subshell), but returns only when
/// the target is finished (either exited or killed by a signal).
///
/// Returns the process ID of the awaited process and its exit status.
pub async fn wait_for_subshell_to_finish(
&mut self,
target: Pid,
) -> nix::Result<(Pid, ExitStatus)> {
loop {
let wait_status = self.wait_for_subshell(target).await?;
if wait_status.is_finished() {
return Ok((wait_status.pid().unwrap(), wait_status.try_into().unwrap()));
}
}
}

/// Applies all job status updates to jobs in `self.jobs`.
///
/// This function calls [`self.system.wait`](System::wait) repeatedly until
Expand Down
13 changes: 6 additions & 7 deletions yash-semantics/src/command_impl/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,12 @@ async fn execute_multi_command_pipeline(env: &mut Env, commands: &[Rc<syntax::Co

// Await the last command
for pid in pids {
use yash_env::job::WaitStatus::*;
env.exit_status = match env.wait_for_subshell(pid).await {
Ok(Exited(_pid, exit_status)) => ExitStatus(exit_status),
// TODO Report signal if interactive
Ok(Signaled(_pid, signal, _core_dumped)) => ExitStatus::from(signal),
_ => todo!(),
}
// TODO Report if the child was signaled and the shell is interactive
env.exit_status = env
.wait_for_subshell_to_finish(pid)
.await
.expect("cannot receive exit status of child process")
.1;
}
Continue(())
}
Expand Down

0 comments on commit 856a30d

Please sign in to comment.