runner.pm 46 KB

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