runtests: support creating more than one runner process
The controller currently only creates and uses one, but more are now possible. Ref: #10818
This commit is contained in:
parent
38465f9a55
commit
faebcee349
@ -126,12 +126,15 @@ my $CURLLOG="$LOGDIR/commands.log"; # all command lines run
|
|||||||
my $SERVERLOGS_LOCK="$LOGDIR/serverlogs.lock"; # server logs advisor read lock
|
my $SERVERLOGS_LOCK="$LOGDIR/serverlogs.lock"; # server logs advisor read lock
|
||||||
my $defserverlogslocktimeout = 2; # timeout to await server logs lock removal
|
my $defserverlogslocktimeout = 2; # timeout to await server logs lock removal
|
||||||
my $defpostcommanddelay = 0; # delay between command and postcheck sections
|
my $defpostcommanddelay = 0; # delay between command and postcheck sections
|
||||||
my $controllerw; # pipe that controller writes to
|
my $multiprocess; # nonzero with a separate test runner process
|
||||||
|
|
||||||
|
# pipes
|
||||||
my $runnerr; # pipe that runner reads from
|
my $runnerr; # pipe that runner reads from
|
||||||
my $runnerw; # pipe that runner writes to
|
my $runnerw; # pipe that runner writes to
|
||||||
my $controllerr; # pipe that controller reads from
|
|
||||||
my $multiprocess; # nonzero with a separate test runner process
|
# per-runner variables, indexed by runner ID; these are used by controller only
|
||||||
my $onerunnerid; # a single runner ID
|
my %controllerr; # pipe that controller reads from
|
||||||
|
my %controllerw; # pipe that controller writes to
|
||||||
|
|
||||||
# redirected stdout/stderr to these files
|
# redirected stdout/stderr to these files
|
||||||
sub stdoutfilename {
|
sub stdoutfilename {
|
||||||
@ -165,9 +168,11 @@ sub runner_init {
|
|||||||
$ENV{'COLUMNS'}=79; # screen width!
|
$ENV{'COLUMNS'}=79; # screen width!
|
||||||
|
|
||||||
# create pipes for communication with runner
|
# create pipes for communication with runner
|
||||||
pipe $runnerr, $controllerw;
|
my ($thisrunnerr, $thiscontrollerw, $thiscontrollerr, $thisrunnerw);
|
||||||
pipe $controllerr, $runnerw;
|
pipe $thisrunnerr, $thiscontrollerw;
|
||||||
|
pipe $thiscontrollerr, $thisrunnerw;
|
||||||
|
|
||||||
|
my $thisrunnerid;
|
||||||
if($multiprocess) {
|
if($multiprocess) {
|
||||||
# Create a separate process in multiprocess mode
|
# Create a separate process in multiprocess mode
|
||||||
my $child = fork();
|
my $child = fork();
|
||||||
@ -176,12 +181,14 @@ sub runner_init {
|
|||||||
$SIG{INT} = 'IGNORE';
|
$SIG{INT} = 'IGNORE';
|
||||||
$SIG{TERM} = 'IGNORE';
|
$SIG{TERM} = 'IGNORE';
|
||||||
|
|
||||||
$onerunnerid = $$;
|
$thisrunnerid = $$;
|
||||||
print "Runner $onerunnerid starting\n" if($verbose);
|
print "Runner $thisrunnerid starting\n" if($verbose);
|
||||||
|
|
||||||
# Here we are the child (runner).
|
# Here we are the child (runner).
|
||||||
close($controllerw);
|
close($thiscontrollerw);
|
||||||
close($controllerr);
|
close($thiscontrollerr);
|
||||||
|
$runnerr = $thisrunnerr;
|
||||||
|
$runnerw = $thisrunnerw;
|
||||||
|
|
||||||
# Set this directory as ours
|
# Set this directory as ours
|
||||||
$LOGDIR = $logdir;
|
$LOGDIR = $logdir;
|
||||||
@ -191,25 +198,30 @@ sub runner_init {
|
|||||||
event_loop();
|
event_loop();
|
||||||
|
|
||||||
# Can't rely on logmsg here in case it's buffered
|
# Can't rely on logmsg here in case it's buffered
|
||||||
print "Runner $onerunnerid exiting\n" if($verbose);
|
print "Runner $thisrunnerid exiting\n" if($verbose);
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Here we are the parent (controller).
|
# Here we are the parent (controller).
|
||||||
close($runnerw);
|
close($thisrunnerw);
|
||||||
close($runnerr);
|
close($thisrunnerr);
|
||||||
|
|
||||||
$onerunnerid = $child;
|
$thisrunnerid = $child;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
# Create our pid directory
|
# Create our pid directory
|
||||||
mkdir("$LOGDIR/$PIDDIR", 0777);
|
mkdir("$LOGDIR/$PIDDIR", 0777);
|
||||||
|
|
||||||
# Don't create a separate process
|
# Don't create a separate process
|
||||||
$onerunnerid = "integrated";
|
$thisrunnerid = "integrated";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $onerunnerid;
|
$controllerw{$thisrunnerid} = $thiscontrollerw;
|
||||||
|
$runnerr = $thisrunnerr;
|
||||||
|
$runnerw = $thisrunnerw;
|
||||||
|
$controllerr{$thisrunnerid} = $thiscontrollerr;
|
||||||
|
|
||||||
|
return $thisrunnerid;
|
||||||
}
|
}
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
@ -1132,13 +1144,14 @@ sub runnerac_clearlocks {
|
|||||||
# received.
|
# received.
|
||||||
# Called by controller
|
# Called by controller
|
||||||
sub runnerac_shutdown {
|
sub runnerac_shutdown {
|
||||||
|
my ($runnerid)=$_[0];
|
||||||
controlleripccall(\&runner_shutdown, @_);
|
controlleripccall(\&runner_shutdown, @_);
|
||||||
|
|
||||||
# These have no more use
|
# These have no more use
|
||||||
close($controllerw);
|
close($controllerw{$runnerid});
|
||||||
undef $controllerw;
|
undef $controllerw{$runnerid};
|
||||||
close($controllerr);
|
close($controllerr{$runnerid});
|
||||||
undef $controllerr;
|
undef $controllerr{$runnerid};
|
||||||
}
|
}
|
||||||
|
|
||||||
# Async call of runner_stopservers
|
# Async call of runner_stopservers
|
||||||
@ -1175,7 +1188,7 @@ sub controlleripccall {
|
|||||||
my $margs = freeze \@_;
|
my $margs = freeze \@_;
|
||||||
|
|
||||||
# Send IPC call via pipe
|
# Send IPC call via pipe
|
||||||
syswrite($controllerw, (pack "L", length($margs)) . $margs);
|
syswrite($controllerw{$runnerid}, (pack "L", length($margs)) . $margs);
|
||||||
|
|
||||||
if(!$multiprocess) {
|
if(!$multiprocess) {
|
||||||
# Call the remote function here in single process mode
|
# Call the remote function here in single process mode
|
||||||
@ -1188,13 +1201,14 @@ sub controlleripccall {
|
|||||||
# The first return value is the runner ID
|
# The first return value is the runner ID
|
||||||
# Called by controller
|
# Called by controller
|
||||||
sub runnerar {
|
sub runnerar {
|
||||||
|
my ($runnerid) = @_;
|
||||||
my $datalen;
|
my $datalen;
|
||||||
if (sysread($controllerr, $datalen, 4) <= 0) {
|
if (sysread($controllerr{$runnerid}, $datalen, 4) <= 0) {
|
||||||
die "error in runnerar\n";
|
die "error in runnerar\n";
|
||||||
}
|
}
|
||||||
my $len=unpack("L", $datalen);
|
my $len=unpack("L", $datalen);
|
||||||
my $buf;
|
my $buf;
|
||||||
if (sysread($controllerr, $buf, $len) <= 0) {
|
if (sysread($controllerr{$runnerid}, $buf, $len) <= 0) {
|
||||||
die "error in runnerar\n";
|
die "error in runnerar\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1202,19 +1216,41 @@ sub runnerar {
|
|||||||
my $resarrayref = thaw $buf;
|
my $resarrayref = thaw $buf;
|
||||||
|
|
||||||
# First argument is runner ID
|
# First argument is runner ID
|
||||||
unshift @$resarrayref, $onerunnerid;
|
# TODO: remove this; it's unneeded since it's passed in
|
||||||
|
unshift @$resarrayref, $runnerid;
|
||||||
return @$resarrayref;
|
return @$resarrayref;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################################################
|
###################################################################
|
||||||
# Returns nonzero if a response from an async call is ready
|
# Returns runnder ID if a response from an async call is ready
|
||||||
# argument is 0 for nonblocking, undef for blocking, anything else for timeout
|
# argument is 0 for nonblocking, undef for blocking, anything else for timeout
|
||||||
# Called by controller
|
# Called by controller
|
||||||
sub runnerar_ready {
|
sub runnerar_ready {
|
||||||
my ($blocking) = @_;
|
my ($blocking) = @_;
|
||||||
my $rin = "";
|
my $rin = "";
|
||||||
vec($rin, fileno($controllerr), 1) = 1;
|
my %idbyfileno;
|
||||||
return select(my $rout=$rin, undef, my $eout=$rin, $blocking);
|
my $maxfileno=0;
|
||||||
|
foreach my $p (keys(%controllerr)) {
|
||||||
|
my $fd = fileno($controllerr{$p});
|
||||||
|
vec($rin, $fd, 1) = 1;
|
||||||
|
$idbyfileno{$fd} = $p; # save the runner ID for each pipe fd
|
||||||
|
if($fd > $maxfileno) {
|
||||||
|
$maxfileno = $fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wait for any pipe from any runner to be ready
|
||||||
|
# TODO: this is relatively slow with hundreds of fds
|
||||||
|
# TODO: handle errors
|
||||||
|
if(select(my $rout=$rin, undef, undef, $blocking)) {
|
||||||
|
for my $fd (0..$maxfileno) {
|
||||||
|
if(vec($rin, $fd, 1)) {
|
||||||
|
return $idbyfileno{$fd};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
die "Internal pipe readiness inconsistency\n";
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################################################
|
###################################################################
|
||||||
|
|||||||
@ -1418,7 +1418,10 @@ sub singletest_check {
|
|||||||
logmsg "ERROR: section verify=>file$partsuffix ".
|
logmsg "ERROR: section verify=>file$partsuffix ".
|
||||||
"has no name attribute\n";
|
"has no name attribute\n";
|
||||||
runnerac_stopservers($runnerid);
|
runnerac_stopservers($runnerid);
|
||||||
my ($rid, $unexpected, $logs) = runnerar();
|
# TODO: this is a blocking call that will stall the controller,
|
||||||
|
# but this error condition should never happen except during
|
||||||
|
# development.
|
||||||
|
my ($rid, $unexpected, $logs) = runnerar($runnerid);
|
||||||
logmsg $logs;
|
logmsg $logs;
|
||||||
# timestamp test result verification end
|
# timestamp test result verification end
|
||||||
$timevrfyend{$testnum} = Time::HiRes::time();
|
$timevrfyend{$testnum} = Time::HiRes::time();
|
||||||
@ -1650,7 +1653,7 @@ sub singletest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} elsif($singletest_state == ST_CLEARLOCKS) {
|
} elsif($singletest_state == ST_CLEARLOCKS) {
|
||||||
my ($rid, $logs) = runnerar();
|
my ($rid, $logs) = runnerar($runnerid);
|
||||||
logmsg $logs;
|
logmsg $logs;
|
||||||
my $logdir = getlogdir($testnum);
|
my $logdir = getlogdir($testnum);
|
||||||
cleardir($logdir);
|
cleardir($logdir);
|
||||||
@ -1680,7 +1683,7 @@ sub singletest {
|
|||||||
$singletest_state = ST_PREPROCESS;
|
$singletest_state = ST_PREPROCESS;
|
||||||
|
|
||||||
} elsif($singletest_state == ST_PREPROCESS) {
|
} elsif($singletest_state == ST_PREPROCESS) {
|
||||||
my ($rid, $why, $error, $logs, $testtimings) = runnerar();
|
my ($rid, $why, $error, $logs, $testtimings) = runnerar($runnerid);
|
||||||
logmsg $logs;
|
logmsg $logs;
|
||||||
if($error == -2) {
|
if($error == -2) {
|
||||||
if($postmortem) {
|
if($postmortem) {
|
||||||
@ -1716,7 +1719,7 @@ sub singletest {
|
|||||||
$singletest_state = ST_RUN;
|
$singletest_state = ST_RUN;
|
||||||
|
|
||||||
} elsif($singletest_state == ST_RUN) {
|
} elsif($singletest_state == ST_RUN) {
|
||||||
my ($rid, $error, $logs, $testtimings, $cmdres, $CURLOUT, $tool, $usedvalgrind) = runnerar();
|
my ($rid, $error, $logs, $testtimings, $cmdres, $CURLOUT, $tool, $usedvalgrind) = runnerar($runnerid);
|
||||||
logmsg $logs;
|
logmsg $logs;
|
||||||
updatetesttimings($testnum, %$testtimings);
|
updatetesttimings($testnum, %$testtimings);
|
||||||
if($error == -1) {
|
if($error == -1) {
|
||||||
@ -2607,7 +2610,7 @@ foreach my $testnum (@runtests) {
|
|||||||
# Wait for the last request to complete and throw it away so
|
# Wait for the last request to complete and throw it away so
|
||||||
# that IPC calls & responses stay in sync
|
# that IPC calls & responses stay in sync
|
||||||
# TODO: send a signal to the runner to interrupt a long test
|
# TODO: send a signal to the runner to interrupt a long test
|
||||||
runnerar();
|
runnerar(runnerar_ready());
|
||||||
}
|
}
|
||||||
last nexttest;
|
last nexttest;
|
||||||
}
|
}
|
||||||
@ -2670,7 +2673,7 @@ citest_finishtestrun();
|
|||||||
|
|
||||||
# Tests done, stop the servers
|
# Tests done, stop the servers
|
||||||
runnerac_stopservers($runnerid);
|
runnerac_stopservers($runnerid);
|
||||||
my ($rid, $unexpected, $logs) = runnerar();
|
my ($rid, $unexpected, $logs) = runnerar($runnerid);
|
||||||
logmsg $logs;
|
logmsg $logs;
|
||||||
|
|
||||||
# Kill the runner
|
# Kill the runner
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user