in reply to Re^3: Perl Alarm Not Working
in thread Perl Alarm Not Working

You have something there that MySql is immune to SIGALRM.

Here's another test script I wrote to test SIGALRM in a script running MySql:

#!/usr/bin/perl require 'myconfigure.cgi'; $timeout = 5; use DBI; $keywords = "Whether rocking natural-curls, a-short"; print "Content-type: text/html\n\n"; sub do_search { $time1 = time; $dbh=DBI->connect("dbi:mysql:$database:localhost","$username","$pa +ssword"); $keywords_quoted = $dbh ->quote ($keywords); $query="SELECT count(*) FROM $websites_table WHERE MATCH(title) AG +AINST ($keywords_quoted)"; $sth=$dbh->prepare(qq{$query}); $sth->execute(); $total_count = $sth->fetchrow_array (); $sth->finish; $dbh->disconnect ||die("Couldn't disconnect to database!\n"); $time2 = time; $time_ran = $time2 - $time1; } eval { local $SIG{ALRM} = sub { die "alarm\n" }; alarm $timeout; &do_search; alarm 0; }; if($@) { $time2 = time; $time_ran = $time2 - $time1; print "$@, Time Ran: $time_ran, Total Count: $total_count\n"; exit; } print "Time Ran: $time_ran, Total Count: $total_count\n"; exit;

Above script basically do a search for the number of matches of $keywords in $websites_table. I've used a timeout of 5 seconds( $timeout = 5;) to limit the time of search, i.e. exit if search takes more than 5 seconds.

When it timeouts by the eval{} block, it will indicate how much time the script has ran as shown by the variable $time_ran in the if($@) loop.

But I'm getting funny results when it timeout. It overshoots the timeout limit of 5 sec condiderably. In one instance, I got a value of $time_ran = 18.

How do I fix this problem?

Replies are listed 'Best First'.
Re^5: Perl Alarm Not Working
by ikegami (Patriarch) on Dec 20, 2010 at 05:13 UTC
    There's two different issues at play:
    • Calls to C code (e.g. calls to the db driver) are not interruptible.
    • DBD::mysql might clear the alarm.

    When it takes longer than the timeout, does it say "alarm" and ", Time Ran" or just "Time Ran"? If it's the former, you have crazy long database calls and should look at fixing that. If it's the latter, DBD::mysql is probably using alarm itself so you're pre-empted from using it yourself.

      Most of time, it will not timeout. In these instances, it will not get into the if($@) loop.
      It will have the following results for various keywords, $keywords:

      Time Ran: 0, Total Count: 3560
      Time Ran: 0, Total Count: 7860
      Time Ran: 0, Total Count: 17863

      For some keywords, it will timeout and it will get into the if($@) loop with results like the followings:

      Alarm, Time Ran: 18, Total Count: 0
      Alarm, Time Ran: 12, Total Count: 0

      They all overshoot the set timeout limit of 5 sec. considerably.

      It appears that MySql is doing funny things to SIGALRM.

      Questions:

      1) Is this problem fixable?

      2) The whole purpose of this exercise is to find a way to get out of the MySql operation if it takes longer than 5 sec. to do MySql. Timeout at around 5 sec. not at anything above 5 sec. If above problem is not fixable, meaning we cannot use eval {} to limit MySql time, what can then?

        It appears that MySql is doing funny things to SIGALRM.

        No, it doesn't. It's the first bullet. The alarm signal is received. C calls are not interruptible, so calling the handler is delayed until the C code returns. alarm is working as expected.

        1) Is this problem fixable?

        You can interrupt C code by using unsafe signals, but it can leave the process in a weird state.

        2) The whole purpose of this exercise is to find a way to get out of the MySql operation if it takes longer than 5 sec. to do MySql.

        Perhaps you should start a thread with that question.