* Don't use /hostfs to signal the test driver that a VM is up, but

write some magic string to ttyS0.  This removes the dependency on
  having a CIFS mount.
* Use a thread to process the stdout/stderr of each QEMU instance.
* Add a kernel command line parameter "stage1panic" to tell stage 1 to
  panic if an error occurs.  This is faster than waiting until
  connect() times out.

svn path=/nixos/trunk/; revision=19212
This commit is contained in:
Eelco Dolstra 2010-01-04 18:04:57 +00:00
parent 5730c27aed
commit 170331be30
3 changed files with 40 additions and 15 deletions

View File

@ -1,9 +1,12 @@
package Machine;
use strict;
use threads;
use Thread::Queue;
use Socket;
use IO::Handle;
use POSIX qw(dup2);
use FileHandle;
# Stuff our PID in the multicast address/port to prevent collissions
@ -26,6 +29,7 @@ sub new {
booted => 0,
pid => 0,
connected => 0,
connectedQueue => Thread::Queue->new(),
socket => undef,
stateDir => "$tmpDir/$name",
};
@ -62,14 +66,15 @@ sub start {
$self->log("starting vm");
my ($read, $write) = FileHandle::pipe;
my $pid = fork();
die if $pid == -1;
if ($pid == 0) {
my $name = $self->{name};
open LOG, "| sed --unbuffered 's|^|$name console: |'" or die;
dup2(fileno(LOG), fileno(STDOUT));
dup2(fileno(LOG), fileno(STDERR));
close $read;
dup2(fileno($write), fileno(STDOUT));
dup2(fileno($write), fileno(STDERR));
open NUL, "</dev/null" or die;
dup2(fileno(NUL), fileno(STDIN));
$ENV{TMPDIR} = $self->{stateDir};
@ -79,7 +84,22 @@ sub start {
exec $self->{script};
die;
}
close $write;
threads->create(\&processQemuOutput)->detach;
sub processQemuOutput {
$/ = "\r\n";
while (<$read>) {
chomp;
print STDERR $self->name, "# $_\n";
$self->{connectedQueue}->enqueue(1) if $_ eq "===UP===";
}
# If the child dies, wake up connect().
$self->{connectedQueue}->enqueue(1);
}
$self->log("vm running as pid $pid");
$self->{pid} = $pid;
$self->{booted} = 1;
@ -92,12 +112,9 @@ sub connect {
$self->start;
my $try = 0;
while (1) {
last if -e ($self->{stateDir} . "/running");
sleep 1;
die ("VM " . $self->{name} . " timed out") if $try++ > 300;
}
# Wait until the processQemuOutput thread signals that the machine
# is up.
$self->{connectedQueue}->dequeue();
while (1) {
$self->log("trying to connect");

View File

@ -7,13 +7,15 @@ export PATH=@extraUtils@/bin:@klibc@/bin
fail() {
if [ -n "$panicOnFail" ]; then exit 1; fi
# If starting stage 2 failed, allow the user to repair the problem
# in an interactive shell.
cat <<EOF
An error occured in stage 1 of the boot process, which must mount the
root filesystem on \`$targetRoot' and then start stage 2. Press one
of the following keys within $timeout seconds:
of the following keys:
i) to launch an interactive shell;
f) to start an interactive shell having pid 1 (needed if you want to
@ -74,6 +76,9 @@ for o in $(cat /proc/cmdline); do
debug1mounts) # stop after mounting file systems
debug1mounts=1
;;
stage1panic)
panicOnFail=1
;;
esac
done

View File

@ -14,9 +14,8 @@ with pkgs.lib;
preStart =
''
eval $(cat /proc/cmdline)
echo "guest running, will write in $hostTmpDir on host" > /dev/ttyS0
touch /hostfs/$hostTmpDir/running
echo "guest running" > /dev/ttyS0
echo "===UP===" > dev/ttyS0
'';
exec = "${pkgs.socat}/bin/socat tcp-listen:514,fork exec:/bin/sh,stderr";
@ -45,6 +44,10 @@ with pkgs.lib;
# If the kernel has been built with coverage instrumentation, make
# it available under /proc/gcov.
boot.kernelModules = [ "gcov-proc" ];
# Panic if an error occurs in stage 1 (rather than waiting for
# user intervention).
boot.kernelParams = [ "stage1panic" ];
};