Browse Source

Merge pull request #745 from aya-rs/even-more-aggro-kp-handling

xtask: watch for kernel panic in stdout too
Tamir Duberstein 1 năm trước cách đây
mục cha
commit
68bf8818ec
1 tập tin đã thay đổi với 41 bổ sung17 xóa
  1. 41 17
      xtask/src/run.rs

+ 41 - 17
xtask/src/run.rs

@@ -5,7 +5,8 @@ use std::{
     fs::{copy, create_dir_all, metadata, File},
     io::{BufRead as _, BufReader, ErrorKind, Write as _},
     path::{Path, PathBuf},
-    process::{Child, Command, Output, Stdio},
+    process::{Child, ChildStdin, Command, Output, Stdio},
+    sync::{Arc, Mutex},
     thread,
 };
 
@@ -392,7 +393,7 @@ pub fn run(opts: Options) -> Result<()> {
                     qemu.args(["-cpu", cpu]);
                 }
                 let console = OsString::from("ttyS0");
-                let kernel_args = std::iter::once(("console", &console))
+                let mut kernel_args = std::iter::once(("console", &console))
                     .chain(run_args.clone().map(|run_arg| ("init.arg", run_arg)))
                     .enumerate()
                     .fold(OsString::new(), |mut acc, (i, (k, v))| {
@@ -404,6 +405,12 @@ pub fn run(opts: Options) -> Result<()> {
                         acc.push(v);
                         acc
                     });
+                // We sometimes see kernel panics containing:
+                //
+                // [    0.064000] Kernel panic - not syncing: IO-APIC + timer doesn't work!  Boot with apic=debug and send a report.  Then try booting with the 'noapic' option.
+                //
+                // Heed the advice and boot with noapic. We don't know why this happens.
+                kernel_args.push(" noapic");
                 qemu.args(["-no-reboot", "-nographic", "-m", "512M", "-smp", "2"])
                     .arg("-append")
                     .arg(kernel_args)
@@ -462,32 +469,49 @@ pub fn run(opts: Options) -> Result<()> {
                     stderr,
                     ..
                 } = &mut qemu_child;
-                let mut stdin = stdin.take().unwrap();
+                let stdin = stdin.take().unwrap();
+                let stdin = Arc::new(Mutex::new(stdin));
                 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")?;
+                fn terminate_if_contains_kernel_panic(
+                    line: &str,
+                    stdin: &Arc<Mutex<ChildStdin>>,
+                ) -> anyhow::Result<()> {
+                    if line.contains("end Kernel panic") {
+                        println!("kernel panic detected; terminating QEMU");
+                        let mut stdin = stdin.lock().unwrap();
+                        stdin
+                            .write_all(&[0x01, b'x'])
+                            .context("failed to write to stdin")?;
+                        println!("waiting for QEMU to terminate");
+                    }
+                    Ok(())
+                }
+
+                let stderr = {
+                    let stdin = stdin.clone();
+                    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.
+                                terminate_if_contains_kernel_panic(&line, &stdin)?;
                             }
-                        }
-                        anyhow::Ok(())
-                    })
-                    .unwrap();
+                            anyhow::Ok(())
+                        })
+                        .unwrap()
+                };
 
                 let mut outcome = None;
                 for line in stdout.lines() {
                     let line = line.context("failed to read line from stdout")?;
                     println!("{}", line);
+                    // Try to get QEMU to exit on kernel panic; otherwise it might hang indefinitely.
+                    terminate_if_contains_kernel_panic(&line, &stdin)?;
                     // The init program will print "init: success" or "init: failure" to indicate
                     // the outcome of running the binaries it found in /bin.
                     if let Some(line) = line.strip_prefix("init: ") {