--eta was broken. Now fixed.

Race condition in sem fixed with setsid().
Passes unittest.
This commit is contained in:
Ole Tange 2010-08-22 01:29:26 +02:00
parent adff24a1a0
commit 0fbd1b2653
9 changed files with 92 additions and 98 deletions

View file

@ -1,16 +1,7 @@
Bug: seq 1 10 | stdout parallel --eta echo
# Examples of sem # Examples of sem
Weird bug - only interactive
perlipc: Complete Dissociation of Child from Parent
Setting $SIG{CHLD} to 'IGNORE'
echo '### BUG: Test --fg followed by --bg'
parallel -u --fg --semaphore seq 1 10 '|' pv -qL 20
parallel -u --bg --semaphore seq 11 20 '|' pv -qL 20
parallel -u --fg --semaphore seq 21 30 '|' pv -qL 20
parallel -u --bg --semaphore seq 31 40 '|' pv -qL 20
sem --wait
find . -execdir sem -j100 'sleep 4; echo {}' \; ; sem --wait find . -execdir sem -j100 'sleep 4; echo {}' \; ; sem --wait
@ -18,46 +9,12 @@ fex syntax for splitting fields
http://www.semicomplete.com/projects/fex/ http://www.semicomplete.com/projects/fex/
sql :foo 'select * from bar' | parallel --fex '|{1,2}' do_stuff {2} {1} sql :foo 'select * from bar' | parallel --fex '|{1,2}' do_stuff {2} {1}
Unittest: --colsep + multiple -a
Import sql Import sql
inputfile tabel, Split colonner til {n} inputfile tabel, Split colonner til {n}
sql :foo 'select * from bar' | parallel --colsep '\|' do_stuff {4} {1} sql :foo 'select * from bar' | parallel --colsep '\|' do_stuff {4} {1}
if(defined $::opt_colsep and defined @::opt_a and @::opt_a > 1) {
# must be done after converting :::: to -a -a
warn("--colsep incompatible with multiple argument files. Ignoring --colsep");
$::opt_colsep = undef;
}
if($::opt_colsep) {
# read input either from -a or from stdin
my $max_cols = 0;
my @table;
my $lineno = 0;
$Global::input_is_filename = 0; # cheat get_next_arg into not quoting
while get_next_arg {
my @cols = split /$::opt_colsep/o, $_;
if ($Global::trim) {
for(@cols) { s/^\s+//; s/\s+$//; }
}
$max_cols = max($#cols+1,$max_cols);
@table[$lineno++] = @cols;
}
$::opt_N = $max_cols;
for ($lineno = 0; $lineno <= $#table; $lineno++) {
if (not defined $table[$lineno][$max_col-1]) {
# Make sure the table has the same columns for all rows
$table[$lineno][$max_col-1] = "";
}
unget_arg(@table[$lineno]);
}
}
--autocolsep: Læs alle linjer. --autocolsep: Læs alle linjer.
Prøv fastlængde: Find tegn, som står i alle linjer på de samme pladser. Risiko for falske pos Prøv fastlængde: Find tegn, som står i alle linjer på de samme pladser. Risiko for falske pos
Prøv fieldsep: Find eet tegn, som optræder det samme antal gange i alle linjer (tab sep) Prøv fieldsep: Find eet tegn, som optræder det samme antal gange i alle linjer (tab sep)
@ -117,6 +74,9 @@ find music-files -type f | parallel -j+0 lame {} -o {.}.mp3
find music-files -type f | parallel -j+0 -S :,computer1.examle.com,computer2.example.com \ find music-files -type f | parallel -j+0 -S :,computer1.examle.com,computer2.example.com \
--eta --trc {.}.mp3 lame {} -o {.}.mp3 --eta --trc {.}.mp3 lame {} -o {.}.mp3
# Colsep
# sem
=head1 YouTube video =head1 YouTube video

View file

@ -91,7 +91,9 @@ download at: http://ftp.gnu.org/gnu/parallel/
New in this release: New in this release:
* Counting semaphore functionality: start a job in the background. If * Counting semaphore functionality: start a job in the background. If
N jobs are already running, wait for one to complete. N jobs are already running, wait for one to complete. Examples:
sem 'sleep 2; echo foo'; sem 'sleep 1; echo bar'; sem --wait
sem -j2 'sleep 2; echo foo'; sem -j2 'sleep 1; echo bar'; sem --wait
* With --colsep a table can be used as input. Example: * With --colsep a table can be used as input. Example:
cat tab_sep_table | parallel --colsep '\t' echo col1 {1} col2 {2} cat tab_sep_table | parallel --colsep '\t' echo col1 {1} col2 {2}

View file

@ -1265,11 +1265,11 @@ To run:
you can run: you can run:
parallel -a table_file.tsv --colsep '\t' cmd -o {2} -i {1} B<parallel -a table_file.tsv --colsep '\t' cmd -o {2} -i {1}>
Note: The default for GNU B<parallel> is to remove the spaces around the columns. To keep the spaces: Note: The default for GNU B<parallel> is to remove the spaces around the columns. To keep the spaces:
parallel -a table_file.tsv --trim n --colsep '\t' cmd -o {2} -i {1} B<parallel -a table_file.tsv --trim n --colsep '\t' cmd -o {2} -i {1}>
=head1 EXAMPLE: Working as cat | sh. Ressource inexpensive jobs and evaluation =head1 EXAMPLE: Working as cat | sh. Ressource inexpensive jobs and evaluation
@ -2077,7 +2077,7 @@ B<xjobs>(1), B<prll>(1), B<dxargs>(1), B<mdm>(1)
use IPC::Open3; use IPC::Open3;
use Symbol qw(gensym); use Symbol qw(gensym);
use IO::File; use IO::File;
use POSIX ":sys_wait_h"; use POSIX qw/:sys_wait_h setsid/;
use File::Temp qw/tempfile tempdir/; use File::Temp qw/tempfile tempdir/;
use Getopt::Long; use Getopt::Long;
use strict; use strict;
@ -2109,8 +2109,6 @@ sub acquire_semaphore {
my $sem = Semaphore->new($Semaphore::name,$Global::host{':'}{'max_no_of_running'}); my $sem = Semaphore->new($Semaphore::name,$Global::host{':'}{'max_no_of_running'});
$sem->acquire(); $sem->acquire();
debug("run"); debug("run");
$Global::argfile = open_or_exit("/dev/null");
unget_arg("");
if($Semaphore::fg) { if($Semaphore::fg) {
# skip # skip
} else { } else {
@ -2118,14 +2116,11 @@ sub acquire_semaphore {
# therefore release and re-acquire the semaphore # therefore release and re-acquire the semaphore
$sem->release(); $sem->release();
if(fork()) { if(fork()) {
# TODO figure out the race condition that requires this sleep 1
# sem --fg seq 21 30
# sem --bg seq 31 40
sleep(1);
exit(0); exit(0);
} else { } else {
# child # child
# Get a semaphore for this pid # Get a semaphore for this pid
die "Can't start a new session: $!" if setsid() == -1;
$sem = Semaphore->new($Semaphore::name,$Global::host{':'}{'max_no_of_running'}); $sem = Semaphore->new($Semaphore::name,$Global::host{':'}{'max_no_of_running'});
$sem->acquire(); $sem->acquire();
} }
@ -2316,6 +2311,25 @@ sub parse_options {
$Global::Xargs = 1; $Global::Xargs = 1;
} }
# Semaphore defaults
# Must be done before computing number of processes and max_line_length as no args
$Global::semaphore ||= ($0 =~ m:(^|/)sem$:); # called as 'sem'
if($Global::semaphore) {
# A semaphore does not take input from neither stdin nor file
$Global::argfile = open_or_exit("/dev/null");
unget_arg("");
$Semaphore::timeout = $::opt_semaphoretimeout || 0;
if(defined $::opt_semaphorename) {
$Semaphore::name = $::opt_semaphorename;
} else {
$Semaphore::name = `tty`;
chomp $Semaphore::name;
}
$Semaphore::fg = $::opt_fg;
$Semaphore::wait = $::opt_wait;
$Global::default_simultaneous_sshlogins = 1;
}
if(defined $::opt_eta) { if(defined $::opt_eta) {
# must be done after opt_a # must be done after opt_a
$::opt_progress = $::opt_eta; $::opt_progress = $::opt_eta;
@ -2345,22 +2359,6 @@ sub parse_options {
print STDERR ("Warning: using -X or -m with --sshlogin may fail\n"); print STDERR ("Warning: using -X or -m with --sshlogin may fail\n");
} }
# Semaphore defaults
# Must be done before computing number of processes
$Global::semaphore ||= ($0 =~ m:(^|/)sem$:); # called as 'sem'
if($Global::semaphore) {
$Semaphore::timeout = $::opt_semaphoretimeout || 0;
if(defined $::opt_semaphorename) {
$Semaphore::name = $::opt_semaphorename;
} else {
$Semaphore::name = `tty`;
chomp $Semaphore::name;
}
$Semaphore::fg = $::opt_fg;
$Semaphore::wait = $::opt_wait;
$Global::default_simultaneous_sshlogins = 1;
}
# Needs to be done after setting $Global::command and $Global::command_line_max_len # Needs to be done after setting $Global::command and $Global::command_line_max_len
# as '-m' influences the number of commands that needs to be run # as '-m' influences the number of commands that needs to be run
if(defined $::opt_P) { if(defined $::opt_P) {
@ -2518,7 +2516,7 @@ sub trim {
# lr|rl = both # lr|rl = both
# Returns: # Returns:
# string with white space removed as needed # string with white space removed as needed
my (@strings) = (@_); my (@strings) = map { defined $_ ? $_ : "" } (@_);
my $arg; my $arg;
if($Global::trim eq "n") { if($Global::trim eq "n") {
# skip # skip
@ -3774,9 +3772,11 @@ sub more_arguments {
# Returns: # Returns:
# whether there are more arguments to be processed or not # whether there are more arguments to be processed or not
my $fh = shift || $Global::argfile; my $fh = shift || $Global::argfile;
return (@Global::unget_argv or @{$Global::unget_line{$fh}} or return (
@{$Global::unget_col{$fh}} or @Global::unget_arg or not @Global::unget_argv or
eof $fh); (defined $Global::unget_line{$fh} and @{$Global::unget_line{$fh}}) or
(defined $Global::unget_col{$fh} and @{$Global::unget_col{$fh}})
or @Global::unget_arg or not eof $fh);
} }
sub get_line_from_fh { sub get_line_from_fh {

View file

@ -24,16 +24,17 @@ sem -u -j2 'echo job2; sleep 0.5; echo job2'
sem --wait sem --wait
echo done echo done
echo '### Test similar example as from man page' echo '### Test similar example as from man page - run 2 jobs simultaneously'
for i in 0.5 0.1 0.2 0.3 0.4 ; do echo 'Expect done: 1 2 5 3 4'
echo $i for i in 5 1 2 3 4 ; do
sem -j+0 sleep $i ";" echo done $i echo Scheduling $i
sem -j2 -u echo starting $i ";" sleep $i ";" echo done $i
done done
sem --wait sem --wait
echo '### BUG: Test --fg followed by --bg' echo '### Test --fg followed by --bg'
parallel -u --fg --semaphore seq 1 10 '|' pv -qL 20 parallel -u --fg --semaphore seq 1 10 '|' pv -qL 30
parallel -u --bg --semaphore seq 11 20 '|' pv -qL 20 parallel -u --bg --semaphore seq 11 20 '|' pv -qL 30
parallel -u --fg --semaphore seq 21 30 '|' pv -qL 20 parallel -u --fg --semaphore seq 21 30 '|' pv -qL 30
parallel -u --bg --semaphore seq 31 40 '|' pv -qL 20 parallel -u --bg --semaphore seq 31 40 '|' pv -qL 30
sem --wait sem --wait

View file

@ -37,6 +37,12 @@ echo '### Test of tab as colsep'
printf 'def\tabc\njkl\tghi' | parallel -k --colsep '\t' echo {2} {1} printf 'def\tabc\njkl\tghi' | parallel -k --colsep '\t' echo {2} {1}
parallel -k -a <(printf 'def\tabc\njkl\tghi') --colsep '\t' echo {2} {1} parallel -k -a <(printf 'def\tabc\njkl\tghi') --colsep '\t' echo {2} {1}
echo '### Test of multiple -a plus colsep'
parallel -k -a <(printf 'def\njkl\n') -a <(printf 'abc\tghi\nmno\tpqr') --colsep '\t' echo {2} {1}
echo '### Test of multiple -a no colsep'
parallel -k -a <(printf 'ghi\npqr\n') -a <(printf 'abc\tdef\njkl\tmno') echo {2} {1}
echo '### Test of quoting after colsplit' echo '### Test of quoting after colsplit'
parallel --colsep % echo {2} {1} ::: '>/dev/null%>/tmp/null' parallel --colsep % echo {2} {1} ::: '>/dev/null%>/tmp/null'

View file

@ -0,0 +1,7 @@
#!/bin/bash
echo '### Test of --eta'
seq 1 10 | stdout parallel --eta "sleep 1; echo {}" | wc -l
echo '### Test of --progress'
seq 1 10 | stdout parallel --progress "sleep 1; echo {}" | wc -l

View file

@ -54,18 +54,24 @@ job2
job1 job1
job2 job2
done done
### Test similar example as from man page ### Test similar example as from man page - run 2 jobs simultaneously
0.5 Expect done: 1 2 5 3 4
0.1 Scheduling 5
0.2 Scheduling 1
done 0.1 starting 5
0.3 Scheduling 2
done 0.5 starting 1
0.4 done 1
done 0.2 Scheduling 3
done 0.3 starting 2
done 0.4 done 2
### BUG: Test --fg followed by --bg Scheduling 4
starting 3
done 5
starting 4
done 3
done 4
### Test --fg followed by --bg
1 1
2 2
3 3

View file

@ -38,6 +38,14 @@ abc def
ghi jkl ghi jkl
abc def abc def
ghi jkl ghi jkl
### Test of multiple -a plus colsep
abc def
ghi jkl
mno
pqr
### Test of multiple -a no colsep
abc def ghi
jkl mno pqr
### Test of quoting after colsplit ### Test of quoting after colsplit
>/tmp/null >/dev/null >/tmp/null >/dev/null
### Test of --colsep as regexp ### Test of --colsep as regexp

View file

@ -0,0 +1,4 @@
### Test of --eta
16
### Test of --progress
16