X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Futils%2Fpintos;h=83954bb951fdabf2a8e7c019e6344fac92bbb7ac;hb=e9fd665beb814115e19fdbcd33cddd8a299c6960;hp=c29b6a3c4043b85968fec25de43e0a8d699634b6;hpb=31a48f116ba391a08a4844eb407c43e0ba8f773f;p=pintos-anon diff --git a/src/utils/pintos b/src/utils/pintos index c29b6a3..83954bb 100755 --- a/src/utils/pintos +++ b/src/utils/pintos @@ -7,6 +7,7 @@ use File::Temp 'tempfile'; use Getopt::Long qw(:config bundling); # Command-line options. +our ($start_time) = time (); our ($sim); # Simulator: bochs, qemu, or gsx. our ($debug) = "none"; # Debugger: none, monitor, or gdb. our ($mem) = 4; # Physical RAM in MB. @@ -111,7 +112,8 @@ Display options: (default is both VGA and serial) Timing options: (Bochs only) -j SEED Randomize timer interrupts -r, --realtime Use realistic, not reproducible, timings - -T, --timeout=N Time out and kill Pintos after N seconds + -T, --timeout=N Kill Pintos after N seconds CPU time or N*load_avg + seconds wall-clock time (whichever comes first) Configuration options: -m, --mem=N Give Pintos N MB physical RAM (default: 4) File system commands (for `run' command): @@ -212,10 +214,8 @@ sub find_disks { my ($mb) = $disk->{FILENAME}; undef $disk->{FILENAME}; - my ($cylinder) = 1024 * 504; - my ($bytes) = $mb * ($cylinder * 2); - $bytes = int (($bytes + $cylinder - 1) / $cylinder) * $cylinder; - extend_disk ($disk, $bytes); + my ($cyl_size) = 512 * 16 * 63; + extend_disk ($disk, ceil ($mb * 2) * $cyl_size); } else { # The file must exist and have nonzero size. -e $disk->{FILENAME} or die "$disk->{FILENAME}: stat: $!\n"; @@ -382,6 +382,7 @@ boot: c ips: 1000000 megs: $mem log: bochsout.txt +panic: action=fatal EOF print BOCHSRC "clock: sync=", $realtime ? 'realtime' : 'none', "time0=0\n"; print_bochs_disk_line ("ata0-master", 0); @@ -425,9 +426,10 @@ EOF # line for attaching it to $device. sub print_bochs_disk_line { my ($device, $iface) = @_; - my ($file) = $disks_by_iface[$iface]{FILENAME}; + my ($disk) = $disks_by_iface[$iface]; + my ($file) = $disk->{FILENAME}; if (defined $file) { - my (%geom) = disk_geometry ($file); + my (%geom) = disk_geometry ($disk); print BOCHSRC "$device: type=disk, path=$file, mode=flat, "; print BOCHSRC "cylinders=$geom{C}, heads=$geom{H}, spt=$geom{S}, "; print BOCHSRC "translation=none\n"; @@ -446,7 +448,7 @@ sub run_qemu { push (@cmd, $option, $disks_by_iface[$iface]{FILENAME}) if defined $disks_by_iface[$iface]{FILENAME}; } - push (@cmd, '-m', $mem); + push (@cmd, '-m', $mem, '-nics', '0'); push (@cmd, '-nographic') if $vga eq 'none'; push (@cmd, '-serial', 'stdio') if $serial_out && $vga ne 'none'; push (@cmd, '-S') if $debug eq 'monitor'; @@ -487,7 +489,8 @@ serial0.fileName = "pintos.out" EOF for (my ($i) = 0; $i < 4; $i++) { - my ($dsk) = $disks_by_iface[$i]{FILENAME}; + my ($disk) = $disks_by_iface[$i]; + my ($dsk) = $disk->{FILENAME}; next if !defined $dsk; my ($pln) = $dsk; @@ -502,7 +505,7 @@ $device.deviceType = "plainDisk" $device.fileName = "$pln" EOF - my (%geom) = disk_geometry ($dsk); + my (%geom) = disk_geometry ($disk); open (PLN, ">", $pln) or die "$pln: create: $!\n"; print PLN <{FILENAME}; my ($size) = -s $file; die "$file: stat: $!\n" if !defined $size; die "$file: size not a multiple of 512 bytes\n" if $size % 512; - my ($cylinders) = int ($size / (512 * 16 * 63)); - $cylinders++ if $size % (512 * 16 * 63); + my ($cyl_size) = 512 * 16 * 63; + my ($cylinders) = ceil ($size / $cyl_size); + extend_disk ($disk, $cylinders * $cyl_size) if $size % $cyl_size; return (CAPACITY => $size / 512, C => $cylinders, @@ -657,16 +662,22 @@ sub xsystem { die "fork: $!\n"; } elsif (!$pid) { # Running in child process. - exec (@_); - exit (1); + exec_setitimer (@_); } else { # Running in parent process. local $SIG{ALRM} = sub { timeout ($pid); }; local $SIG{INT} = sub { relay_signal ($pid, "INT"); }; local $SIG{TERM} = sub { relay_signal ($pid, "TERM"); }; - alarm ($timeout) if defined ($timeout); + alarm ($timeout * get_load_average () + 1) if defined ($timeout); waitpid ($pid, 0); alarm (0); + + if (WIFSIGNALED ($?) && WTERMSIG ($?) == SIGVTALRM ()) { + seek (STDOUT, 0, 2); + print "\nTIMEOUT after $timeout seconds of host CPU time\n"; + exit 0; + } + return $?; } } @@ -674,10 +685,11 @@ sub xsystem { # relay_signal($pid, $signal) # # Relays $signal to $pid and then reinvokes it for us with the default -# handler. +# handler. Also cleans up temporary files. sub relay_signal { my ($pid, $signal) = @_; kill $signal, $pid; + File::Temp::cleanup(); $SIG{$signal} = 'DEFAULT'; kill $signal, getpid (); } @@ -691,8 +703,45 @@ sub timeout { waitpid ($pid, 0); seek (STDOUT, 0, 2); my ($load_avg) = `uptime` =~ /(load average:.*)$/i; - print "\nTIMEOUT after $timeout seconds"; + print "\nTIMEOUT after ", time () - $start_time, + " seconds of wall-clock time"; print " - $load_avg" if defined $load_avg; print "\n"; exit 0; } + +# Returns the system load average over the last minute. +# If the load average is less than 1.0 or cannot be determined, returns 1.0. +sub get_load_average { + my ($avg) = `uptime` =~ /load average:\s*([^,]+),/; + return $avg >= 1.0 ? $avg : 1.0; +} + +# Calls setitimer to set a timeout, then execs what was passed to us. +sub exec_setitimer { + if (defined $timeout) { + if ($ ge 5.8.0) { + eval " + use Time::HiRes qw(setitimer ITIMER_VIRTUAL); + setitimer (ITIMER_VIRTUAL, $timeout, 0); + "; + } else { + { exec ("setitimer-helper", $timeout, @_); }; + exit 1 if !$!{ENOENT}; + print STDERR "warning: setitimer-helper is not installed, so ", + "CPU time limit will not be enforced\n"; + } + } + exec (@_); + exit (1); +} + +sub SIGVTALRM { + use Config; + my $i = 0; + foreach my $name (split(' ', $Config{sig_name})) { + return $i if $name eq 'VTALRM'; + $i++; + } + return 0; +}