Merge pull request #738 from aya-rs/kill-qemu-better

xtask: watch for kernel panics on stderr
reviewable/pr741/r1
Tamir Duberstein 1 year ago committed by GitHub
commit fbbf191bd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -178,7 +178,7 @@ pub trait WriteToBuf {
macro_rules! impl_write_to_buf { macro_rules! impl_write_to_buf {
($type:ident, $arg_type:expr) => { ($type:ident, $arg_type:expr) => {
impl WriteToBuf for $type { impl WriteToBuf for $type {
// This need not be inlined because the return value is Result<N, ()> where N is // This need not be inlined because the return value is Option<N> where N is
// mem::size_of<$type>, which is a compile-time constant. // mem::size_of<$type>, which is a compile-time constant.
#[inline(never)] #[inline(never)]
fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> { fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
@ -204,7 +204,7 @@ impl_write_to_buf!(f32, Argument::F32);
impl_write_to_buf!(f64, Argument::F64); impl_write_to_buf!(f64, Argument::F64);
impl WriteToBuf for [u8; 16] { impl WriteToBuf for [u8; 16] {
// This need not be inlined because the return value is Result<N, ()> where N is 16, which is a // This need not be inlined because the return value is Option<N> where N is 16, which is a
// compile-time constant. // compile-time constant.
#[inline(never)] #[inline(never)]
fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> { fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
@ -213,7 +213,7 @@ impl WriteToBuf for [u8; 16] {
} }
impl WriteToBuf for [u16; 8] { impl WriteToBuf for [u16; 8] {
// This need not be inlined because the return value is Result<N, ()> where N is 16, which is a // This need not be inlined because the return value is Option<N> where N is 16, which is a
// compile-time constant. // compile-time constant.
#[inline(never)] #[inline(never)]
fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> { fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
@ -223,7 +223,7 @@ impl WriteToBuf for [u16; 8] {
} }
impl WriteToBuf for [u8; 6] { impl WriteToBuf for [u8; 6] {
// This need not be inlined because the return value is Result<N, ()> where N is 6, which is a // This need not be inlined because the return value is Option<N> where N is 6, which is a
// compile-time constant. // compile-time constant.
#[inline(never)] #[inline(never)]
fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> { fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
@ -252,7 +252,7 @@ impl WriteToBuf for &str {
} }
impl WriteToBuf for DisplayHint { impl WriteToBuf for DisplayHint {
// This need not be inlined because the return value is Result<N, ()> where N is 1, which is a // This need not be inlined because the return value is Option<N> where N is 1, which is a
// compile-time constant. // compile-time constant.
#[inline(never)] #[inline(never)]
fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> { fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {

@ -6,6 +6,7 @@ use std::{
io::{BufRead as _, BufReader, ErrorKind, Write as _}, io::{BufRead as _, BufReader, ErrorKind, Write as _},
path::{Path, PathBuf}, path::{Path, PathBuf},
process::{Child, Command, Output, Stdio}, process::{Child, Command, Output, Stdio},
thread,
}; };
use anyhow::{anyhow, bail, Context as _, Result}; use anyhow::{anyhow, bail, Context as _, Result};
@ -450,17 +451,42 @@ pub fn run(opts: Options) -> Result<()> {
}; };
} }
let mut qemu_child = qemu let mut qemu_child = qemu
.stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn() .spawn()
.with_context(|| format!("failed to spawn {qemu:?}"))?; .with_context(|| format!("failed to spawn {qemu:?}"))?;
let Child { stdout, .. } = &mut qemu_child; let Child {
stdin,
stdout,
stderr,
..
} = &mut qemu_child;
let mut stdin = stdin.take().unwrap();
let stdout = stdout.take().unwrap(); let stdout = stdout.take().unwrap();
let stdout = BufReader::new(stdout); let stdout = BufReader::new(stdout);
let stderr = stderr.take().unwrap();
let stderr = BufReader::new(stderr);
let stderr = thread::Builder::new()
.spawn(move || {
for line in stderr.lines() {
let line = line.context("failed to read line from stderr")?;
eprintln!("{}", line);
// Try to get QEMU to exit on kernel panic; otherwise it might hang indefinitely.
if line.contains("end Kernel panic") {
stdin
.write_all(&[0x01, b'x'])
.context("failed to write to stdin")?;
}
}
anyhow::Ok(())
})
.unwrap();
let mut outcome = None; let mut outcome = None;
for line in stdout.lines() { for line in stdout.lines() {
let line = let line = line.context("failed to read line from stdout")?;
line.with_context(|| format!("failed to read line from {qemu:?}"))?;
println!("{}", line); println!("{}", line);
// The init program will print "init: success" or "init: failure" to indicate // The init program will print "init: success" or "init: failure" to indicate
// the outcome of running the binaries it found in /bin. // the outcome of running the binaries it found in /bin.
@ -473,10 +499,6 @@ pub fn run(opts: Options) -> Result<()> {
if let Some(previous) = previous { if let Some(previous) = previous {
bail!("multiple exit status: previous={previous:?}, current={line}"); bail!("multiple exit status: previous={previous:?}, current={line}");
} }
// Try to get QEMU to exit on kernel panic; otherwise it might hang indefinitely.
if line.contains("end Kernel panic") {
qemu_child.kill().context("failed to kill {qemu:?}")?;
}
} }
} }
@ -488,6 +510,8 @@ pub fn run(opts: Options) -> Result<()> {
bail!("{qemu:?} failed: {output:?}") bail!("{qemu:?} failed: {output:?}")
} }
stderr.join().unwrap()?;
let outcome = outcome.ok_or(anyhow!("init did not exit"))?; let outcome = outcome.ok_or(anyhow!("init did not exit"))?;
match outcome { match outcome {
Ok(()) => {} Ok(()) => {}

Loading…
Cancel
Save