Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

blocking socket and alarm

by InfiniteLoop (Hermit)
on Sep 05, 2006 at 14:10 UTC ( #571254=perlquestion: print w/replies, xml ) Need Help??

InfiniteLoop has asked for the wisdom of the Perl Monks concerning the following question:

Greetings Monks,
   I have a script that opens a blocking socket to a messaging server, in a while(1) loop (it is a backgrounded processs). While the script is running, I want to interrupt the socket read process, say every 1 minute, and write a status message to, say, STDERR (basically I want to monitor the process). Here is how my code looks like this:
use Sys::AlarmCall; #open socket #.... &socket_read(); sub alarm_signal { print STDERR "Received alarm\n"; &socket_read(); }; sub socket_read { while(1){ alarm_call(60, 'alarm_signal'); my $len = $socket->sysread($line,1024); #..... } }

Although the alarm_signal is executed (not after 60 seconds), I get the:
 Deep recursion on subroutine "Sys::AlarmCall::alarm_call" at ... error.

I feel Im not using the alarm properly here. How would you implement a way to interrupt a background process to print a debug message, periodically ?

 I forgot to mention, this elaborate alarm call, is to monitor a messaging server. The socket read, is for the advisory message from the messaging server. Basically I wanted a "watch the watcher" kind of script, hence the interrupt to write a debug message.

Replies are listed 'Best First'.
Re: blocking socket and alarm
by ikegami (Pope) on Sep 05, 2006 at 14:59 UTC

    The function passed to alarm_call is not called on timeout as you expect. The function passed to alarm_call is the one alarm_call will interupt after the specified timeout. Reread the docs.

    sub socket_read { my $len; { ($len, my $errmsg) = alarm_call(60, '->sysread', $socket, $lin +e, 1024); if (defined($len)) { if ($len eq 'TIMEOUT') { print STDERR "Received alarm\n"; redo; } if ($len eq 'ERROR') { die($errmsg); } } } ... }

    Of course, you could also use alarm directly.

    sub socket_read { my $len; { eval { local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n require +d alarm 60; $len = $socket->sysread($line, 1024); }; alarm 0; if (my $e = $@) { if ($e eq "alarm\n") { print STDERR "Received alarm\n"; redo; } die($e); } } ... }

    Untested.

    Update: Added second snippet. Handle exceptions.

Re: blocking socket and alarm
by ozone (Friar) on Sep 05, 2006 at 16:59 UTC
    A more robust (and portable) approach is to perform a 'select' call on the socket handle with a 60 second timeout. That way you don't have to worry about any signal nastiness.

    Either use IO::Select or the second form from perldoc -f select

      It's also much simpler. Why didn't I think of that?

      use IO::Select (); sub socket_read { my $sel = IO::Select->new($socket); while (!$sel->can_read(60)) { print STDERR "Received alarm\n"; } my $len = $socket->sysread($line, 1024); ... }

      Reference: IO::Select

Re: blocking socket and alarm
by samtregar (Abbot) on Sep 05, 2006 at 17:02 UTC
    I don't think I would use alarm() for this. Instead I'd use select() (easier with IO::Select) to do non-blocking reads on the socket. Then it's easy to periodically write to the log when the right amount of time has passed.

    -sam

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://571254]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (6)
As of 2020-05-30 15:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    If programming languages were movie genres, Perl would be:















    Results (173 votes). Check out past polls.

    Notices?