-sub run_test {
- my ($test) = @_;
- return "ok" if -f "output/$test.run.out";
-
- my ($src) = "$GRADES_DIR/$test.c";
- -e $src or die "$src: stat: $!\n";
- xsystem ("", "cp $src pintos/src/threads/test.c") or die;
- unlink ("pintos/src/threads/build/threads/test.o");
- unlink ("pintos/src/threads/build/kernel.o");
- unlink ("pintos/src/threads/build/kernel.bin");
- unlink ("pintos/src/threads/build/os.dsk");
- xsystem ("$test.make", "cd pintos/src/threads && make")
- or return "compile error";
- xsystem ("$test.run", "cd pintos/src/threads/build && pintos -v run -q")
- or return "Bochs error";
- return "ok";
-}
-
-sub xsystem {
- my ($log, $command) = @_;
- print "$command\n" if $verbose;
-
- my ($status);
- if ($log ne '') {
- $status = systimeout ("($command) >output/$log.out 2>output/$log.err");
- unlink ("output/$log.err") unless $status != 0;
- } else {
- $status = systimeout ($command);
+sub grade_alarm_zero {
+ my (@output) = @_;
+ verify_common (@output);
+ die "Crashed in timer_sleep()\n" if !grep (/^Success\.$/, @output);
+}
+
+sub grade_alarm_negative {
+ my (@output) = @_;
+ verify_common (@output);
+ die "Crashed in timer_sleep()\n" if !grep (/^Success\.$/, @output);
+}
+
+sub grade_join_invalid {
+ my (@output) = @_;
+ verify_common (@output);
+ grep (/Testing invalid join/, @output) or die "Test didn't start\n";
+ grep (/Invalid join test done/, @output) or die "Test didn't complete\n";
+}
+
+sub grade_join_no {
+ my (@output) = @_;
+ verify_common (@output);
+ grep (/Testing no join/, @output) or die "Test didn't start\n";
+ grep (/No join test done/, @output) or die "Test didn't complete\n";
+}
+
+sub grade_join_multiple {
+ my (@output) = @_;
+
+ verify_common (@output);
+ my (@t);
+ $t[4] = $t[5] = $t[6] = -1;
+ local ($_);
+ foreach (@output) {
+ my ($idx) = /^Thread (\d+)/ or next;
+ my ($iter) = /iteration (\d+)$/;
+ $iter = 5 if /done!$/;
+ die "Malformed output\n" if !defined $iter;
+ if ($idx == 6) {
+ die "Thread 6 started before either other thread finished\n"
+ if $t[4] < 5 && $t[5] < 5;
+ die "Thread 6 started before thread 4 finished\n"
+ if $t[4] < 5;
+ die "Thread 6 started before thread 5 finished\n"
+ if $t[5] < 5;
+ }
+ die "Thread $idx out of order output\n" if $t[$idx] != $iter - 1;
+ $t[$idx] = $iter;
+ }
+
+ my ($err) = "";
+ for my $idx (4, 5, 6) {
+ if ($t[$idx] == -1) {
+ $err .= "Thread $idx did not run at all\n";
+ } elsif ($t[$idx] != 5) {
+ $err .= "Thread $idx only completed $t[$idx] iterations\n";
+ }
+ }
+ die $err if $err ne '';
+}
+
+sub grade_priority_fifo {
+ my (@output) = @_;
+
+ verify_common (@output);
+ my ($thread_cnt) = 10;
+ my ($iter_cnt) = 5;
+ my (@order);
+ my (@t) = (-1) x $thread_cnt;
+ local ($_);
+ foreach (@output) {
+ my ($idx) = /^Thread (\d+)/ or next;
+ my ($iter) = /iteration (\d+)$/;
+ $iter = $iter_cnt if /done!$/;
+ die "Malformed output\n" if !defined $iter;
+ if (@order < $thread_cnt) {
+ push (@order, $idx);
+ die "Thread $idx repeated within first $thread_cnt iterations: "
+ . join (' ', @order) . ".\n"
+ if grep ($_ == $idx, @order) != 1;
+ } else {
+ die "Thread $idx ran when $order[0] should have.\n"
+ if $idx != $order[0];
+ push (@order, shift @order);
+ }
+ die "Thread $idx out of order output.\n" if $t[$idx] != $iter - 1;
+ $t[$idx] = $iter;
+ }
+
+ my ($err) = "";
+ for my $idx (0..$#t) {
+ if ($t[$idx] == -1) {
+ $err .= "Thread $idx did not run at all.\n";
+ } elsif ($t[$idx] != $iter_cnt) {
+ $err .= "Thread $idx only completed $t[$idx] iterations.\n";
+ }