* 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:
parent
5730c27aed
commit
170331be30
@ -1,9 +1,12 @@
|
|||||||
package Machine;
|
package Machine;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
use threads;
|
||||||
|
use Thread::Queue;
|
||||||
use Socket;
|
use Socket;
|
||||||
use IO::Handle;
|
use IO::Handle;
|
||||||
use POSIX qw(dup2);
|
use POSIX qw(dup2);
|
||||||
|
use FileHandle;
|
||||||
|
|
||||||
|
|
||||||
# Stuff our PID in the multicast address/port to prevent collissions
|
# Stuff our PID in the multicast address/port to prevent collissions
|
||||||
@ -26,6 +29,7 @@ sub new {
|
|||||||
booted => 0,
|
booted => 0,
|
||||||
pid => 0,
|
pid => 0,
|
||||||
connected => 0,
|
connected => 0,
|
||||||
|
connectedQueue => Thread::Queue->new(),
|
||||||
socket => undef,
|
socket => undef,
|
||||||
stateDir => "$tmpDir/$name",
|
stateDir => "$tmpDir/$name",
|
||||||
};
|
};
|
||||||
@ -62,14 +66,15 @@ sub start {
|
|||||||
|
|
||||||
$self->log("starting vm");
|
$self->log("starting vm");
|
||||||
|
|
||||||
|
my ($read, $write) = FileHandle::pipe;
|
||||||
|
|
||||||
my $pid = fork();
|
my $pid = fork();
|
||||||
die if $pid == -1;
|
die if $pid == -1;
|
||||||
|
|
||||||
if ($pid == 0) {
|
if ($pid == 0) {
|
||||||
my $name = $self->{name};
|
close $read;
|
||||||
open LOG, "| sed --unbuffered 's|^|$name console: |'" or die;
|
dup2(fileno($write), fileno(STDOUT));
|
||||||
dup2(fileno(LOG), fileno(STDOUT));
|
dup2(fileno($write), fileno(STDERR));
|
||||||
dup2(fileno(LOG), fileno(STDERR));
|
|
||||||
open NUL, "</dev/null" or die;
|
open NUL, "</dev/null" or die;
|
||||||
dup2(fileno(NUL), fileno(STDIN));
|
dup2(fileno(NUL), fileno(STDIN));
|
||||||
$ENV{TMPDIR} = $self->{stateDir};
|
$ENV{TMPDIR} = $self->{stateDir};
|
||||||
@ -80,6 +85,21 @@ sub start {
|
|||||||
die;
|
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->log("vm running as pid $pid");
|
||||||
$self->{pid} = $pid;
|
$self->{pid} = $pid;
|
||||||
$self->{booted} = 1;
|
$self->{booted} = 1;
|
||||||
@ -92,12 +112,9 @@ sub connect {
|
|||||||
|
|
||||||
$self->start;
|
$self->start;
|
||||||
|
|
||||||
my $try = 0;
|
# Wait until the processQemuOutput thread signals that the machine
|
||||||
while (1) {
|
# is up.
|
||||||
last if -e ($self->{stateDir} . "/running");
|
$self->{connectedQueue}->dequeue();
|
||||||
sleep 1;
|
|
||||||
die ("VM " . $self->{name} . " timed out") if $try++ > 300;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
$self->log("trying to connect");
|
$self->log("trying to connect");
|
||||||
|
@ -7,13 +7,15 @@ export PATH=@extraUtils@/bin:@klibc@/bin
|
|||||||
|
|
||||||
|
|
||||||
fail() {
|
fail() {
|
||||||
|
if [ -n "$panicOnFail" ]; then exit 1; fi
|
||||||
|
|
||||||
# If starting stage 2 failed, allow the user to repair the problem
|
# If starting stage 2 failed, allow the user to repair the problem
|
||||||
# in an interactive shell.
|
# in an interactive shell.
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
An error occured in stage 1 of the boot process, which must mount the
|
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
|
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;
|
i) to launch an interactive shell;
|
||||||
f) to start an interactive shell having pid 1 (needed if you want to
|
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) # stop after mounting file systems
|
||||||
debug1mounts=1
|
debug1mounts=1
|
||||||
;;
|
;;
|
||||||
|
stage1panic)
|
||||||
|
panicOnFail=1
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -14,9 +14,8 @@ with pkgs.lib;
|
|||||||
|
|
||||||
preStart =
|
preStart =
|
||||||
''
|
''
|
||||||
eval $(cat /proc/cmdline)
|
echo "guest running" > /dev/ttyS0
|
||||||
echo "guest running, will write in $hostTmpDir on host" > /dev/ttyS0
|
echo "===UP===" > dev/ttyS0
|
||||||
touch /hostfs/$hostTmpDir/running
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
exec = "${pkgs.socat}/bin/socat tcp-listen:514,fork exec:/bin/sh,stderr";
|
exec = "${pkgs.socat}/bin/socat tcp-listen:514,fork exec:/bin/sh,stderr";
|
||||||
@ -46,6 +45,10 @@ with pkgs.lib;
|
|||||||
# it available under /proc/gcov.
|
# it available under /proc/gcov.
|
||||||
boot.kernelModules = [ "gcov-proc" ];
|
boot.kernelModules = [ "gcov-proc" ];
|
||||||
|
|
||||||
|
# Panic if an error occurs in stage 1 (rather than waiting for
|
||||||
|
# user intervention).
|
||||||
|
boot.kernelParams = [ "stage1panic" ];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user