From ecd052098413f87701ba00e28f88563248a177f6 Mon Sep 17 00:00:00 2001 From: Peter Palfrader Date: Wed, 5 Jun 2002 04:05:40 +0000 Subject: Initial Import --- Echolot/Scheduler.pm | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 Echolot/Scheduler.pm (limited to 'Echolot/Scheduler.pm') diff --git a/Echolot/Scheduler.pm b/Echolot/Scheduler.pm new file mode 100644 index 0000000..24ca6e3 --- /dev/null +++ b/Echolot/Scheduler.pm @@ -0,0 +1,150 @@ +package Echolot::Scheduler; + +# (c) 2002 Peter Palfrader +# $Id: Scheduler.pm,v 1.1 2002/06/05 04:05:40 weasel Exp $ +# + +=pod + +=head1 Name + +Echolot::Scheduler - Task selector/scheduler for echolot + +=head1 DESCRIPTION + +This package provides several functions for scheduling tasks within +the ping daemon. + +=over + +=cut + +use strict; +use warnings; +use Carp gw{cluck}; + +my $ORDER = 1; + +=item B () + +Creates a new scheduler object. + +=cut +sub new { + my ($class, %params) = @_; + my $self = {}; + bless $self, $class; + return $self; +}; + +=item B (I, I, I, I) + +Adds a task with I to the list of tasks. Every I seconds +I is called. If for example I is 3600 - meaning I +should be executed hourly - setting I to 600 would mean that +it get's called 10 minutes after the hour. + +=cut +sub add($$$$$) { + my ($self, $name, $interval, $offset, $what) = @_; + + if (defined $self->{'tasks'}->{$name}) { + @{ $self->{'schedule'} } = grep { $_->{'name'} ne $name } @{ $self->{'schedule'} }; + }; + + $self->{'tasks'}->{$name} = + { + interval => $interval, + offset => $offset, + what => $what, + order => $ORDER++ + }; + + $self->schedule($name); + + return 1; +}; + +=item B (I, I) + +Internal function. + +Schedule execution of I for I. If I is not given it is calculated +from I and I passed to B. + +=cut +sub schedule($$;$) { + my ($self, $name, $for) = @_; + + (defined $self->{'tasks'}->{$name}) or + cluck("Task $name is not defined"), + return 0; + + my $interval = $self->{'tasks'}->{$name}->{'interval'}; + my $offset = $self->{'tasks'}->{$name}->{'offset'}; + + + unless (defined $for) { + my $now = time(); + $for = $now - $now % $interval + $offset; + ($for <= $now) and $for += $interval; + }; + + push @{ $self->{'schedule'} }, + { + start => $for, + order => $self->{'tasks'}->{$name}->{'order'}, + name => $name + }; + + @{ $self->{'schedule'} } = sort { $a->{'start'} <=> $b->{'start'} or $a->{'order'} <=> $b->{'order'} } + @{ $self->{'schedule'} }; + + return 1; +}; + +=item B () + +Start the scheduling run. + +It will run forever or until a task with I == 'exit' is executed. + +=cut +sub run($) { + my ($self) = @_; + + my $task = shift @{ $self->{'schedule'} }; + (defined $task) or + croak("Scheduler is empty"), + return 0; + + while(1) { + my $now = time(); + if ($task->{'start'} < $now) { + warn("Task $task->{'name'} could not be started on time\n"); + } else { + sleep ($task->{'start'} - $now); + }; + + $now = $task->{'start'}; + do { + my $name = $task->{'name'}; + (defined $self->{'tasks'}->{$name}) or + warn("Task $task->{'name'} is not defined\n"); + + my $what = $self->{'tasks'}->{$name}->{'what'}; + last if ($what eq 'exit'); + &$what(); + $self->schedule($name, $now + $self->{'tasks'}->{$name}->{'interval'}); + + $task = shift @{ $self->{'schedule'} }; + (defined $task) or + croak("Scheduler is empty"), + return 0; + } while ($now == $task->{'start'}); + }; + + return 1; +}; + +# vim: set ts=4 shiftwidth=4: -- cgit v1.2.3