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

Hi, I'm writing a script and am looking for the best way to proceed. I have an interface that allows you to request a some data. The following works fine for single event...
->log abc

I want to make it so that I setup timed events i.e.
-> log abc ontime 1
so that the info would come out periodically and multiple logs could setup etc.
To process my command line input I'm just using the readline module...i.e.
while(defined($_ = $term->readline($prompt))) { [case statement to parse command] }

this works fine for single entries, but readline is blocking so that I can't put any other code in the while loop that will trigger until another command is issued.
So what I'd like is either a good way to piggy back onto what I have with something that can be added periodically or rewrite it a better way...
i.e.
while (not time to quit) { [see if there is keyboard stuff to process] [process any timer based stuff] [go back to sleep] }

I tried using signals to keep the other code the same, but because you run into problems with reentrancy of code the signal stops after a few operations.

I expect there is a very clean way of doing this in perl as the problem is pretty straight forwards. The periodicity is only going down to a 1second level so I don't need any complex sub-second routines.

I have setup the backend for the timing ready for the triggers from whatever source. I'm basically using a hash with the key being the update rate and the value being a reference to an array of logs that are requested at that rate. So the event timer just will just look at the key to work out which groups to process when and takes it from there.

If anyone can point me in the right direction, offer a code snippet, an example of someone else that does this or a module for this type of thing it would be much appreciated..
Regards Paul.

Replies are listed 'Best First'.
•Re: Event timing and input processing
by merlyn (Sage) on Sep 27, 2004 at 01:36 UTC
      Just what I was after, thanks =P
Re: Event timing and input processing
by BrowserUk (Patriarch) on Sep 27, 2004 at 02:10 UTC
    Simplicity itself using [cpan://threads]. #! perl -slw use strict; use threads qw[ async ]; use Thread::Queue; my $Qin = new Thread::Queue; async { my $input; do { chomp( $input = <STDIN> ); $Qin->enqueue( $input ); } until $input =~ m[^Q(?:uit)?]i; }->detach; my %events; while( sleep 1 ) { if( $Qin->pending ) { my $input = $Qin->dequeue ; last if $input =~ m[^Q(?:uit)?]i; ## Process input print "Got: $input"; } ## process timer based stuff if( exists $events{ scalar localtime } ) { ## Processing event } }

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re: Event timing and input processing
by graff (Chancellor) on Sep 27, 2004 at 02:42 UTC
    I haven't tried POE myself yet, but on following merlyn's link, it looks like something that would be very good to try.

    But if, for some odd reason, you wanted to consider some other approach, the next thing I would consider (if I were in your position) would be to create a separate script that fetches and prints log info, with the ability to control source and output format (and perhaps timing as well) based on command-line params, and run that via a pipeline "open()" for each log activity being requested -- something like (untested):

    my @loggers; # array of file handles my @logpids; # array of pids for open file handles ... # in branch of case statement for starting a new logger: my $args = "whatever is appropriate..."; my $pid = open( $loggers[@loggers], "logger_script $args |" ) or die "can't run logger_script: $!" ); push @logpids, $pid; ...
    The other part of the trick would be to manipulate each file handle (as well as STDIN) to allow for non-blocking i/o, which means that a read will return data if there is any, and will return immediately with no data if there is none available. Check the IO::Handle man page for info on non-blocking i/o (IO::Handle is part of the perl core distro). You may also want to look at the multi-arg usage of the "select" function -- see "perldoc -f select".

    The person doing the interaction can request that logs be turned off at any time -- just close the associated file handle to stop the chosen process.