diff --git a/src/parallel b/src/parallel index c46d1dc3..bd5affae 100755 --- a/src/parallel +++ b/src/parallel @@ -2439,7 +2439,7 @@ sub reaper { if($opt::halt_on_error) { if($opt::halt_on_error == 1 or - ($opt::halt_on_error < 1 and $Global::total_failed > 1 + ($opt::halt_on_error < 1 and $Global::total_failed > 3 and $Global::total_failed / $Global::total_started > $opt::halt_on_error)) { # If halt on error == 1 or --halt 10% @@ -4771,36 +4771,55 @@ sub kill { } } -sub family_pids { - # Find the pids with this->pid as (grand)*parent - # TODO test this on different OS as 'ps' is known to be different - my $self = shift; - my $pid = $self->pid(); - my (@pidtable,%children_of,@pids); - if ($^O eq 'linux' or $^O eq 'solaris' or $^O eq 'cygwin') { - # Table with pid parentpid (SysV + GNU) - @pidtable = `ps -ef | awk '{print \$2" "\$3}'`; - } else { - # Table with pid parentpid (BSD) - @pidtable = `ps -o pid,ppid -ax`; - } - for (@pidtable) { - /(\S+)\s+(\S+)/ or ::die_bug("pidtable format"); - push(@{$children_of{$2}},$1); - } - my @more = ($pid); - while(@more) { - my @m; - push @pids,@more; - for my $parent (@more) { - if($children_of{$parent}) { - push @m, @{$children_of{$parent}}; - } - } - @more = @m; - } +{ + my %pid_parentpid_cmd; - return (@pids); + sub family_pids { + # Find the pids with this->pid as (grand)*parent + my $self = shift; + my $pid = $self->pid(); + + %pid_parentpid_cmd or %pid_parentpid_cmd = + ( + 'aix' => q( ps -ef | awk '{print $2" "$3}' ), + 'cygwin' => q( ps -ef | awk '{print $2" "$3}' ), + 'dec_osf' => q( ps -ef | awk '{print $2" "$3}' ), + 'darwin' => q( ps -o pid,ppid -ax ), + 'dragonfly' => q( ps -o pid,ppid -ax ), + 'freebsd' => q( ps -o pid,ppid -ax ), + 'gnu' => q( ps -ef | awk '{print $2" "$3}' ), + 'hpux' => q( ps -ef | awk '{print $2" "$3}' ), + 'linux' => q( ps -ef | awk '{print $2" "$3}' ), + 'mirbsd' => q( ps -o pid,ppid -ax ), + 'netbsd' => q( ps -o pid,ppid -ax ), + 'nto' => q( ps -ef | awk '{print $2" "$3}' ), + 'openbsd' => q( ps -o pid,ppid -ax ), + 'solaris' => q( ps -ef | awk '{print $2" "$3}' ), + 'svr5' => q( ps -ef | awk '{print $2" "$3}' ), + ); + $pid_parentpid_cmd{$^O} or ::die_bug("pid_parentpid_cmd for $^O missing"); + + my (@pidtable,%children_of,@pids); + # Table with pid parentpid + @pidtable = `$pid_parentpid_cmd{$^O}`; + for (@pidtable) { + /(\S+)\s+(\S+)/ or ::die_bug("pidtable format"); + push(@{$children_of{$2}},$1); + } + my @more = ($pid); + while(@more) { + my @m; + push @pids,@more; + for my $parent (@more) { + if($children_of{$parent}) { + push @m, @{$children_of{$parent}}; + } + } + @more = @m; + } + + return (@pids); + } } sub failed { diff --git a/src/parallel.pod b/src/parallel.pod index 28cab596..ac2db6b1 100644 --- a/src/parallel.pod +++ b/src/parallel.pod @@ -639,11 +639,13 @@ See also: B<--line-buffer> B<--ungroup> Print a summary of the options to GNU B and exit. -=item B<--halt-on-error> <0|1|2> +=item B<--halt-on-error> I (alpha testing) -=item B<--halt> <0|1|2> +=item B<--halt> I (alpha testing) -=over 3 +How should GNU B terminate if one of more jobs fail? + +=over 7 =item Z<>0 @@ -661,6 +663,12 @@ last failing job. Kill off all jobs immediately and exit without cleanup. The exit status will be the exit status from the failing job. +=item Z<>1-99% + +If I% of the jobs fail and minimum 3: Do not start new jobs, but +complete the running jobs including cleanup. The exit status will be +the exit status from the last failing job. + =back @@ -845,9 +853,9 @@ the same syntax as B<--jobs>, so I<100%> for one per CPU is a valid setting. Only difference is 0 which is interpreted as 0.01. -=item B<--controlmaster> (experimental) +=item B<--controlmaster> -=item B<-M> (experimental) +=item B<-M> Use ssh's ControlMaster to make ssh connections faster. Useful if jobs run remote and are very fast to run. This is disabled for sshlogins diff --git a/src/parallel.texi b/src/parallel.texi index 245b7e18..d87d5120 100644 --- a/src/parallel.texi +++ b/src/parallel.texi @@ -737,11 +737,13 @@ See also: @strong{--line-buffer} @strong{--ungroup} Print a summary of the options to GNU @strong{parallel} and exit. -@item @strong{--halt-on-error} <0|1|2> -@anchor{@strong{--halt-on-error} <0|1|2>} +@item @strong{--halt-on-error} @emph{val} (alpha testing) +@anchor{@strong{--halt-on-error} @emph{val} (alpha testing)} -@item @strong{--halt} <0|1|2> -@anchor{@strong{--halt} <0|1|2>} +@item @strong{--halt} @emph{val} (alpha testing) +@anchor{@strong{--halt} @emph{val} (alpha testing)} + +How should GNU @strong{parallel} terminate if one of more jobs fail? @table @asis @item 0 @@ -763,6 +765,13 @@ last failing job. Kill off all jobs immediately and exit without cleanup. The exit status will be the exit status from the failing job. +@item 1-99% +@anchor{1-99%} + +If @emph{val}% of the jobs fail: Do not start new jobs, but complete the +running jobs including cleanup. The exit status will be the exit +status from the last failing job. + @end table @item @strong{--header} @emph{regexp} diff --git a/src/parallel_tutorial.pod b/src/parallel_tutorial.pod index fb14b318..3fe35a03 100644 --- a/src/parallel_tutorial.pod +++ b/src/parallel_tutorial.pod @@ -1170,6 +1170,25 @@ Output: parallel: This job failed: echo 1; exit 1 +If --halt is given a percentage this percentage of the jobs must fail +(though minimum 3) before GNU Parallel stops spawning more jobs: + + parallel -j2 --halt 20% echo {}\; exit {} ::: 0 0 1 2 3 4 5 6 7 + +Output: + + 0 + 0 + 1 + 2 + 3 + 4 + parallel: Starting no more jobs. Waiting for 2 jobs to finish. This job failed: + echo 4; exit 4 + 5 + parallel: Starting no more jobs. Waiting for 1 jobs to finish. This job failed: + echo 5; exit 5 + GNU Parallel can retry the command with --retries. This is useful if a command fails for unkown reasons now and then. diff --git a/testsuite/tests-to-run/parallel-polarhome.sh b/testsuite/tests-to-run/parallel-polarhome.sh index 99824722..5228bc8f 100644 --- a/testsuite/tests-to-run/parallel-polarhome.sh +++ b/testsuite/tests-to-run/parallel-polarhome.sh @@ -1,6 +1,6 @@ #!/bin/bash -P_ALL="vax freebsd solaris openbsd netbsd debian alpha aix redhat hpux ultrix qnx irix tru64 openindiana suse solaris-x86 mandriva ubuntu scosysv unixware dragonfly centos miros hurd raspberrypi" +P_ALL="vax freebsd solaris openbsd netbsd debian alpha aix redhat hpux ultrix minix qnx irix tru64 openindiana suse solaris-x86 mandriva ubuntu scosysv unixware dragonfly centos miros hurd raspberrypi" P_NOTWORKING="vax alpha openstep" P_NOTWORKING_YET="ultrix irix"