# You may distribute under the terms of either the GNU General Public License # or the Artistic License (the same terms as Perl itself) # # (C) Paul Evans, 2009-2012 -- leonerd@leonerd.org.uk package IO::Async::Timer; use strict; use warnings; use base qw( IO::Async::Notifier ); our $VERSION = '0.60_002'; use Carp; =head1 NAME C<IO::Async::Timer> - base class for Notifiers that use timed delays =head1 DESCRIPTION This module provides a subclass of L<IO::Async::Notifier> for implementing notifiers that use timed delays. For specific implementations, see one of the subclasses: =over 8 =item * L<IO::Async::Timer::Absolute> - event callback at a fixed future time =item * L<IO::Async::Timer::Countdown> - event callback after a fixed delay =item * L<IO::Async::Timer::Periodic> - event callback at regular intervals =back =cut =head1 CONSTRUCTOR =cut =head2 $timer = IO::Async::Timer->new( %args ) Constructs a particular subclass of C<IO::Async::Timer> object, and returns it. This constructor is provided for backward compatibility to older code which doesn't use the subclasses. New code should directly construct a subclass instead. =over 8 =item mode => STRING The type of timer to create. Currently the only allowed mode is C<countdown> but more types may be added in the future. =back Once constructed, the C<Timer> will need to be added to the C<Loop> before it will work. It will also need to be started by the C<start> method. =cut sub new { my $class = shift; my %args = @_; if( my $mode = delete $args{mode} ) { # Might define some other modes later $mode eq "countdown" or croak "Expected 'mode' to be 'countdown'"; require IO::Async::Timer::Countdown; return IO::Async::Timer::Countdown->new( %args ); } return $class->SUPER::new( %args ); } sub _add_to_loop { my $self = shift; $self->start if delete $self->{pending}; } sub _remove_from_loop { my $self = shift; $self->stop; } =head1 METHODS =cut =head2 $running = $timer->is_running Returns true if the Timer has been started, and has not yet expired, or been stopped. =cut sub is_running { my $self = shift; defined $self->{id}; } =head2 $timer->start Starts the Timer. Throws an error if it was already running. If the Timer is not yet in a Loop, the actual start will be deferred until it is added. Once added, it will be running, and will expire at the given duration after the time it was added. As a convenience, C<$timer> is returned. This may be useful for starting timers at construction time: $loop->add( IO::Async::Timer->new( ... )->start ); =cut sub start { my $self = shift; my $loop = $self->loop; if( !defined $loop ) { $self->{pending} = 1; return $self; } defined $self->{id} and croak "Cannot start a Timer that is already running"; if( !$self->{cb} ) { $self->{cb} = $self->_make_cb; } $self->{id} = $loop->watch_time( $self->_make_enqueueargs, code => $self->{cb}, ); return $self; } =head2 $timer->stop Stops the Timer if it is running. If it has not yet been added to the C<Loop> but there is a start pending, this will cancel it. =cut sub stop { my $self = shift; if( $self->{pending} ) { delete $self->{pending}; return; } return if !$self->is_running; my $loop = $self->loop or croak "Cannot stop a Timer that is not in a Loop"; defined $self->{id} or return; # nothing to do but no error $loop->unwatch_time( $self->{id} ); undef $self->{id}; } =head1 AUTHOR Paul Evans <leonerd@leonerd.org.uk> =cut 0x55AA;