mirror of
https://git.savannah.gnu.org/git/parallel.git
synced 2024-11-22 05:57:54 +00:00
--eta was broken. Now fixed.
Race condition in sem fixed with setsid(). Passes unittest.
This commit is contained in:
parent
adff24a1a0
commit
0fbd1b2653
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
|
|
60
src/parallel
60
src/parallel
|
@ -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,8 +2077,8 @@ 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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'
|
||||||
|
|
||||||
|
|
7
unittest/tests-to-run/test30.sh
Normal file
7
unittest/tests-to-run/test30.sh
Normal 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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
4
unittest/wanted-results/test30
Normal file
4
unittest/wanted-results/test30
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
### Test of --eta
|
||||||
|
16
|
||||||
|
### Test of --progress
|
||||||
|
16
|
Loading…
Reference in a new issue