3 # This file is part of Stem.
4 # Copyright (C) 1999, 2000, 2001 Stem Systems, Inc.
6 # Stem is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # Stem is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with Stem; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 # For a license to use the Stem under conditions other than those
21 # described here, to purchase support for this software, or to purchase a
22 # commercial warranty contract, please contact Stem Systems at:
24 # Stem Systems, Inc. 781-643-7504
25 # 79 Everett St. info@stemsystems.com
29 # this is the base class for all of the other event classes. it
30 # provides common services and also stubs for the internal _methods so
31 # the other classes don't need to declare them if they don't use them.
39 # this will hold the hashes of events for each event type.
50 # table of loop types to the Stem::Event::* class name
62 # use the requested event loop and default to perl on windows and
65 my $loop_class = _get_loop_class() ;
72 Stem::Event::Queue::_init_queue() if defined &Stem::Event::Queue::_init_queue ;
74 $loop_class->_init_loop() ;
76 <<<<<<< HEAD:lib/Stem/Event.pm
77 #Stem::Event::Queue::_init_queue() if defined &Stem::Event::Queue::_init_queue ;
79 >>>>>>> master:lib/Stem/Event.pm
85 $loop_class->_start_loop() ;
90 $loop_class->_stop_loop() ;
95 my( $self, $method ) = @_ ;
97 # never trigger inactive events
99 return unless $self->{active} ;
102 $method ||= $self->{'method'} ;
103 #print "METHOD [$method]\n" ;
105 $self->{'object'}->$method( $self->{'id'} ) ;
107 Stem::Msg::process_queue() if defined &Stem::Msg::process_queue;
113 # all the stuff below is a rough cell call trace thing. it needs work
114 # it would be put inside the trigger method
115 # 'log_type' attribute is set or the event type is used.
116 #_init subs need to set event_log_type in the object
117 #use Stem::Trace 'log' => 'stem_status', 'sub' => 'TraceStatus' ;
118 #use Stem::Trace 'log' => 'stem_error' , 'sub' => 'TraceError' ;
119 # $log_type = $self->{'log_type'} || $self->{'event_type'} ;
120 # TraceStatus "[$log_type] [$object] [$method]\n" ;
121 # $Stem::Event::current_object = $object ;
122 # my ( $cell_name, $target ) = Stem::Route::lookup_cell_name( $object ) ;
123 # if ( $cell_name ) {
125 # # "EVENT $event to $cell_name:$target [$object] [$method]\n" ;
128 # # Debug "EVENT $event to [$object] [$method]\n" ;
133 # get all the event objects for an event type
134 # this is a class sub.
138 my( $event_type ) = @_ ;
140 my $events = $all_events{ $event_type } ;
142 return unless $events ;
144 return values %{$events} if wantarray ;
149 # initialize the subclass object for this event and store generic event
152 sub _build_core_event {
156 my( $self, $event_type ) = @_ ;
159 #print "EVT [$self] [$event_type]\n" ;
161 # call and and check the return of the core event constructor
163 if ( my $core_event = $self->_build() ) {
165 # return the error if it was an error string
167 return $core_event unless ref $core_event ;
169 # save the core event
171 $self->{core_event} = $core_event ;
174 # mark the event type and track it
176 $self->{event_type} = $event_type ;
177 $all_events{ $event_type }{ $self } = $self ;
182 # these are the public versions of the support methods.
183 # subclasses can provide a _method to override the stub ones in this class.
189 $self->{'active'} = 0 ;
190 delete $self->{'object'} ;
192 # delete the core object
194 if ( my $core_event = delete $self->{core_event} ) {
196 # call the core cancel
198 $self->_cancel( $core_event ) ;
201 # delete this event from the tracking hash
203 delete $all_events{ $self->{event_type} }{ $self } ;
211 $self->{'active'} = 1 ;
212 $self->_start( $self->{core_event} ) ;
220 $self->{'active'} = 0 ;
221 $self->_stop( $self->{core_event} ) ;
226 # stubs for the internal methods that subclasses should override if needed.
235 use Stem::Debug qw( dump_socket dump_owner dump_data ) ;
239 print dump_data( \%all_events ) ;
246 my $event_text = <<TEXT ;
248 ACT: $self->{'active'}
251 my $obj_dump = dump_owner $self->{'object'} ;
252 $event_text .= <<TEXT ;
254 METH: $self->{'method'}
257 if ( my $fh = $self->{'fh'} ) {
259 my $fh_text = dump_socket( $self->{'fh'} ) ;
260 $event_text .= <<TEXT ;
265 if ( $self->{event_type} eq 'timer' ) {
267 my $delay = $self->{delay} || 'NONE' ;
268 my $interval = $self->{interval} || 'NONE' ;
269 $event_text .= <<TEXT ;
275 if ( my $io_timer_event = $self->{'io_timer_event'} ) {
277 $event_text = "IO TIMER: >>>>>\n" . $io_timer_event->dump() .
291 # change this to a cleaner loop style which can handle more event loops and
292 # try them in sequence
295 sub _get_loop_class {
297 my $loop_type = $Stem::Vars::Env{ 'event_loop' } ||
298 ($^O =~ /win32/i ? 'perl' : 'event' );
300 $loop_type = 'perl' unless $loop_to_class{ $loop_type } ;
301 my $loop_class = "Stem::Event::$loop_to_class{ $loop_type }" ;
303 print "LOOP $loop_class\n" ;
305 unless ( eval "require $loop_class" ) {
306 die "can't load $loop_class: $@" if $@ && $@ !~ /locate/ ;
308 print "not found\n" ;
310 $loop_type = 'perl' ;
311 eval { require Stem::Event::Perl } ;
312 die "can't load event loop Stem::Event::Perl $@" if $@ ;
316 # save the event loop that we loaded.
318 #print "using event loop [$loop_type]\n" ;
319 $Stem::Vars::Env{ 'event_loop' } = $loop_type ;
326 ############################################################################
328 package Stem::Event::Plain ;
329 <<<<<<< HEAD:lib/Stem/Event.pm
332 >>>>>>> master:lib/Stem/Event.pm
333 our @ISA = qw( Stem::Event ) ;
335 =head2 Stem::Event::Plain::new
337 This class creates an event that will trigger a callback after all
338 other pending events have been triggered.
342 $plain_event = Stem::Event::Plain->new( 'object' => $self ) ;
346 my $attr_spec_plain = [
353 This object gets the method callbacks
358 'default' => 'triggered',
360 This method is called on the object when the plain event is triggered
366 The id is passed to the callback method as its only argument. Use it to
367 identify different instances of this object.
375 my( $class ) = shift ;
377 my $self = Stem::Class::parse_args( $attr_spec_plain, @_ ) ;
378 return $self unless ref $self ;
380 my $err = $self->_build_core_event( 'plain' ) ;
381 return $err if $err ;
386 ############################################################################
388 package Stem::Event::Signal ;
389 <<<<<<< HEAD:lib/Stem/Event.pm
392 >>>>>>> master:lib/Stem/Event.pm
393 our @ISA = qw( Stem::Event ) ;
395 =head2 Stem::Event::Signal::new
397 This class creates an event that will trigger a callback whenever
398 its its signal has been received.
402 $signal_event = Stem::Event::Signal->new( 'object' => $self,
403 'signal' => 'INT' ) ;
405 sub sig_int_handler { die "SIGINT\n" }
409 my $attr_spec_signal = [
416 This object gets the method callbacks
422 This method is called on the object when this event is triggered. The
423 default method name for the signal NAME is 'sig_name_handler' (all lower case)
430 This is the name of the signal to handle. It is used as part of the
431 default handler method name.
439 This flag marks the event as being active. It can be toggled with the
446 The id is passed to the callback method as its only argument. Use it to
447 identify different instances of this object.
455 my( $class ) = shift ;
457 my $self = Stem::Class::parse_args( $attr_spec_signal, @_ ) ;
458 return $self unless ref $self ;
460 my $signal = uc $self->{'signal'} ;
462 return "Unknown signal: $signal" unless exists $SIG{ $signal } ;
464 $self->{'method'} ||= "sig_\L${signal}_handler" ;
465 $self->{'signal'} = $signal ;
467 my $err = $self->_build_core_event( 'signal' ) ;
468 return $err if $err ;
470 #print "SELF SIG $self\nPID $$\n" ;
476 ############################################################################
478 package Stem::Event::Timer ;
479 <<<<<<< HEAD:lib/Stem/Event.pm
482 >>>>>>> master:lib/Stem/Event.pm
483 our @ISA = qw( Stem::Event ) ;
485 =head2 Stem::Event::Timer::new
487 This class creates an event that will trigger a callback after a time
488 period has elapsed. The initial timer delay is set from the 'delay',
489 'at' or 'interval' attributes in that order. If the 'interval'
490 attribute is not set, the timer will cancel itself after its first
491 triggering (it is a one-shot). The 'hard' attribute means that the
492 next interval delay starts before the callback to the object is
493 made. If a soft timer is selected (hard is 0), the delay starts after
494 the callback returns. So the hard timer ignores the time taken by the
495 callback and so it is a more accurate timer. The accuracy a soft timer
496 is affected by how much time the callback takes.
500 $timer_event = Stem::Event::Timer->new( 'object' => $self,
504 sub timed_out { print "timer alert\n" } ;
511 my $attr_spec_timer = [
518 This object gets the method callbacks
523 'default' => 'timed_out',
525 This method is called on the object when the timeout is triggered
531 Delay this amount of seconds before triggering the first time. If this
532 is not set then the 'at' or 'interval' attributes will be used.
536 'name' => 'interval',
538 Wait this time (in seconds) before any repeated triggers. If not set
539 then the timer is a one-shot
545 Trigger in the future at this time (in epoch seconds). It will set the intial
546 delay to the different between the current time and the 'at' time.
554 If this is set, the interval time starts when the event is
555 triggered. If it is not set, the interval time starts when the object
556 callback has finished. So 'hard' timers repeat closer to equal
557 intervals while without 'hard' the repeat time is dependant on how
558 long the callback takes.
566 This flag marks the event as being active. It can be toggled with the
573 The id is passed to the callback method as its only argument. Use it to
574 identify different instances of this object.
582 my( $class ) = shift ;
584 my $self = Stem::Class::parse_args( $attr_spec_timer, @_ ) ;
585 return $self unless ref $self ;
587 # the delay is either set, or at a future time or the interval
589 my $delay = exists( $self->{ 'delay' } ) ?
591 exists( $self->{ 'at' } ) ?
592 $self->{ 'at' } - time() :
593 $self->{'interval'} ;
595 #print "INT $self->{'interval'} DELAY $delay\n" ;
597 # squawk if no delay value
599 return "No initial delay was specified for timer"
600 unless defined $delay ;
602 $self->{'delay'} = $delay ;
603 $self->{'time_left'} = $delay ;
605 my $err = $self->_build_core_event( 'timer' ) ;
606 return $err if $err ;
609 # check on this logic
612 $self->_stop unless $self->{'active'} ;
621 my( $self, $reset_delay ) = @_ ;
623 return unless $self->{'active'} ;
625 # if we don't get passed a delay, use the interval or the delay attribute
627 $reset_delay ||= ($self->{'interval'}) ?
628 $self->{'interval'} : $self->{'delay'} ;
630 # track the new delay and reset the real timer (if we are using one)
632 $self->{'time_left'} = $reset_delay ;
634 $self->_reset( $self->{core_event}, $reset_delay ) ;
639 sub timer_triggered {
643 #print time(), " TIMER TRIG\n" ;
644 #use Carp qw( cluck ) ;
647 # check if this is a one-shot timer
649 $self->cancel() unless $self->{'interval'} ;
651 # reset the timer count before the trigger code for hard timers
652 #(trigger on fixed intervals)
654 $self->reset( $self->{'interval'} ) if $self->{'hard'};
658 # reset the timer count before the trigger code for soft timers
659 #(trigger on at least fixed intervals)
661 $self->reset( $self->{'interval'} ) unless $self->{'hard'};
664 ############################################################################
666 ####################################################################
667 # common methods for the Read/Write event classes to handle the optional
669 # these override Stem::Event's methods and then call those via SUPER::
671 package Stem::Event::IO ;
672 <<<<<<< HEAD:lib/Stem/Event.pm
675 >>>>>>> master:lib/Stem/Event.pm
676 our @ISA = qw( Stem::Event ) ;
678 sub init_io_timeout {
682 my $timeout = $self->{'timeout'} ;
683 return unless $timeout ;
685 $self->{'io_timer_event'} = Stem::Event::Timer->new(
687 'interval' => $timeout,
697 #print "IO CANCEL $self\n" ;
699 if ( my $io_timer_event = delete $self->{'io_timer_event'} ) {
700 $io_timer_event->cancel() ;
703 $self->SUPER::cancel() ;
705 delete $self->{'fh'} ;
714 if ( my $io_timer_event = $self->{'io_timer_event'} ) {
715 $io_timer_event->start() ;
718 $self->SUPER::start() ;
727 $self->{'active'} = 0 ;
729 if ( my $io_timer_event = $self->{'io_timer_event'} ) {
730 $io_timer_event->stop() ;
733 $self->SUPER::stop() ;
742 # $self->{log_type} = "$self->{'event_type'}_timeout" ;
743 $self->trigger( $self->{'timeout_method'} ) ;
746 #######################################################
748 package Stem::Event::Read ;
749 our @ISA = qw( Stem::Event::IO ) ;
752 <<<<<<< HEAD:lib/Stem/Event.pm
753 our @ISA = qw( Stem::Event::IO ) ;
755 >>>>>>> master:lib/Stem/Event.pm
757 =head2 Stem::Event::Read::new
759 This class creates an event that will trigger a callback whenever
760 its file descriptor has data to be read. It takes an optional timeout
761 value which will trigger a callback to the object if no data has been
762 read during that period.
764 Read events are active when created - a call to the stop method is
765 needed to deactivate them.
771 my $attr_spec_read = [
778 This object gets the method callbacks
786 This file handle is checked if it has data to read
792 How long to wait (in seconds) without being readable before calling
798 'default' => 'readable',
800 This method is called on the object when the file handle has data to read
804 'name' => 'timeout_method',
805 'default' => 'read_timeout',
807 This method is called on the object when the hasn't been readable
808 after the timeout period
816 This flag marks the event as being active. It can be toggled with the
823 The id is passed to the callback method as its only argument. Use it to
824 identify different instances of this object.
832 my( $class ) = shift ;
835 my $self = Stem::Class::parse_args( $attr_spec_read, @_ ) ;
836 return $self unless ref $self ;
839 # return <<ERR unless defined fileno $self->{fh} ;
840 # Stem::Event::Read: $self->{fh} is not an open handle
843 my $err = $self->_build_core_event( 'read' ) ;
844 return $err if $err ;
846 $self->init_io_timeout() ;
852 ############################################################################
854 package Stem::Event::Write ;
855 <<<<<<< HEAD:lib/Stem/Event.pm
858 >>>>>>> master:lib/Stem/Event.pm
859 our @ISA = qw( Stem::Event::IO ) ;
861 =head2 Stem::Event::Write::new
863 This class creates an event that will trigger a callback whenever
864 its file descriptor can be written to. It takes an optional timeout
865 value which will trigger a callback to the object if no data has been
866 written during that period.
868 Write events are stopped when created - a call to the start method is
869 needed to activate them.
873 my $attr_spec_write = [
880 This object gets the method callbacks
888 This file handle is checked if it is writeable
894 How long to wait (in seconds) without being writeable before calling
900 'default' => 'writeable',
902 This method is called on the object when the file handle is writeable
906 'name' => 'timeout_method',
907 'default' => 'write_timeout',
909 This method is called on the object when the hasn't been writeable
910 after the timeout period
918 This flag marks the event as being active. It can be toggled with the
920 NOTE: Write events are not active by default.
926 The id is passed to the callback method as its only argument. Use it to
927 identify different instances of this object.
935 my( $class ) = shift ;
937 my $self = Stem::Class::parse_args( $attr_spec_write, @_ ) ;
938 return $self unless ref $self ;
940 my $err = $self->_build_core_event( 'write' ) ;
941 return $err if $err ;
943 #print $self->dump_events() ;
945 $self->init_io_timeout() ;
947 $self->stop() unless $self->{'active'} ;
949 #print $self->dump() ;