File Coverage

blib/lib/Net/Peep/Scheduler.pm
Criterion Covered Total %
statement 74 82 90.2
branch 12 18 66.6
condition 4 11 36.3
subroutine 16 18 88.8
pod 0 9 0.0
total 106 138 76.8


line stmt bran cond sub pod time code
1             package Net::Peep::Scheduler;
2              
3             require 5.00503;
4 3     3   1131 use strict;
  3         7  
  3         103  
5             # use warnings; # commented out for 5.005 compatibility
6 3     3   16 use Carp;
  3         4  
  3         178  
7 3     3   932 use Data::Dumper;
  3         10630  
  3         173  
8 3     3   1071 use Time::HiRes qw{ tv_interval gettimeofday alarm };
  3         1727  
  3         23  
9 3     3   1144 use Net::Peep::Log;
  3         5  
  3         144  
10              
11             require Exporter;
12              
13 3     3   15 use vars qw{ @ISA %EXPORT_TAGS @EXPORT_OK @EXPORT $VERSION };
  3         16  
  3         495  
14              
15             @ISA = qw(Exporter);
16             %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
17             @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
18             @EXPORT = qw( );
19             $VERSION = do { my @r = (q$Revision: 1.2 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };
20              
21             # structure of an event
22             # $entry = {
23             # 'application' => The application name
24             # 'schedule_time' => the time for wakeup
25             # 'type' => the type of event
26             # 'data' => the data to pass to the handler
27             # 'handler' => the handler to invoke
28             # }
29              
30             # The scheduled event queue
31 3     3   14 use vars qw( @scheduler_queue );
  3         5  
  3         3107  
32              
33             sub new {
34              
35 5     5 0 448 my $self = shift;
36 5   33     43 my $class = ref($self) || $self;
37 5         15 my $this = { };
38 5         16 bless $this, $class;
39              
40             # Init the scheduler
41 5         21 $this->logger()->debug(8, "Registering scheduler and scheduling alarm ...");
42 5     1   139 $SIG{'ALRM'} = sub { $this->schedulerWakeUp };
  1         2999904  
43              
44 5         24 return $this;
45              
46             } #end sub new
47              
48             # returns a logging object
49             sub logger {
50              
51 16     16 0 38 my $self = shift;
52 16 100       99 unless ( exists $self->{'__LOGGER'} ) { $self->{'__LOGGER'} = new Net::Peep::Log }
  5         41  
53 16         167 return $self->{'__LOGGER'};
54              
55             } #end sub logger
56              
57             sub schedulerAddEvent {
58              
59 3     3 0 356 my ($self, $app, $sleepsec, $sleepusec, $type, $handler, $data, $repeated) = @_;
60              
61             # Do some sanity checking
62 3 50       8 confess "Error: No application name given to scheduler when adding event." unless $app;
63 3 50 33     11 confess "Error: Wakeup given to scheduler is in the past." unless $sleepsec > 0.0 || $sleepusec > 0.0;
64 3 50       9 confess "Error: No scheduled event type given to scheduler when adding event." unless $type;
65 3 50       11 confess "Error: No handler given to scheduler when adding event." unless $handler;
66              
67 3         18 my ($s, $usec) = gettimeofday();
68              
69 3         29 my $entry = {
70             'application' => $app,
71             'sleepsec' => $sleepsec,
72             'sleepusec' => $sleepusec,
73             'schedule_time' => [ $s + $sleepsec, $usec + $sleepusec ],
74             'type' => $type,
75             'data' => $data,
76             'handler' => $handler,
77             'repeated' => $repeated,
78             };
79              
80             # Add the entry into the scheduler queue and sort by time
81 3         7 push @scheduler_queue, $entry;
82 4         9 @scheduler_queue = sort {
83 3         12 my ($asec, $ausec) = @{ $a->{'schedule_time'} };
  4         5  
84 4         7 my ($bsec, $busec) = @{ $b->{'schedule_time'} };
  4         48  
85 4         13 $asec + 0.000001 * $ausec <=> $bsec + 0.000001 * $busec;
86             } @scheduler_queue;
87              
88             # Now sleep for the new time
89 3         9 $self->schedulerSleep;
90              
91             } #end sub schedulerAddEvent
92              
93             sub schedulerRemoveEventsForApp {
94              
95             # Removes all entries in the scheduler queue for an application
96              
97 0     0 0 0 my $self = shift;
98 0   0     0 my $app = shift || die "Application name not found!";
99              
100 0         0 @scheduler_queue = grep ! $_->{'app'} eq $app, @scheduler_queue;
101            
102              
103             } # end sub schedulerRemoveEventsForApp
104              
105             sub schedulerGetEvent {
106              
107 3     3 0 10 my $self = shift;
108 3         13 return (shift @scheduler_queue);
109              
110             } #end sub schedulerGetEvent
111              
112             sub schedulerCalcSleepTime {
113              
114 6     6 0 11 my $self = shift;
115 6         14 my $nextent = $scheduler_queue[0];
116              
117             # Check if we have an empty queue
118 6 100       20 unless ( $nextent ) { return undef; }
  1         10  
119              
120 5         71 my $sleeptime = tv_interval ( [ gettimeofday() ], $nextent->{'schedule_time'} );
121 5         79 return $sleeptime;
122              
123             } #end sub schedulerCalcSleepTime
124              
125             sub schedulerSleep {
126              
127 6     6 0 13 my ($self, $time) = @_;
128 6   66     42 my $sleeptime = $time || $self->schedulerCalcSleepTime;
129              
130             # Check if there's no such sleep time at this moment
131 6 100       22 unless ( $sleeptime ) { return undef; }
  1         20  
132              
133 5         16 $self->logger()->debug(8, "Scheduler will wake up in $sleeptime seconds.");
134 5         49 alarm ( $sleeptime );
135 5         51 return $sleeptime;
136              
137             } #end sub schedulerSleep
138              
139             sub schedulerExplicitWakeUp {
140              
141 0     0 0 0 my $self = shift;
142 0         0 $self->logger()->debug(8, "Scheduler received explicit wake up...");
143 0         0 $self->schedulerWakeUp;
144              
145             } #end sub schedulerExplicitWakeUp
146              
147             sub schedulerWakeUp {
148              
149 3     3 0 16 my $self = shift;
150 3         188 $self->logger()->debug(8, "Scheduler woke up.");
151 3         15 my $entry = $self->schedulerGetEvent;
152              
153             # Doesn't apply because a schedulerExplicitWakeUp call would violate this and
154             # still be valid
155             #
156             # # Check that the time has past
157             # unless ( &Time::HiRes::tv_interval ( [ &Time::HiRes::gettimeofday() ], $entry->{'schedule_time'}) < 0.0 ) {
158             # $self->logger()->debug(8, "Scheduled event was premature - returned error.");
159             # return "Error: Scheduler woke up prematurely.";
160             # }
161              
162             # Check if this is an internal housekeeping entry
163             # Otherwise, pass control and data to the handler
164 3 50       20 if ($entry->{'application'} eq '__SCHEDULER') {
165             # internal processing - reserved for future use
166 0         0 $self->logger()->debug(8, "Processing internal event...");
167             }
168             else {
169             # Otherwise, call the handler with arguments of the type
170             # of scheduled event and the data associated
171 3         51 $self->logger()->debug(8, "Invoking event handler for ". $entry->{'application'}. " of type ". $entry->{'type'}. " ...");
172 3         11 &{ $entry->{'handler'} } ( $entry->{'type'}, $entry->{'data'} );
  3         26  
173 3 50       591 if ($entry->{'repeated'}) {
174              
175             # if it's a repeated event, it should
176             # reschedule itself
177              
178             # note that repeated events don't happen
179             # precisely every sleepsec + 0.000001 *
180             # sleepusec because of a delay every cycle
181             # imposed by the execution time of the handler
182              
183 0         0 $self->schedulerAddEvent(
184             $entry->{'application'},
185             $entry->{'sleepsec'},
186             $entry->{'sleepusec'},
187             $entry->{'type'},
188             $entry->{'handler'},
189             $entry->{'data'},
190             $entry->{'repeated'}
191             );
192             }
193             }
194              
195             # Reassign ourselves before we exit
196 3     2   72 $SIG{'ALRM'} = sub { $self->schedulerWakeUp };
  2         2958095  
197 3         16 $self->schedulerSleep;
198              
199             } #end sub schedulerWakeUp
200              
201             1;
202             __END__