runner.pm 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534
  1. #***************************************************************************
  2. # _ _ ____ _
  3. # Project ___| | | | _ \| |
  4. # / __| | | | |_) | |
  5. # | (__| |_| | _ <| |___
  6. # \___|\___/|_| \_\_____|
  7. #
  8. # Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  9. #
  10. # This software is licensed as described in the file COPYING, which
  11. # you should have received as part of this distribution. The terms
  12. # are also available at https://curl.se/docs/copyright.html.
  13. #
  14. # You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. # copies of the Software, and permit persons to whom the Software is
  16. # furnished to do so, under the terms of the COPYING file.
  17. #
  18. # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. # KIND, either express or implied.
  20. #
  21. # SPDX-License-Identifier: curl
  22. #
  23. ###########################################################################
  24. # This module contains entry points to run a single test. runner_init
  25. # determines whether they will run in a separate process or in the process of
  26. # the caller. The relevant interface is asynchronous so it will work in either
  27. # case. Program arguments are marshalled and then written to the end of a pipe
  28. # (in controlleripccall) which is later read from and the arguments
  29. # unmarshalled (in ipcrecv) before the desired function is called normally.
  30. # The function return values are then marshalled and written into another pipe
  31. # (again in ipcrecv) when is later read from and unmarshalled (in runnerar)
  32. # before being returned to the caller.
  33. package runner;
  34. use strict;
  35. use warnings;
  36. use 5.006;
  37. BEGIN {
  38. use base qw(Exporter);
  39. our @EXPORT = qw(
  40. checktestcmd
  41. prepro
  42. readtestkeywords
  43. restore_test_env
  44. runner_init
  45. runnerac_clearlocks
  46. runnerac_shutdown
  47. runnerac_stopservers
  48. runnerac_test_preprocess
  49. runnerac_test_run
  50. runnerar
  51. runnerar_ready
  52. stderrfilename
  53. stdoutfilename
  54. $DBGCURL
  55. $gdb
  56. $gdbthis
  57. $gdbxwin
  58. $shallow
  59. $tortalloc
  60. $valgrind_logfile
  61. $valgrind_tool
  62. );
  63. # these are for debugging only
  64. our @EXPORT_OK = qw(
  65. singletest_preprocess
  66. );
  67. }
  68. use B qw(
  69. svref_2object
  70. );
  71. use Storable qw(
  72. freeze
  73. thaw
  74. );
  75. use pathhelp qw(
  76. exe_ext
  77. );
  78. use processhelp qw(
  79. portable_sleep
  80. );
  81. use servers qw(
  82. checkcmd
  83. clearlocks
  84. initserverconfig
  85. serverfortest
  86. stopserver
  87. stopservers
  88. subvariables
  89. );
  90. use getpart;
  91. use globalconfig;
  92. use testutil qw(
  93. clearlogs
  94. logmsg
  95. runclient
  96. shell_quote
  97. subbase64
  98. subsha256base64file
  99. substrippemfile
  100. subnewlines
  101. );
  102. use valgrind;
  103. #######################################################################
  104. # Global variables set elsewhere but used only by this package
  105. # These may only be set *before* runner_init is called
  106. our $DBGCURL=$CURL; #"../src/.libs/curl"; # alternative for debugging
  107. our $valgrind_logfile="--log-file"; # the option name for valgrind >=3
  108. our $valgrind_tool="--tool=memcheck";
  109. our $gdb = checktestcmd("gdb");
  110. our $gdbthis = 0; # run test case with debugger (gdb or lldb)
  111. our $gdbxwin; # use windowed gdb when using gdb
  112. # torture test variables
  113. our $shallow;
  114. our $tortalloc;
  115. # local variables
  116. my %oldenv; # environment variables before test is started
  117. my $UNITDIR="./unit";
  118. my $CURLLOG="$LOGDIR/commands.log"; # all command lines run
  119. my $defserverlogslocktimeout = 5; # timeout to await server logs lock removal
  120. my $defpostcommanddelay = 0; # delay between command and postcheck sections
  121. my $multiprocess; # nonzero with a separate test runner process
  122. # pipes
  123. my $runnerr; # pipe that runner reads from
  124. my $runnerw; # pipe that runner writes to
  125. # per-runner variables, indexed by runner ID; these are used by controller only
  126. my %controllerr; # pipe that controller reads from
  127. my %controllerw; # pipe that controller writes to
  128. # redirected stdout/stderr to these files
  129. sub stdoutfilename {
  130. my ($logdir, $testnum)=@_;
  131. return "$logdir/stdout$testnum";
  132. }
  133. sub stderrfilename {
  134. my ($logdir, $testnum)=@_;
  135. return "$logdir/stderr$testnum";
  136. }
  137. #######################################################################
  138. # Initialize the runner and prepare it to run tests
  139. # The runner ID returned by this function must be passed into the other
  140. # runnerac_* functions
  141. # Called by controller
  142. sub runner_init {
  143. my ($logdir, $jobs)=@_;
  144. $multiprocess = !!$jobs;
  145. # enable memory debugging if curl is compiled with it
  146. $ENV{'CURL_MEMDEBUG'} = "$logdir/$MEMDUMP";
  147. $ENV{'CURL_ENTROPY'}="12345678";
  148. $ENV{'CURL_FORCETIME'}=1; # for debug NTLM magic
  149. $ENV{'CURL_GLOBAL_INIT'}=1; # debug curl_global_init/cleanup use
  150. $ENV{'HOME'}=$pwd;
  151. $ENV{'CURL_HOME'}=$ENV{'HOME'};
  152. $ENV{'XDG_CONFIG_HOME'}=$ENV{'HOME'};
  153. $ENV{'COLUMNS'}=79; # screen width!
  154. # Incorporate the $logdir into the random seed and re-seed the PRNG.
  155. # This gives each runner a unique yet consistent seed which provides
  156. # more unique port number selection in each runner, yet is deterministic
  157. # across runs.
  158. $randseed += unpack('%16C*', $logdir);
  159. srand $randseed;
  160. # create pipes for communication with runner
  161. my ($thisrunnerr, $thiscontrollerw, $thiscontrollerr, $thisrunnerw);
  162. pipe $thisrunnerr, $thiscontrollerw;
  163. pipe $thiscontrollerr, $thisrunnerw;
  164. my $thisrunnerid;
  165. if($multiprocess) {
  166. # Create a separate process in multiprocess mode
  167. my $child = fork();
  168. if(0 == $child) {
  169. # TODO: set up better signal handlers
  170. $SIG{INT} = 'IGNORE';
  171. $SIG{TERM} = 'IGNORE';
  172. eval {
  173. # some msys2 perl versions don't define SIGUSR1
  174. $SIG{USR1} = 'IGNORE';
  175. };
  176. $thisrunnerid = $$;
  177. print "Runner $thisrunnerid starting\n" if($verbose);
  178. # Here we are the child (runner).
  179. close($thiscontrollerw);
  180. close($thiscontrollerr);
  181. $runnerr = $thisrunnerr;
  182. $runnerw = $thisrunnerw;
  183. # Set this directory as ours
  184. $LOGDIR = $logdir;
  185. mkdir("$LOGDIR/$PIDDIR", 0777);
  186. mkdir("$LOGDIR/$LOCKDIR", 0777);
  187. # Initialize various server variables
  188. initserverconfig();
  189. # handle IPC calls
  190. event_loop();
  191. # Can't rely on logmsg here in case it's buffered
  192. print "Runner $thisrunnerid exiting\n" if($verbose);
  193. # To reach this point, either the controller has sent
  194. # runnerac_stopservers() and runnerac_shutdown() or we have called
  195. # runnerabort(). In both cases, there are no more of our servers
  196. # running and we can safely exit.
  197. exit 0;
  198. }
  199. # Here we are the parent (controller).
  200. close($thisrunnerw);
  201. close($thisrunnerr);
  202. $thisrunnerid = $child;
  203. } else {
  204. # Create our pid directory
  205. mkdir("$LOGDIR/$PIDDIR", 0777);
  206. # Don't create a separate process
  207. $thisrunnerid = "integrated";
  208. }
  209. $controllerw{$thisrunnerid} = $thiscontrollerw;
  210. $runnerr = $thisrunnerr;
  211. $runnerw = $thisrunnerw;
  212. $controllerr{$thisrunnerid} = $thiscontrollerr;
  213. return $thisrunnerid;
  214. }
  215. #######################################################################
  216. # Loop to execute incoming IPC calls until the shutdown call
  217. sub event_loop {
  218. while () {
  219. if(ipcrecv()) {
  220. last;
  221. }
  222. }
  223. }
  224. #######################################################################
  225. # Check for a command in the PATH of the machine running curl.
  226. #
  227. sub checktestcmd {
  228. my ($cmd)=@_;
  229. my @testpaths=("$LIBDIR/.libs", "$LIBDIR");
  230. return checkcmd($cmd, @testpaths);
  231. }
  232. # See if Valgrind should actually be used
  233. sub use_valgrind {
  234. if($valgrind) {
  235. my @valgrindoption = getpart("verify", "valgrind");
  236. if((!@valgrindoption) || ($valgrindoption[0] !~ /disable/)) {
  237. return 1;
  238. }
  239. }
  240. return 0;
  241. }
  242. # Massage the command result code into a useful form
  243. sub normalize_cmdres {
  244. my $cmdres = $_[0];
  245. my $signal_num = $cmdres & 127;
  246. my $dumped_core = $cmdres & 128;
  247. if(!$anyway && ($signal_num || $dumped_core)) {
  248. $cmdres = 1000;
  249. }
  250. else {
  251. $cmdres >>= 8;
  252. $cmdres = (2000 + $signal_num) if($signal_num && !$cmdres);
  253. }
  254. return ($cmdres, $dumped_core);
  255. }
  256. # 'prepro' processes the input array and replaces %-variables in the array
  257. # etc. Returns the processed version of the array
  258. sub prepro {
  259. my $testnum = shift;
  260. my (@entiretest) = @_;
  261. my $show = 1;
  262. my @out;
  263. my $data_crlf;
  264. my @pshow;
  265. my @altshow;
  266. my $plvl;
  267. my $line;
  268. for my $s (@entiretest) {
  269. my $f = $s;
  270. $line++;
  271. if($s =~ /^ *%if ([A-Za-z0-9!_-]*)/) {
  272. my $cond = $1;
  273. my $rev = 0;
  274. if($cond =~ /^!(.*)/) {
  275. $cond = $1;
  276. $rev = 1;
  277. }
  278. $rev ^= $feature{$cond} ? 1 : 0;
  279. push @pshow, $show; # push the previous state
  280. $plvl++;
  281. if($show) {
  282. # only if this was showing before we can allow the alternative
  283. # to go showing as well
  284. push @altshow, $rev ^ 1; # push the reversed show state
  285. }
  286. else {
  287. push @altshow, 0; # the alt should still hide
  288. }
  289. if($show) {
  290. # we only allow show if already showing
  291. $show = $rev;
  292. }
  293. next;
  294. }
  295. elsif($s =~ /^ *%else/) {
  296. if(!$plvl) {
  297. print STDERR "error: test$testnum:$line: %else no %if\n";
  298. last;
  299. }
  300. $show = pop @altshow;
  301. push @altshow, $show; # put it back for consistency
  302. next;
  303. }
  304. elsif($s =~ /^ *%endif/) {
  305. if(!$plvl--) {
  306. print STDERR "error: test$testnum:$line: %endif had no %if\n";
  307. last;
  308. }
  309. $show = pop @pshow;
  310. pop @altshow; # not used here but we must pop it
  311. next;
  312. }
  313. if($show) {
  314. # The processor does CRLF replacements in the <data*> sections if
  315. # necessary since those parts might be read by separate servers.
  316. if($s =~ /^ *<data(.*)\>/) {
  317. if($1 =~ /crlf="yes"/ ||
  318. ($feature{"hyper"} && ($keywords{"HTTP"} || $keywords{"HTTPS"}))) {
  319. $data_crlf = 1;
  320. }
  321. }
  322. elsif(($s =~ /^ *<\/data/) && $data_crlf) {
  323. $data_crlf = 0;
  324. }
  325. subvariables(\$s, $testnum, "%");
  326. subbase64(\$s);
  327. subsha256base64file(\$s);
  328. substrippemfile(\$s);
  329. subnewlines(0, \$s) if($data_crlf);
  330. push @out, $s;
  331. }
  332. }
  333. return @out;
  334. }
  335. #######################################################################
  336. # Load test keywords into %keywords hash
  337. #
  338. sub readtestkeywords {
  339. my @info_keywords = getpart("info", "keywords");
  340. # Clear the list of keywords from the last test
  341. %keywords = ();
  342. for my $k (@info_keywords) {
  343. chomp $k;
  344. $keywords{$k} = 1;
  345. }
  346. }
  347. #######################################################################
  348. # Return a list of log locks that still exist
  349. #
  350. sub logslocked {
  351. opendir(my $lockdir, "$LOGDIR/$LOCKDIR");
  352. my @locks;
  353. foreach (readdir $lockdir) {
  354. if(/^(.*)\.lock$/) {
  355. push @locks, $1;
  356. }
  357. }
  358. return @locks;
  359. }
  360. #######################################################################
  361. # Wait log locks to be unlocked
  362. #
  363. sub waitlockunlock {
  364. # If a server logs advisor read lock file exists, it is an indication
  365. # that the server has not yet finished writing out all its log files,
  366. # including server request log files used for protocol verification.
  367. # So, if the lock file exists the script waits here a certain amount
  368. # of time until the server removes it, or the given time expires.
  369. my $serverlogslocktimeout = shift;
  370. if($serverlogslocktimeout) {
  371. my $lockretry = $serverlogslocktimeout * 20;
  372. my @locks;
  373. while((@locks = logslocked()) && $lockretry--) {
  374. portable_sleep(0.05);
  375. }
  376. if(($lockretry < 0) &&
  377. ($serverlogslocktimeout >= $defserverlogslocktimeout)) {
  378. logmsg "Warning: server logs lock timeout ",
  379. "($serverlogslocktimeout seconds) expired (locks: " .
  380. join(", ", @locks) . ")\n";
  381. }
  382. }
  383. }
  384. #######################################################################
  385. # Memory allocation test and failure torture testing.
  386. #
  387. sub torture {
  388. my ($testcmd, $testnum, $gdbline) = @_;
  389. # remove memdump first to be sure we get a new nice and clean one
  390. unlink("$LOGDIR/$MEMDUMP");
  391. # First get URL from test server, ignore the output/result
  392. runclient($testcmd);
  393. logmsg " CMD: $testcmd\n" if($verbose);
  394. # memanalyze -v is our friend, get the number of allocations made
  395. my $count=0;
  396. my @out = `$memanalyze -v "$LOGDIR/$MEMDUMP"`;
  397. for(@out) {
  398. if(/^Operations: (\d+)/) {
  399. $count = $1;
  400. last;
  401. }
  402. }
  403. if(!$count) {
  404. logmsg " found no functions to make fail\n";
  405. return 0;
  406. }
  407. my @ttests = (1 .. $count);
  408. if($shallow && ($shallow < $count)) {
  409. my $discard = scalar(@ttests) - $shallow;
  410. my $percent = sprintf("%.2f%%", $shallow * 100 / scalar(@ttests));
  411. logmsg " $count functions found, but only fail $shallow ($percent)\n";
  412. while($discard) {
  413. my $rm;
  414. do {
  415. # find a test to discard
  416. $rm = rand(scalar(@ttests));
  417. } while(!$ttests[$rm]);
  418. $ttests[$rm] = undef;
  419. $discard--;
  420. }
  421. }
  422. else {
  423. logmsg " $count functions to make fail\n";
  424. }
  425. for (@ttests) {
  426. my $limit = $_;
  427. my $fail;
  428. my $dumped_core;
  429. if(!defined($limit)) {
  430. # --shallow can undefine them
  431. next;
  432. }
  433. if($tortalloc && ($tortalloc != $limit)) {
  434. next;
  435. }
  436. if($verbose) {
  437. my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
  438. localtime(time());
  439. my $now = sprintf("%02d:%02d:%02d ", $hour, $min, $sec);
  440. logmsg "Fail function no: $limit at $now\r";
  441. }
  442. # make the memory allocation function number $limit return failure
  443. $ENV{'CURL_MEMLIMIT'} = $limit;
  444. # remove memdump first to be sure we get a new nice and clean one
  445. unlink("$LOGDIR/$MEMDUMP");
  446. my $cmd = $testcmd;
  447. if($valgrind && !$gdbthis) {
  448. my @valgrindoption = getpart("verify", "valgrind");
  449. if((!@valgrindoption) || ($valgrindoption[0] !~ /disable/)) {
  450. my $valgrindcmd = "$valgrind ";
  451. $valgrindcmd .= "$valgrind_tool " if($valgrind_tool);
  452. $valgrindcmd .= "--quiet --leak-check=yes ";
  453. $valgrindcmd .= "--suppressions=$srcdir/valgrind.supp ";
  454. # $valgrindcmd .= "--gen-suppressions=all ";
  455. $valgrindcmd .= "--num-callers=16 ";
  456. $valgrindcmd .= "${valgrind_logfile}=$LOGDIR/valgrind$testnum";
  457. $cmd = "$valgrindcmd $testcmd";
  458. }
  459. }
  460. logmsg "*** Function number $limit is now set to fail ***\n" if($gdbthis);
  461. my $ret = 0;
  462. if($gdbthis) {
  463. runclient($gdbline);
  464. }
  465. else {
  466. $ret = runclient($cmd);
  467. }
  468. #logmsg "$_ Returned " . ($ret >> 8) . "\n";
  469. # Now clear the variable again
  470. delete $ENV{'CURL_MEMLIMIT'} if($ENV{'CURL_MEMLIMIT'});
  471. if(-r "core") {
  472. # there's core file present now!
  473. logmsg " core dumped\n";
  474. $dumped_core = 1;
  475. $fail = 2;
  476. }
  477. if($valgrind) {
  478. my @e = valgrindparse("$LOGDIR/valgrind$testnum");
  479. if(@e && $e[0]) {
  480. if($automakestyle) {
  481. logmsg "FAIL: torture $testnum - valgrind\n";
  482. }
  483. else {
  484. logmsg " valgrind ERROR ";
  485. logmsg @e;
  486. }
  487. $fail = 1;
  488. }
  489. }
  490. # verify that it returns a proper error code, doesn't leak memory
  491. # and doesn't core dump
  492. if(($ret & 255) || ($ret >> 8) >= 128) {
  493. logmsg " system() returned $ret\n";
  494. $fail=1;
  495. }
  496. else {
  497. my @memdata=`$memanalyze "$LOGDIR/$MEMDUMP"`;
  498. my $leak=0;
  499. for(@memdata) {
  500. if($_ ne "") {
  501. # well it could be other memory problems as well, but
  502. # we call it leak for short here
  503. $leak=1;
  504. }
  505. }
  506. if($leak) {
  507. logmsg "** MEMORY FAILURE\n";
  508. logmsg @memdata;
  509. logmsg `$memanalyze -l "$LOGDIR/$MEMDUMP"`;
  510. $fail = 1;
  511. }
  512. }
  513. if($fail) {
  514. logmsg " $testnum: torture FAILED: function number $limit in test.\n",
  515. " invoke with \"-t$limit\" to repeat this single case.\n";
  516. stopservers($verbose);
  517. return 1;
  518. }
  519. }
  520. logmsg "\n" if($verbose);
  521. logmsg "torture OK\n";
  522. return 0;
  523. }
  524. #######################################################################
  525. # restore environment variables that were modified in test
  526. sub restore_test_env {
  527. my $deleteoldenv = $_[0]; # 1 to delete the saved contents after restore
  528. foreach my $var (keys %oldenv) {
  529. if($oldenv{$var} eq 'notset') {
  530. delete $ENV{$var} if($ENV{$var});
  531. }
  532. else {
  533. $ENV{$var} = $oldenv{$var};
  534. }
  535. if($deleteoldenv) {
  536. delete $oldenv{$var};
  537. }
  538. }
  539. }
  540. #######################################################################
  541. # Start the servers needed to run this test case
  542. sub singletest_startservers {
  543. my ($testnum, $testtimings) = @_;
  544. # remove old test server files before servers are started/verified
  545. unlink("$LOGDIR/$SERVERCMD");
  546. unlink("$LOGDIR/$SERVERIN");
  547. unlink("$LOGDIR/$PROXYIN");
  548. # timestamp required servers verification start
  549. $$testtimings{"timesrvrini"} = Time::HiRes::time();
  550. my $why;
  551. my $error;
  552. if (!$listonly) {
  553. my @what = getpart("client", "server");
  554. if(!$what[0]) {
  555. warn "Test case $testnum has no server(s) specified";
  556. $why = "no server specified";
  557. $error = -1;
  558. } else {
  559. my $err;
  560. ($why, $err) = serverfortest(@what);
  561. if($err == 1) {
  562. # Error indicates an actual problem starting the server
  563. $error = -2;
  564. } else {
  565. $error = -1;
  566. }
  567. }
  568. }
  569. # timestamp required servers verification end
  570. $$testtimings{"timesrvrend"} = Time::HiRes::time();
  571. return ($why, $error);
  572. }
  573. #######################################################################
  574. # Generate preprocessed test file
  575. sub singletest_preprocess {
  576. my $testnum = $_[0];
  577. # Save a preprocessed version of the entire test file. This allows more
  578. # "basic" test case readers to enjoy variable replacements.
  579. my @entiretest = fulltest();
  580. my $otest = "$LOGDIR/test$testnum";
  581. @entiretest = prepro($testnum, @entiretest);
  582. # save the new version
  583. open(my $fulltesth, ">", "$otest") || die "Failure writing test file";
  584. foreach my $bytes (@entiretest) {
  585. print $fulltesth pack('a*', $bytes) or die "Failed to print '$bytes': $!";
  586. }
  587. close($fulltesth) || die "Failure writing test file";
  588. # in case the process changed the file, reload it
  589. loadtest("$LOGDIR/test${testnum}");
  590. }
  591. #######################################################################
  592. # Set up the test environment to run this test case
  593. sub singletest_setenv {
  594. my @setenv = getpart("client", "setenv");
  595. foreach my $s (@setenv) {
  596. chomp $s;
  597. if($s =~ /([^=]*)(.*)/) {
  598. my ($var, $content) = ($1, $2);
  599. # remember current setting, to restore it once test runs
  600. $oldenv{$var} = ($ENV{$var})?"$ENV{$var}":'notset';
  601. if($content =~ /^=(.*)/) {
  602. # assign it
  603. $content = $1;
  604. if($var =~ /^LD_PRELOAD/) {
  605. if(exe_ext('TOOL') && (exe_ext('TOOL') eq '.exe')) {
  606. logmsg "Skipping LD_PRELOAD due to lack of OS support\n" if($verbose);
  607. next;
  608. }
  609. if($feature{"Debug"} || !$has_shared) {
  610. logmsg "Skipping LD_PRELOAD due to no release shared build\n" if($verbose);
  611. next;
  612. }
  613. }
  614. $ENV{$var} = "$content";
  615. logmsg "setenv $var = $content\n" if($verbose);
  616. }
  617. else {
  618. # remove it
  619. delete $ENV{$var} if($ENV{$var});
  620. }
  621. }
  622. }
  623. if($proxy_address) {
  624. $ENV{http_proxy} = $proxy_address;
  625. $ENV{HTTPS_PROXY} = $proxy_address;
  626. }
  627. }
  628. #######################################################################
  629. # Check that test environment is fine to run this test case
  630. sub singletest_precheck {
  631. my $testnum = $_[0];
  632. my $why;
  633. my @precheck = getpart("client", "precheck");
  634. if(@precheck) {
  635. my $cmd = $precheck[0];
  636. chomp $cmd;
  637. if($cmd) {
  638. my @p = split(/ /, $cmd);
  639. if($p[0] !~ /\//) {
  640. # the first word, the command, does not contain a slash so
  641. # we will scan the "improved" PATH to find the command to
  642. # be able to run it
  643. my $fullp = checktestcmd($p[0]);
  644. if($fullp) {
  645. $p[0] = $fullp;
  646. }
  647. $cmd = join(" ", @p);
  648. }
  649. my @o = `$cmd 2> $LOGDIR/precheck-$testnum`;
  650. if($o[0]) {
  651. $why = $o[0];
  652. $why =~ s/[\r\n]//g;
  653. }
  654. elsif($?) {
  655. $why = "precheck command error";
  656. }
  657. logmsg "prechecked $cmd\n" if($verbose);
  658. }
  659. }
  660. return $why;
  661. }
  662. #######################################################################
  663. # Prepare the test environment to run this test case
  664. sub singletest_prepare {
  665. my ($testnum) = @_;
  666. if($feature{"TrackMemory"}) {
  667. unlink("$LOGDIR/$MEMDUMP");
  668. }
  669. unlink("core");
  670. # remove server output logfiles after servers are started/verified
  671. unlink("$LOGDIR/$SERVERIN");
  672. unlink("$LOGDIR/$PROXYIN");
  673. # if this section exists, it might be FTP server instructions:
  674. my @ftpservercmd = getpart("reply", "servercmd");
  675. push @ftpservercmd, "Testnum $testnum\n";
  676. # write the instructions to file
  677. writearray("$LOGDIR/$SERVERCMD", \@ftpservercmd);
  678. # create (possibly-empty) files before starting the test
  679. for my $partsuffix (('', '1', '2', '3', '4')) {
  680. my @inputfile=getpart("client", "file".$partsuffix);
  681. my %fileattr = getpartattr("client", "file".$partsuffix);
  682. my $filename=$fileattr{'name'};
  683. if(@inputfile || $filename) {
  684. if(!$filename) {
  685. logmsg " $testnum: IGNORED: section client=>file has no name attribute\n";
  686. return -1;
  687. }
  688. my $fileContent = join('', @inputfile);
  689. # make directories if needed
  690. my $path = $filename;
  691. # cut off the file name part
  692. $path =~ s/^(.*)\/[^\/]*/$1/;
  693. my @ldparts = split(/\//, $LOGDIR);
  694. my $nparts = @ldparts;
  695. my @parts = split(/\//, $path);
  696. if(join("/", @parts[0..$nparts-1]) eq $LOGDIR) {
  697. # the file is in $LOGDIR/
  698. my $d = shift @parts;
  699. for(@parts) {
  700. $d .= "/$_";
  701. mkdir $d; # 0777
  702. }
  703. }
  704. if (open(my $outfile, ">", "$filename")) {
  705. binmode $outfile; # for crapage systems, use binary
  706. if($fileattr{'nonewline'}) {
  707. # cut off the final newline
  708. chomp($fileContent);
  709. }
  710. print $outfile $fileContent;
  711. close($outfile);
  712. } else {
  713. logmsg "ERROR: cannot write $filename\n";
  714. }
  715. }
  716. }
  717. return 0;
  718. }
  719. #######################################################################
  720. # Run the test command
  721. sub singletest_run {
  722. my ($testnum, $testtimings) = @_;
  723. # get the command line options to use
  724. my ($cmd, @blaha)= getpart("client", "command");
  725. if($cmd) {
  726. # make some nice replace operations
  727. $cmd =~ s/\n//g; # no newlines please
  728. # substitute variables in the command line
  729. }
  730. else {
  731. # there was no command given, use something silly
  732. $cmd="-";
  733. }
  734. my $CURLOUT="$LOGDIR/curl$testnum.out"; # curl output if not stdout
  735. # if stdout section exists, we verify that the stdout contained this:
  736. my $out="";
  737. my %cmdhash = getpartattr("client", "command");
  738. if((!$cmdhash{'option'}) || ($cmdhash{'option'} !~ /no-output/)) {
  739. #We may slap on --output!
  740. if (!partexists("verify", "stdout") ||
  741. ($cmdhash{'option'} && $cmdhash{'option'} =~ /force-output/)) {
  742. $out=" --output $CURLOUT ";
  743. }
  744. }
  745. my @codepieces = getpart("client", "tool");
  746. my $tool="";
  747. my $tool_name=""; # without exe extension
  748. if(@codepieces) {
  749. $tool_name = $codepieces[0];
  750. chomp $tool_name;
  751. $tool = $tool_name . exe_ext('TOOL');
  752. }
  753. my $disablevalgrind;
  754. my $CMDLINE="";
  755. my $cmdargs;
  756. my $cmdtype = $cmdhash{'type'} || "default";
  757. my $fail_due_event_based = $run_event_based;
  758. if($cmdtype eq "perl") {
  759. # run the command line prepended with "perl"
  760. $cmdargs ="$cmd";
  761. $CMDLINE = "$perl ";
  762. $tool=$CMDLINE;
  763. $disablevalgrind=1;
  764. }
  765. elsif($cmdtype eq "shell") {
  766. # run the command line prepended with "/bin/sh"
  767. $cmdargs ="$cmd";
  768. $CMDLINE = "/bin/sh ";
  769. $tool=$CMDLINE;
  770. $disablevalgrind=1;
  771. }
  772. elsif(!$tool && !$keywords{"unittest"}) {
  773. # run curl, add suitable command line options
  774. my $inc="";
  775. if((!$cmdhash{'option'}) || ($cmdhash{'option'} !~ /no-include/)) {
  776. $inc = " --include";
  777. }
  778. $cmdargs = "$out$inc ";
  779. if($cmdhash{'option'} && ($cmdhash{'option'} =~ /binary-trace/)) {
  780. $cmdargs .= "--trace $LOGDIR/trace$testnum ";
  781. }
  782. else {
  783. $cmdargs .= "--trace-ascii $LOGDIR/trace$testnum ";
  784. }
  785. $cmdargs .= "--trace-config all ";
  786. $cmdargs .= "--trace-time ";
  787. if($run_event_based) {
  788. $cmdargs .= "--test-event ";
  789. $fail_due_event_based--;
  790. }
  791. $cmdargs .= $cmd;
  792. if ($proxy_address) {
  793. $cmdargs .= " --proxy $proxy_address ";
  794. }
  795. }
  796. else {
  797. $cmdargs = " $cmd"; # $cmd is the command line for the test file
  798. $CURLOUT = stdoutfilename($LOGDIR, $testnum); # sends received data to stdout
  799. # Default the tool to a unit test with the same name as the test spec
  800. if($keywords{"unittest"} && !$tool) {
  801. $tool_name="unit$testnum";
  802. $tool = $tool_name;
  803. }
  804. if($tool =~ /^lib/) {
  805. if($bundle) {
  806. $CMDLINE="$LIBDIR/libtests";
  807. }
  808. else {
  809. $CMDLINE="$LIBDIR/$tool";
  810. }
  811. }
  812. elsif($tool =~ /^unit/) {
  813. if($bundle) {
  814. $CMDLINE="$UNITDIR/units";
  815. }
  816. else {
  817. $CMDLINE="$UNITDIR/$tool";
  818. }
  819. }
  820. if(! -f $CMDLINE) {
  821. logmsg " $testnum: IGNORED: The tool set in the test case for this: '$tool' does not exist\n";
  822. return (-1, 0, 0, "", "", 0);
  823. }
  824. if($bundle) {
  825. $CMDLINE.=" $tool_name";
  826. }
  827. $DBGCURL=$CMDLINE;
  828. }
  829. if($fail_due_event_based) {
  830. logmsg " $testnum: IGNORED: This test cannot run event based\n";
  831. return (-1, 0, 0, "", "", 0);
  832. }
  833. if($gdbthis) {
  834. # gdb is incompatible with valgrind, so disable it when debugging
  835. # Perhaps a better approach would be to run it under valgrind anyway
  836. # with --db-attach=yes or --vgdb=yes.
  837. $disablevalgrind=1;
  838. }
  839. my @stdintest = getpart("client", "stdin");
  840. if(@stdintest) {
  841. my $stdinfile="$LOGDIR/stdin-for-$testnum";
  842. my %hash = getpartattr("client", "stdin");
  843. if($hash{'nonewline'}) {
  844. # cut off the final newline from the final line of the stdin data
  845. chomp($stdintest[-1]);
  846. }
  847. writearray($stdinfile, \@stdintest);
  848. $cmdargs .= " <$stdinfile";
  849. }
  850. if(!$tool) {
  851. $CMDLINE=shell_quote($CURL);
  852. if((!$cmdhash{'option'}) || ($cmdhash{'option'} !~ /no-q/)) {
  853. $CMDLINE .= " -q";
  854. }
  855. }
  856. if(use_valgrind() && !$disablevalgrind) {
  857. my $valgrindcmd = "$valgrind ";
  858. $valgrindcmd .= "$valgrind_tool " if($valgrind_tool);
  859. $valgrindcmd .= "--quiet --leak-check=yes ";
  860. $valgrindcmd .= "--suppressions=$srcdir/valgrind.supp ";
  861. # $valgrindcmd .= "--gen-suppressions=all ";
  862. $valgrindcmd .= "--num-callers=16 ";
  863. $valgrindcmd .= "${valgrind_logfile}=$LOGDIR/valgrind$testnum";
  864. $CMDLINE = "$valgrindcmd $CMDLINE";
  865. }
  866. $CMDLINE .= "$cmdargs > " . stdoutfilename($LOGDIR, $testnum) .
  867. " 2> " . stderrfilename($LOGDIR, $testnum);
  868. if($verbose) {
  869. logmsg "$CMDLINE\n";
  870. }
  871. open(my $cmdlog, ">", $CURLLOG) || die "Failure writing log file";
  872. print $cmdlog "$CMDLINE\n";
  873. close($cmdlog) || die "Failure writing log file";
  874. my $dumped_core;
  875. my $cmdres;
  876. if($gdbthis) {
  877. my $gdbinit = "$TESTDIR/gdbinit$testnum";
  878. open(my $gdbcmd, ">", "$LOGDIR/gdbcmd") || die "Failure writing gdb file";
  879. if($gdbthis == 1) {
  880. # gdb mode
  881. print $gdbcmd "set args $cmdargs\n";
  882. print $gdbcmd "show args\n";
  883. print $gdbcmd "source $gdbinit\n" if -e $gdbinit;
  884. }
  885. else {
  886. # lldb mode
  887. print $gdbcmd "set args $cmdargs\n";
  888. }
  889. close($gdbcmd) || die "Failure writing gdb file";
  890. }
  891. # Flush output.
  892. $| = 1;
  893. # timestamp starting of test command
  894. $$testtimings{"timetoolini"} = Time::HiRes::time();
  895. # run the command line we built
  896. if ($torture) {
  897. $cmdres = torture($CMDLINE,
  898. $testnum,
  899. "$gdb --directory $LIBDIR " . shell_quote($DBGCURL) . " -x $LOGDIR/gdbcmd");
  900. }
  901. elsif($gdbthis == 1) {
  902. # gdb
  903. my $GDBW = ($gdbxwin) ? "-w" : "";
  904. runclient("$gdb --directory $LIBDIR " . shell_quote($DBGCURL) . " $GDBW -x $LOGDIR/gdbcmd");
  905. $cmdres=0; # makes it always continue after a debugged run
  906. }
  907. elsif($gdbthis == 2) {
  908. # $gdb is "lldb"
  909. print "runs lldb -- $CURL $cmdargs\n";
  910. runclient("lldb -- $CURL $cmdargs");
  911. $cmdres=0; # makes it always continue after a debugged run
  912. }
  913. else {
  914. # Convert the raw result code into a more useful one
  915. ($cmdres, $dumped_core) = normalize_cmdres(runclient("$CMDLINE"));
  916. }
  917. # timestamp finishing of test command
  918. $$testtimings{"timetoolend"} = Time::HiRes::time();
  919. return (0, $cmdres, $dumped_core, $CURLOUT, $tool, use_valgrind() && !$disablevalgrind);
  920. }
  921. #######################################################################
  922. # Clean up after test command
  923. sub singletest_clean {
  924. my ($testnum, $dumped_core, $testtimings)=@_;
  925. if(!$dumped_core) {
  926. if(-r "core") {
  927. # there's core file present now!
  928. $dumped_core = 1;
  929. }
  930. }
  931. if($dumped_core) {
  932. logmsg "core dumped\n";
  933. if(0 && $gdb) {
  934. logmsg "running gdb for post-mortem analysis:\n";
  935. open(my $gdbcmd, ">", "$LOGDIR/gdbcmd2") || die "Failure writing gdb file";
  936. print $gdbcmd "bt\n";
  937. close($gdbcmd) || die "Failure writing gdb file";
  938. runclient("$gdb --directory libtest -x $LOGDIR/gdbcmd2 -batch " . shell_quote($DBGCURL) . " core ");
  939. # unlink("$LOGDIR/gdbcmd2");
  940. }
  941. }
  942. my $serverlogslocktimeout = $defserverlogslocktimeout;
  943. my %cmdhash = getpartattr("client", "command");
  944. if($cmdhash{'timeout'}) {
  945. # test is allowed to override default server logs lock timeout
  946. if($cmdhash{'timeout'} =~ /(\d+)/) {
  947. $serverlogslocktimeout = $1 if($1 >= 0);
  948. }
  949. }
  950. # Test harness ssh server does not have this synchronization mechanism,
  951. # this implies that some ssh server based tests might need a small delay
  952. # once that the client command has run to avoid false test failures.
  953. #
  954. # gnutls-serv also lacks this synchronization mechanism, so gnutls-serv
  955. # based tests might need a small delay once that the client command has
  956. # run to avoid false test failures.
  957. my $postcommanddelay = $defpostcommanddelay;
  958. if($cmdhash{'delay'}) {
  959. # test is allowed to specify a delay after command is executed
  960. if($cmdhash{'delay'} =~ /(\d+)/) {
  961. $postcommanddelay = $1 if($1 > 0);
  962. }
  963. }
  964. portable_sleep($postcommanddelay) if($postcommanddelay);
  965. my @killtestservers = getpart("client", "killserver");
  966. if(@killtestservers) {
  967. foreach my $server (@killtestservers) {
  968. chomp $server;
  969. if(stopserver($server)) {
  970. logmsg " $testnum: killserver FAILED\n";
  971. return 1; # normal error if asked to fail on unexpected alive
  972. }
  973. }
  974. }
  975. # wait for any servers left running to release their locks
  976. waitlockunlock($serverlogslocktimeout);
  977. # timestamp removal of server logs advisor read lock
  978. $$testtimings{"timesrvrlog"} = Time::HiRes::time();
  979. # test definition might instruct to stop some servers
  980. # stop also all servers relative to the given one
  981. return 0;
  982. }
  983. #######################################################################
  984. # Verify that the postcheck succeeded
  985. sub singletest_postcheck {
  986. my ($testnum)=@_;
  987. # run the postcheck command
  988. my @postcheck= getpart("client", "postcheck");
  989. if(@postcheck) {
  990. die "test$testnum uses client/postcheck";
  991. }
  992. @postcheck= getpart("verify", "postcheck");
  993. if(@postcheck) {
  994. my $cmd = join("", @postcheck);
  995. chomp $cmd;
  996. if($cmd) {
  997. logmsg "postcheck $cmd\n" if($verbose);
  998. my $rc = runclient("$cmd");
  999. # Must run the postcheck command in torture mode in order
  1000. # to clean up, but the result can't be relied upon.
  1001. if($rc != 0 && !$torture) {
  1002. logmsg " $testnum: postcheck FAILED\n";
  1003. return -1;
  1004. }
  1005. }
  1006. }
  1007. return 0;
  1008. }
  1009. ###################################################################
  1010. # Get ready to run a single test case
  1011. sub runner_test_preprocess {
  1012. my ($testnum)=@_;
  1013. my %testtimings;
  1014. if(clearlogs()) {
  1015. logmsg "Warning: log messages were lost\n";
  1016. }
  1017. # timestamp test preparation start
  1018. # TODO: this metric now shows only a portion of the prep time; better would
  1019. # be to time singletest_preprocess below instead
  1020. $testtimings{"timeprepini"} = Time::HiRes::time();
  1021. ###################################################################
  1022. # Load test metadata
  1023. # ignore any error here--if there were one, it would have been
  1024. # caught during the selection phase and this test would not be
  1025. # running now
  1026. loadtest("${TESTDIR}/test${testnum}");
  1027. readtestkeywords();
  1028. ###################################################################
  1029. # Restore environment variables that were modified in a previous run.
  1030. # Test definition may instruct to (un)set environment vars.
  1031. restore_test_env(1);
  1032. ###################################################################
  1033. # Start the servers needed to run this test case
  1034. my ($why, $error) = singletest_startservers($testnum, \%testtimings);
  1035. # make sure no locks left for responsive test
  1036. waitlockunlock($defserverlogslocktimeout);
  1037. if(!$why) {
  1038. ###############################################################
  1039. # Generate preprocessed test file
  1040. # This must be done after the servers are started so server
  1041. # variables are available for substitution.
  1042. singletest_preprocess($testnum);
  1043. ###############################################################
  1044. # Set up the test environment to run this test case
  1045. singletest_setenv();
  1046. ###############################################################
  1047. # Check that the test environment is fine to run this test case
  1048. if (!$listonly) {
  1049. $why = singletest_precheck($testnum);
  1050. $error = -1;
  1051. }
  1052. }
  1053. return ($why, $error, clearlogs(), \%testtimings);
  1054. }
  1055. ###################################################################
  1056. # Run a single test case with an environment that already been prepared
  1057. # Returns 0=success, -1=skippable failure, -2=permanent error,
  1058. # 1=unskippable test failure, as first integer, plus any log messages,
  1059. # plus more return values when error is 0
  1060. sub runner_test_run {
  1061. my ($testnum)=@_;
  1062. if(clearlogs()) {
  1063. logmsg "Warning: log messages were lost\n";
  1064. }
  1065. #######################################################################
  1066. # Prepare the test environment to run this test case
  1067. my $error = singletest_prepare($testnum);
  1068. if($error) {
  1069. return (-2, clearlogs());
  1070. }
  1071. #######################################################################
  1072. # Run the test command
  1073. my %testtimings;
  1074. my $cmdres;
  1075. my $dumped_core;
  1076. my $CURLOUT;
  1077. my $tool;
  1078. my $usedvalgrind;
  1079. ($error, $cmdres, $dumped_core, $CURLOUT, $tool, $usedvalgrind) = singletest_run($testnum, \%testtimings);
  1080. if($error) {
  1081. return (-2, clearlogs(), \%testtimings);
  1082. }
  1083. #######################################################################
  1084. # Clean up after test command
  1085. $error = singletest_clean($testnum, $dumped_core, \%testtimings);
  1086. if($error) {
  1087. return ($error, clearlogs(), \%testtimings);
  1088. }
  1089. #######################################################################
  1090. # Verify that the postcheck succeeded
  1091. $error = singletest_postcheck($testnum);
  1092. if($error) {
  1093. return ($error, clearlogs(), \%testtimings);
  1094. }
  1095. #######################################################################
  1096. # restore environment variables that were modified
  1097. restore_test_env(0);
  1098. return (0, clearlogs(), \%testtimings, $cmdres, $CURLOUT, $tool, $usedvalgrind);
  1099. }
  1100. # Async call runner_clearlocks
  1101. # Called by controller
  1102. sub runnerac_clearlocks {
  1103. return controlleripccall(\&runner_clearlocks, @_);
  1104. }
  1105. # Async call runner_shutdown
  1106. # This call does NOT generate an IPC response and must be the last IPC call
  1107. # received.
  1108. # Called by controller
  1109. sub runnerac_shutdown {
  1110. my ($runnerid)=$_[0];
  1111. my $err = controlleripccall(\&runner_shutdown, @_);
  1112. # These have no more use
  1113. close($controllerw{$runnerid});
  1114. undef $controllerw{$runnerid};
  1115. close($controllerr{$runnerid});
  1116. undef $controllerr{$runnerid};
  1117. return $err;
  1118. }
  1119. # Async call of runner_stopservers
  1120. # Called by controller
  1121. sub runnerac_stopservers {
  1122. return controlleripccall(\&runner_stopservers, @_);
  1123. }
  1124. # Async call of runner_test_preprocess
  1125. # Called by controller
  1126. sub runnerac_test_preprocess {
  1127. return controlleripccall(\&runner_test_preprocess, @_);
  1128. }
  1129. # Async call of runner_test_run
  1130. # Called by controller
  1131. sub runnerac_test_run {
  1132. return controlleripccall(\&runner_test_run, @_);
  1133. }
  1134. ###################################################################
  1135. # Call an arbitrary function via IPC
  1136. # The first argument is the function reference, the second is the runner ID
  1137. # Returns 0 on success, -1 on error writing to runner
  1138. # Called by controller (indirectly, via a more specific function)
  1139. sub controlleripccall {
  1140. my $funcref = shift @_;
  1141. my $runnerid = shift @_;
  1142. # Get the name of the function from the reference
  1143. my $cv = svref_2object($funcref);
  1144. my $gv = $cv->GV;
  1145. # Prepend the name to the function arguments so it's marshalled along with them
  1146. unshift @_, $gv->NAME;
  1147. # Marshall the arguments into a flat string
  1148. my $margs = freeze \@_;
  1149. # Send IPC call via pipe
  1150. my $err;
  1151. while(! defined ($err = syswrite($controllerw{$runnerid}, (pack "L", length($margs)) . $margs)) || $err <= 0) {
  1152. if((!defined $err && ! $!{EINTR}) || (defined $err && $err == 0)) {
  1153. # Runner has likely died
  1154. return -1;
  1155. }
  1156. # system call was interrupted, probably by ^C; restart it so we stay in sync
  1157. }
  1158. if(!$multiprocess) {
  1159. # Call the remote function here in single process mode
  1160. ipcrecv();
  1161. }
  1162. return 0;
  1163. }
  1164. ###################################################################
  1165. # Receive async response of a previous call via IPC
  1166. # The first return value is the runner ID or undef on error
  1167. # Called by controller
  1168. sub runnerar {
  1169. my ($runnerid) = @_;
  1170. my $err;
  1171. my $datalen;
  1172. while(! defined ($err = sysread($controllerr{$runnerid}, $datalen, 4)) || $err <= 0) {
  1173. if((!defined $err && ! $!{EINTR}) || (defined $err && $err == 0)) {
  1174. # Runner is likely dead and closed the pipe
  1175. return undef;
  1176. }
  1177. # system call was interrupted, probably by ^C; restart it so we stay in sync
  1178. }
  1179. my $len=unpack("L", $datalen);
  1180. my $buf;
  1181. while(! defined ($err = sysread($controllerr{$runnerid}, $buf, $len)) || $err <= 0) {
  1182. if((!defined $err && ! $!{EINTR}) || (defined $err && $err == 0)) {
  1183. # Runner is likely dead and closed the pipe
  1184. return undef;
  1185. }
  1186. # system call was interrupted, probably by ^C; restart it so we stay in sync
  1187. }
  1188. # Decode response values
  1189. my $resarrayref = thaw $buf;
  1190. # First argument is runner ID
  1191. # TODO: remove this; it's unneeded since it's passed in
  1192. unshift @$resarrayref, $runnerid;
  1193. return @$resarrayref;
  1194. }
  1195. ###################################################################
  1196. # Returns runner ID if a response from an async call is ready or error
  1197. # First value is ready, second is error, however an error case shows up
  1198. # as ready in Linux, so you can't trust it.
  1199. # argument is 0 for nonblocking, undef for blocking, anything else for timeout
  1200. # Called by controller
  1201. sub runnerar_ready {
  1202. my ($blocking) = @_;
  1203. my $rin = "";
  1204. my %idbyfileno;
  1205. my $maxfileno=0;
  1206. my @ready_runners = ();
  1207. foreach my $p (keys(%controllerr)) {
  1208. my $fd = fileno($controllerr{$p});
  1209. vec($rin, $fd, 1) = 1;
  1210. $idbyfileno{$fd} = $p; # save the runner ID for each pipe fd
  1211. if($fd > $maxfileno) {
  1212. $maxfileno = $fd;
  1213. }
  1214. }
  1215. $maxfileno || die "Internal error: no runners are available to wait on\n";
  1216. # Wait for any pipe from any runner to be ready
  1217. # This may be interrupted and return EINTR, but this is ignored and the
  1218. # caller will need to later call this function again.
  1219. # TODO: this is relatively slow with hundreds of fds
  1220. my $ein = $rin;
  1221. if(select(my $rout=$rin, undef, my $eout=$ein, $blocking) >= 1) {
  1222. for my $fd (0..$maxfileno) {
  1223. # Return an error condition first in case it's both
  1224. if(vec($eout, $fd, 1)) {
  1225. return (undef, $idbyfileno{$fd});
  1226. }
  1227. if(vec($rout, $fd, 1)) {
  1228. push(@ready_runners, $idbyfileno{$fd});
  1229. }
  1230. }
  1231. die "Internal pipe readiness inconsistency\n" if(!@ready_runners);
  1232. return (@ready_runners, undef);
  1233. }
  1234. return (undef, undef);
  1235. }
  1236. ###################################################################
  1237. # Cleanly abort and exit the runner
  1238. # This uses print since there is no longer any controller to write logs.
  1239. sub runnerabort{
  1240. print "Controller is gone: runner $$ for $LOGDIR exiting\n";
  1241. my ($error, $logs) = runner_stopservers();
  1242. print $logs;
  1243. runner_shutdown();
  1244. }
  1245. ###################################################################
  1246. # Receive an IPC call in the runner and execute it
  1247. # The IPC is read from the $runnerr pipe and the response is
  1248. # written to the $runnerw pipe
  1249. # Returns 0 if more IPC calls are expected or 1 if the runner should exit
  1250. sub ipcrecv {
  1251. my $err;
  1252. my $datalen;
  1253. while(! defined ($err = sysread($runnerr, $datalen, 4)) || $err <= 0) {
  1254. if((!defined $err && ! $!{EINTR}) || (defined $err && $err == 0)) {
  1255. # pipe has closed; controller is gone and we must exit
  1256. runnerabort();
  1257. # Special case: no response will be forthcoming
  1258. return 1;
  1259. }
  1260. # system call was interrupted, probably by ^C; restart it so we stay in sync
  1261. }
  1262. my $len=unpack("L", $datalen);
  1263. my $buf;
  1264. while(! defined ($err = sysread($runnerr, $buf, $len)) || $err <= 0) {
  1265. if((!defined $err && ! $!{EINTR}) || (defined $err && $err == 0)) {
  1266. # pipe has closed; controller is gone and we must exit
  1267. runnerabort();
  1268. # Special case: no response will be forthcoming
  1269. return 1;
  1270. }
  1271. # system call was interrupted, probably by ^C; restart it so we stay in sync
  1272. }
  1273. # Decode the function name and arguments
  1274. my $argsarrayref = thaw $buf;
  1275. # The name of the function to call is the first argument
  1276. my $funcname = shift @$argsarrayref;
  1277. # print "ipcrecv $funcname\n";
  1278. # Synchronously call the desired function
  1279. my @res;
  1280. if($funcname eq "runner_clearlocks") {
  1281. @res = runner_clearlocks(@$argsarrayref);
  1282. }
  1283. elsif($funcname eq "runner_shutdown") {
  1284. runner_shutdown(@$argsarrayref);
  1285. # Special case: no response will be forthcoming
  1286. return 1;
  1287. }
  1288. elsif($funcname eq "runner_stopservers") {
  1289. @res = runner_stopservers(@$argsarrayref);
  1290. }
  1291. elsif($funcname eq "runner_test_preprocess") {
  1292. @res = runner_test_preprocess(@$argsarrayref);
  1293. }
  1294. elsif($funcname eq "runner_test_run") {
  1295. @res = runner_test_run(@$argsarrayref);
  1296. } else {
  1297. die "Unknown IPC function $funcname\n";
  1298. }
  1299. # print "ipcrecv results\n";
  1300. # Marshall the results to return
  1301. $buf = freeze \@res;
  1302. while(! defined ($err = syswrite($runnerw, (pack "L", length($buf)) . $buf)) || $err <= 0) {
  1303. if((!defined $err && ! $!{EINTR}) || (defined $err && $err == 0)) {
  1304. # pipe has closed; controller is gone and we must exit
  1305. runnerabort();
  1306. # Special case: no response will be forthcoming
  1307. return 1;
  1308. }
  1309. # system call was interrupted, probably by ^C; restart it so we stay in sync
  1310. }
  1311. return 0;
  1312. }
  1313. ###################################################################
  1314. # Kill the server processes that still have lock files in a directory
  1315. sub runner_clearlocks {
  1316. my ($lockdir)=@_;
  1317. if(clearlogs()) {
  1318. logmsg "Warning: log messages were lost\n";
  1319. }
  1320. clearlocks($lockdir);
  1321. return clearlogs();
  1322. }
  1323. ###################################################################
  1324. # Kill all server processes
  1325. sub runner_stopservers {
  1326. my $error = stopservers($verbose);
  1327. my $logs = clearlogs();
  1328. return ($error, $logs);
  1329. }
  1330. ###################################################################
  1331. # Shut down this runner
  1332. sub runner_shutdown {
  1333. close($runnerr);
  1334. undef $runnerr;
  1335. close($runnerw);
  1336. undef $runnerw;
  1337. }
  1338. 1;