As part of some quality control, I've been writing a script that tests whether a homebrew command line utility returns physically-appropriate outputs over a very large parameter space. Essentially, I generated a work queue in the master thread and then in each slave captured the output with backticks and ran it through some numerical tests. This has been functioning for about a month.

Yesterday, I had a rude awakening when I managed to take down the server my test suite was running on. Analysis after a hard reboot of the server showed that in exceptional cases, the utility seems to start grabbing memory in an infinite loop - it consumes the 64GB of physical memory in a few minutes. So today's job was modifying the test so it would abort a given test after a suitable timeout.

Looking through the archives, I first tried following Re: killing a program called with system() if it takes too long? by implementing an alarm (in a single threaded version), which resulted in the creation of zombies that continued chewing through my memory. In order to actually kill the computations, I combined a pipe with repeated calls to `ps --ppid` and kill to get all spawned processes (inspired by almut's Re^2: Killing children's of children). I then discovered that alarms don't work in a threaded context, so I followed ikegami's advice in Re^3: Threads and ALARM() - There is a solution or workaround? and used select on the pipe instead of signals, resulting in some code that seems to be working (special thanks to duff's Using select and IO::Select tutorial). So I replaced

        my $content = `$command 2>&1`;

with

my $pid = open my $calc, '-|', "$command 2>&1" or die "Pipe failed on open: $!\n"; my $vector = ''; vec($vector,fileno($calc),1) = 1; # Flip bit for pipe unless (select($vector,undef,undef,$timeout)) { # Calculation +is hanging # collect list of spawned processes my @pids = $pid; my $i = -1; push @pids, `ps --ppid $pids[$i] -o pid` =~ /\d+/g while + ++$i < @pids; kill 9, $_ for @pids; die "Calculation call failed to return with $timeout secon +ds\n"; } local $/; # Slurp my $content = <$calc>; close $calc;

where both are wrapped in eval blocks. So my questions are:

  1. Is this a reasonable way to be handling this? Have I missed something that will come back to bite me?
  2. I do not feel entirely comfortable with my pid collection strategy. Is there a more robust way to handle "kill all spawned processes"?

In reply to Handling badly behaved system calls in threads by kennethk

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.