ソースを参照

Switch from wait() to waitpid() and move the reaping code from the signal
handler to the main loop.

Markus Hennecke 9 年 前
コミット
2993086fc9
1 ファイル変更46 行追加18 行削除
  1. 46 18
      autoupdate.pl

+ 46 - 18
autoupdate.pl

@@ -1,5 +1,5 @@
 #! /usr/bin/perl -w
-# $Id: autoupdate.pl,v 1.34 2012/03/04 16:09:46 markus Exp $
+# $Id: autoupdate.pl,v 1.35 2014/09/07 07:11:10 markus Exp $
 # Copyright (c) 2007,2008,2009
 #    Markus Hennecke <markus-hennecke@markus-hennecke.de>
 #
@@ -24,7 +24,7 @@ use OpenBSD::PackageName;
 use Getopt::Long;
 use FindBin;
 use File::Spec;
-use POSIX qw/uname/;
+use POSIX qw/uname :sys_wait_h/;
 
 # Silence the warning that is issued because List::Util won't register
 # $a and $b in a correct way for us
@@ -83,24 +83,47 @@ my $abort = 0;
 # Ports that failed to build
 my @aborted = ();
 
+# Hash of reaped child processes
+my %reaped_pids = ();
+
+
 # This function will remove the finished forked build from the list of
 # currently build ports.
 sub REAPER {
-	my $wpid = wait();
-	my $status = $?;
-
-	$abort = 1 if ($status != 0);
-	if (exists $forked_builds{$wpid}) {
-		$jobs--;
-		if ($status == 0) {
-			print STDOUT "Finished build of ";
+	while ((my $wpid = waitpid(-1, &WNOHANG)) > 0) {
+		my $status = $?;
+
+		$abort = 1 if ($status != 0);
+		$reaped_pids{$wpid} = $status;
+	}
+	$SIG{CHLD} = \&REAPER;
+}
+
+
+# Remove the status codes/PIDs from the reaped_pids hash periodically
+sub reap {
+	my @pids = keys %reaped_pids;
+	while (scalar @pids) {
+		my $wpid = shift @pids;
+		if (exists $forked_builds{$wpid}) {
+			my $portname = $forked_builds{$wpid};
+			$jobs--;
+			my $status = $reaped_pids{$wpid};
+			if ($status == 0) {
+				print STDOUT 'Finished build of ';
+			}
+			else {
+				print STDOUT 'Build aborted of ';
+				push @aborted, ($portname);
+			}
+			delete $forked_builds{$wpid};
+			print STDOUT $portname . "\n";
 		}
 		else {
-			print STDOUT "Build aborted of ";
-			push @aborted, ($forked_builds{$wpid});
+			print STDOUT 'No forked process recorded for '
+			  . $wpid . "\n";
 		}
-		print $forked_builds{$wpid} . "\n";
-		delete $forked_builds{$wpid};
+		delete $reaped_pids{$wpid};
 	}
 }
 
@@ -534,7 +557,8 @@ sub build_pkg {
 	my $pid = fork();
 	if (! defined $pid) {
 		die "Cannot fork to build $port\n";
-	} elsif ($pid) {
+	}
+	elsif ($pid) {
 		$forked_builds{$pid} = $port;
 		$jobs++;
 		return;
@@ -819,6 +843,9 @@ $SIG{CHLD} = \&REAPER;
 
 # Build all the packages. Packages that are still unknown to us are ignored.
 foreach my $pkg_name (@pkg_list)  {
+
+	reap();
+
 	# Get the package information from the info array
 	my $info = get_pkg_info($port_info, $pkg_name);
 
@@ -832,13 +859,14 @@ foreach my $pkg_name (@pkg_list)  {
 
 	# XXX Here we must check if the package depends on a currently build
 	# package too.
-	while ($jobs >= $num_jobs || can_pkg_be_build($info)) {
+	while (($jobs >= $num_jobs || can_pkg_be_build($info)) && !$abort) {
 		if ($wait_for_dep_notice == 0 && !can_pkg_be_build($info)) {
 			print STDOUT "Waiting for dependant package to finish "
 			    . "building (" . $pkg_name . ")\n" 
 				unless ($verbose < 2);
 			$wait_for_dep_notice++;
 		}
+		reap();
 		sleep 1;
 	}
 
@@ -847,11 +875,11 @@ foreach my $pkg_name (@pkg_list)  {
 }
 
 # Wait for all childs to finish
-while (keys %forked_builds) {
+while (scalar (keys %forked_builds)) {
 	sleep 1;
 }
 
-die "Abort requested by child" if ($abort != 0);
+die 'Abort requested by child' if ($abort != 0);
 print STDOUT "Done.\n";
 
 # Close the pipe to our log file if we were logging