Browse Source

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

xtask: watch for kernel panics on stderr
Tamir Duberstein 1 year ago
parent
commit
fbbf191bd3
2 changed files with 36 additions and 12 deletions
  1. 5 5
      aya-log-common/src/lib.rs
  2. 31 7
      xtask/src/run.rs

+ 5 - 5
aya-log-common/src/lib.rs

@@ -178,7 +178,7 @@ pub trait WriteToBuf {
 macro_rules! impl_write_to_buf {
     ($type:ident, $arg_type:expr) => {
         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.
             #[inline(never)]
             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 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.
     #[inline(never)]
     fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
@@ -213,7 +213,7 @@ impl WriteToBuf for [u8; 16] {
 }
 
 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.
     #[inline(never)]
     fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
@@ -223,7 +223,7 @@ impl WriteToBuf for [u16; 8] {
 }
 
 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.
     #[inline(never)]
     fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
@@ -252,7 +252,7 @@ impl WriteToBuf for &str {
 }
 
 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.
     #[inline(never)]
     fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {

+ 31 - 7
xtask/src/run.rs

@@ -6,6 +6,7 @@ use std::{
     io::{BufRead as _, BufReader, ErrorKind, Write as _},
     path::{Path, PathBuf},
     process::{Child, Command, Output, Stdio},
+    thread,
 };
 
 use anyhow::{anyhow, bail, Context as _, Result};
@@ -450,17 +451,42 @@ pub fn run(opts: Options) -> Result<()> {
                     };
                 }
                 let mut qemu_child = qemu
+                    .stdin(Stdio::piped())
                     .stdout(Stdio::piped())
+                    .stderr(Stdio::piped())
                     .spawn()
                     .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 = 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;
                 for line in stdout.lines() {
-                    let line =
-                        line.with_context(|| format!("failed to read line from {qemu:?}"))?;
+                    let line = line.context("failed to read line from stdout")?;
                     println!("{}", line);
                     // The init program will print "init: success" or "init: failure" to indicate
                     // 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 {
                             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:?}")
                 }
 
+                stderr.join().unwrap()?;
+
                 let outcome = outcome.ok_or(anyhow!("init did not exit"))?;
                 match outcome {
                     Ok(()) => {}