Solved

How to time out system call in Perl?

Posted on 2011-03-22
6
472 Views
Last Modified: 2012-05-11
Hi,
How can I time out if system call hangs for more than let's say 20 seconds?

system(java -jar someFile.java)  ===> time out this if it hangs more than 20 seconds

Open in new window



Thanks,
0
Comment
Question by:Tolgar
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
6 Comments
 
LVL 5

Expert Comment

by:group0
ID: 35194654
You can do this with by running the system() call in a thread, polling $thr->is_joinable() from another thread after the desired delay, and then taking the necessary action to kill the spawned process if it returns false.

Alternatively, here's a good single-threaded example I found with google that uses SIGALRM:

use Error qw(:try);

$SIG{ALRM} = sub {
    my $sig_name = shift;
    die "Timeout by signal [$sig_name]\n";
};

# example
my $command = "vmstat 1 1000000";
my $output = backtick( 
                 command => $command, 
                 timeout => 60, 
                 verbose => 0 
             );

sub backtick {

    my %arg = (
        command => undef,
        timeout => 900,
        verbose => 1,
        @_,
    );

    my @output;

    defined( my $pid = open( KID, "-|" ) )
        or die "Can't fork: $!\n";

    if ($pid) {

        # parent

        # print "parent: child pid [$pid]\n" if $arg{verbose};

        try {
            alarm( $arg{timeout} );
            while (<KID>) {
                chomp;
                push @output, $_;
            }

            alarm(0);
        }
        catch Error with {
            my $err = shift;
            print $err->{-text} . "\n";

            print "Killing child process [$pid] ...\n" if $arg{verbose};
            kill -9, $pid;
            print "Killed\n" if $arg{verbose};

            alarm(0);
        }
        finally {};
    }
    else {

        # child

        # set the child process to be a group leader, so that
        # kill -9 will kill it and all its descendents
        setpgrp( 0, 0 );

        # print "child: pid [$pid]\n" if $arg{verbose};
        exec $arg{command};
        exit;
    }

    wantarray ? @output : join( "\n", @output );
}

Open in new window

0
 

Author Comment

by:Tolgar
ID: 35194762
Sorry, but I didn't fully understood the code you sent.

Is there a more straightforward way of doing it?


Thanks,
0
 
LVL 28

Accepted Solution

by:
FishMonger earned 500 total points
ID: 35194851
D:\perl>perldoc -q timeout
Found in C:\Perl\lib\pods\perlfaq8.pod
  How do I timeout a slow event?
    Use the "alarm()" function, probably in conjunction with a signal
    handler, as documented in "Signals" in perlipc and the section on
    "Signals" in the Camel. You may instead use the more flexible
    "Sys::AlarmCall" module available from CPAN.

    The "alarm()" function is not implemented on all versions of Windows.
    Check the documentation for your specific version of Perl.

******

D:\perl>perldoc -f alarm
    alarm SECONDS
    alarm   Arranges to have a SIGALRM delivered to this process after the
            specified number of wallclock seconds has elapsed. If SECONDS is
            not specified, the value stored in $_ is used. (On some
            machines, unfortunately, the elapsed time may be up to one
            second less or more than you specified because of how seconds
            are counted, and process scheduling may delay the delivery of
            the signal even further.)

            Only one timer may be counting at once. Each call disables the
            previous timer, and an argument of 0 may be supplied to cancel
            the previous timer without starting a new one. The returned
            value is the amount of time remaining on the previous timer.

            For delays of finer granularity than one second, the Time::HiRes
            module (from CPAN, and starting from Perl 5.8 part of the
            standard distribution) provides ualarm(). You may also use
            Perl's four-argument version of select() leaving the first three
            arguments undefined, or you might be able to use the "syscall"
            interface to access setitimer(2) if your system supports it. See
            perlfaq8 for details.

            It is usually a mistake to intermix "alarm" and "sleep" calls,
            because "sleep" may be internally implemented on your system
            with "alarm".

            If you want to use "alarm" to time out a system call you need to
            use an "eval"/"die" pair. You can't rely on the alarm causing
            the system call to fail with $! set to "EINTR" because Perl sets
            up signal handlers to restart system calls on some systems.
            Using "eval"/"die" always works, modulo the caveats given in
            "Signals" in perlipc.

                eval {
                    local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
                    alarm $timeout;
                    $nread = sysread SOCKET, $buffer, $size;
                    alarm 0;
                };
                if ($@) {
                    die unless $@ eq "alarm\n";   # propagate unexpected errors
                    # timed out
                }
                else {
                    # didn't
                }

            For more information see perlipc.

******

Sys::AlarmCall - A package to handle the logic in timing out calls with alarm() and an ALRM handler, allowing nested calls as well.
http://search.cpan.org/~abh/Sys-AlarmCall-1.2/AlarmCall.pm

Time::Out - Easily timeout long running operations
http://search.cpan.org/~patl/Time-Out-0.11/Out.pod
0
 

Author Comment

by:Tolgar
ID: 35195075
Thank you for your replies!!

So is this code correct? I am curious about line 9 ($?) After putting system call into timeout, does it still have the same meaning which is if system call returns -1 then send some emails. sendEmail is a sub function in my code which I didn't add to this email.

my $nb_sec = 60;
timeout $nb_secs => sub {
        system("java -jar SOMEFILE.java");
  } ;
  if ($@){
    # operation timed-out. Send e-mail to help
    sendEmail('help@mywork.com', 'somename@mywork.com', 'Timed out', "System call interrupted due to time out");
  }
        if ($? == -1) {
            sendEmail('help@mywork.com', 'somename@mywork.com', 'Logging Failed', "failed to execute: $!\n");
        } elsif ($? & 127) {
            printf "Child died with signal %d, %s coredump\n",
              ($? & 127),  ($? & 128) ? 'with' : 'without';
            my $signal = ($? & 127);
            my $woCoredump = ($? & 128) ? 'with' : 'without';
            sendEmail('help@mywork.com', 'somename@mywork.com', 'Logging Failed', "Child died with signal $signal, $woCodedump coredump\n");
        }

Open in new window



Thanks,
0

Featured Post

Transaction Monitoring Vs. Real User Monitoring

Synthetic Transaction Monitoring Vs. Real User Monitoring: When To Use Each Approach? In this article, we will discuss two major monitoring approaches: Synthetic Transaction and Real User Monitoring.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Entering a date in Microsoft Access can be tricky. A typo can cause month and day to be shuffled, entering the day only causes an error, as does entering, say, day 31 in June. This article shows how an inputmask supported by code can help the user a…
If you’re thinking to yourself “That description sounds a lot like two people doing the work that one could accomplish,” you’re not alone.
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…
With the power of JIRA, there's an unlimited number of ways you can customize it, use it and benefit from it. With that in mind, there's bound to be things that I wasn't able to cover in this course. With this summary we'll look at some places to go…

724 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question