From 57a4bdd563db4bc12ad1aa3aaa6d0000cc486fc7 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 4 Feb 2019 14:39:33 +0200 Subject: Use QMP (QEMU Machine Protocol) events as machine log file --- bbot/agent/machine.cxx | 110 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 101 insertions(+), 9 deletions(-) (limited to 'bbot/agent/machine.cxx') diff --git a/bbot/agent/machine.cxx b/bbot/agent/machine.cxx index fdc11c0..2566ca4 100644 --- a/bbot/agent/machine.cxx +++ b/bbot/agent/machine.cxx @@ -189,6 +189,9 @@ namespace bbot using machine::wait; virtual void + cleanup () override; + + virtual void print_info (diag_record&) override; private: @@ -202,6 +205,8 @@ namespace bbot tap net; // Tap network interface. string vnc; // QEMU VNC TCP addr:port. path monitor; // QEMU monitor UNIX socket. + path log; // QEMU log (QMP read end). + auto_fd qmp; // QMP write end. process proc; }; @@ -229,6 +234,18 @@ namespace bbot if (sizeof (sockaddr_un::sun_path) <= monitor.size ()) throw invalid_argument ("monitor unix socket path too long"); + // Machine name. + // + // While we currently can only have one running machine per toolchain, add + // the instance number for debuggability. + // + string name (mm.name + '-' + tc_name + '-' + to_string (inst)); + + // Machine log. Note that it is only removed with an explicit cleanup() + // call. + // + log = path ("/tmp/" + path::traits::temp_name (name) + ".log"); + // Map logical CPUs to sockets/cores/threads keeping the number of and // cores even. Failed that, QEMU just makes it a machine with that number // of sockets and some operating systems (like Windows) can only do two. @@ -315,20 +332,45 @@ namespace bbot //"-device", "scsi-hd,drive=disk0" } - // Start the VM. + // Setup QMP (QEMU Machine Protocol) monitor to act as a log. // - // Notes: + // Note that we still have to tell it our "capabilities" so while it will + // write to a log file, we need a pipe it will read from. // - // 1. echo system_powerdown | socat - UNIX-CONNECT:.../monitor + fdpipe qmp_in; + try + { + qmp_in = fdopen_pipe (); + } + catch (const io_error& e) + { + fail << "unable to create QMP input pipe: " << e; + } + + auto_fd qmp_out; + try + { + qmp_out = fdopen (log, (fdopen_mode::out | + fdopen_mode::create | + fdopen_mode::exclusive)); + } + catch (const io_error& e) + { + fail << "unable to create QMP output file: " << e; + } + + // Start the VM. // const char* env[] = {"QEMU_AUDIO_DRV=none", // Disable audio output. nullptr}; proc = run_io_start ( trace, - fdnull (), - 2, - 2, + qmp_in, + 2, // 1>&2 (QMP goes to stdout) + qmp_out, process_env (kvm, md, env), // Run from the machine's directory. + "-name", name + ",debug-threads=on", + "-S", // Start suspended. "-boot", "c", // Boot from disk. "-no-reboot", // Exit on VM reboot. "-m", to_string (ram / 1024) + "M", @@ -337,15 +379,64 @@ namespace bbot ",sockets=" + to_string (sockets) + ",cores=" + to_string (cores) + ",threads=" + to_string (threads)), - // + // RTC settings. // "-rtc", "clock=vm,driftfix=slew", "-no-hpet", "-global", "kvm-pit.lost_tick_policy=discard", + os, + + // VNC. + // "-vnc", "127.0.0.1:" + to_string (offset), // 5900 + offset - "-monitor", "unix:" + monitor.string () + ",server,nowait"); + + // QMP. + // + "-chardev", "stdio,id=qmp", + "-mon", "chardev=qmp,mode=control,pretty=on", + + // Monitor. + // + "-chardev", "socket,id=mon,path=" + monitor.string () + ",server,nowait", + "-mon", "chardev=mon,mode=readline"); + + qmp_out.close (); + qmp_in.in.close (); + qmp = move (qmp_in.out); + + // Wait for the QMP greeting. One day we will find a better way. + // + sleep (1); + + try + { + ofdstream os (move (qmp)); + os << "{ \"execute\": \"qmp_capabilities\" }" << endl; + qmp = os.release (); + } + catch (const io_error& e) + { + fail << "unable to initialize QMP: " << e; + } + + // Start execution. + // + try + { + monitor_command ("cont"); + } + catch (const system_error& e) + { + fail << "unable to communicate with qemu monitor: " << e; + } + } + + void kvm_machine:: + cleanup () + { + try_rmfile (log, true /* ignore_errors */); } // Connect to the QEMU monitor via the UNIX socket and send system_reset. @@ -434,6 +525,7 @@ namespace bbot print_info (diag_record& dr) { dr << info << "qemu pid: " << proc.id () + << info << "qemu log: " << log << info << "qemu vnc: " << vnc << info << "qemu monitor: unix:" << monitor; } @@ -453,7 +545,7 @@ namespace bbot { run_io_finish (trace, proc, kvm, fh); net.destroy (); //@@ Always fails hard. - try_rmfile (monitor, true); // QEMU doesn't seem to remove it. + try_rmfile (monitor, true /* ignore_errors */); // QEMU doesn't do it. } return t; -- cgit v1.1