File Coverage

blib/lib/Alarm/Queued.pm
Criterion Covered Total %
statement 30 76 39.4
branch 3 34 8.8
condition 2 29 6.9
subroutine 9 16 56.2
pod 6 6 100.0
total 50 161 31.0


line stmt bran cond sub pod time code
1             package Alarm::Queued;
2              
3             $VERSION = 1.0;
4              
5 1     1   3668 use strict;
  1         3  
  1         46  
6              
7             =head1 NAME
8              
9             Alarm::Queued - Allow multiple, queued alarms.
10              
11             =head1 DESCRIPTION
12              
13             This module is an attempt to enhance Perl's built-in
14             alarm/C<$SIG{ALRM}> functionality.
15              
16             The built-in function, and its associated signal handler,
17             allow you to arrange for your program to receive a SIGALRM
18             signal, which you can then catch and deal with appropriately.
19              
20             Unfortunately, due to the nature of the design of these
21             signals (at the OS level), you can only have one alarm
22             and handler active at any given time. That's where this
23             module comes in.
24              
25             This module allows you to define multiple alarms, each
26             with an associated handler. These alarms are queued, which
27             means that if you set one alarm and then set another alarm,
28             shorter than the first, the second alarm does not go off
29             until after the first one has gone off and been handled.
30             (If you'd like to have the alarms go off as their set time
31             expires, regardless of whether or not previous alarms are
32             still pending, see Alarm::Concurrent.)
33              
34             To set an alarm, call the C function with the
35             set time of the alarm and a reference to the subroutine
36             to be called when the alarm goes off. You can then go on
37             with your program and the alarm will be called after the
38             set time has passed.
39              
40             It is also possible to set an alarm that does not have a
41             handler associated with it using C.
42             (This function can also be imported into your namespace,
43             in which case it will replace Perl's built-in alarm for
44             your package only.)
45              
46             If an alarm that does not have a handler associated
47             with it goes off, the default handler, pointed to by
48             C<$Alarm::Queued::DEFAULT_HANLDER>, is called. You can
49             change the default handler by assigning to this variable.
50              
51             The default C<$Alarm::Queued::DEFAULT_HANDLER> simply
52             dies with the message "Alarm clock!\n".
53              
54             =head1 IMPORT/EXPORT
55              
56             No methods are exported by default but you can import
57             any of the functions in the L section.
58              
59             You can also import the special tag C<:ALL> which will
60             import all the functions in the L section.
61              
62             =head1 OVERRIDE
63              
64             If you import the special tag C<:OVERRIDE>, this module
65             will override Perl's built-in alarm function for
66             B and it will take over Perl's magic
67             C<%SIG> variable, changing any attempts to read or write
68             C<$SIG{ALRM}> into calls to C and
69             C, respectively.
70              
71             This can be useful when you are calling code that tries
72             to set its own alarm the "old fashioned way." It can also,
73             however, be dangerous. Overriding alarm is documented and
74             should be stable but taking over C<%SIG> is more risky (see
75             L).
76              
77             Note that if you do I override alarm and C<%SIG>, any
78             code you use that sets "legacy alarms" will disable all of
79             your queued alarms. You can call C
80             to reinstall the Alarm::Queued handler. This function may
81             not be imported.
82              
83             =cut
84              
85 1     1   4 use Alarm::_TieSIG; # In case they want to take over $SIG{ALRM}.
  1         1  
  1         16  
86 1     1   4 use Carp;
  1         2  
  1         116  
87              
88 1     1   4 use Exporter;
  1         1  
  1         43  
89 1     1   5 use vars qw( @ISA @EXPORT_OK %EXPORT_TAGS );
  1         1  
  1         174  
90             @ISA = qw(Exporter);
91             @EXPORT_OK = qw(
92             setalarm
93             clearalarm
94             alarm
95             sethandler
96             gethandler
97             );
98             %EXPORT_TAGS = (
99             ALL => [@EXPORT_OK],
100             );
101              
102             #
103             # Exporter doesn't allow hooks for handling
104             # special tags. So, we have to do it ourselves.
105             #
106             sub import {
107 1     1   7 my $thispkg = shift;
108              
109             # Look for and remove special :OVERRIDE tag.
110 1         1 my $override = 0;
111 1 0       2 @_ = grep { ($_ eq ':OVERLOAD') ? ($override = 1, 0) : 1 } @_;
  0         0  
112              
113 1 50       4 if($override) {
114 0         0 $thispkg->export('CORE::GLOBAL', 'alarm');
115 0         0 Alarm::_TieSIG::tiesig(); # ALL YOUR %SIG ARE BELONG TO US!!!
116             };
117              
118 1         70 $thispkg->export_to_level(1, $thispkg, @_); # export the rest
119             }
120              
121             # Called for an alarm with no defined handler.
122             sub _default_handler {
123 0     0   0 die "Alarm clock!\n";
124             }
125              
126 1     1   4 use vars '$DEFAULT_HANDLER';
  1         2  
  1         55  
127             $DEFAULT_HANDLER = \&_default_handler; # Overeridable.
128              
129             #
130             # Each element of @ALARM_QUEUE should be a pointer
131             # to an array containing exactly three elements:
132             #
133             # 0) The duration of the alarm in seconds
134             # 1) The time at which the alarm was set
135             # 2) A pointer to a subroutine that should be called
136             # when the alarm goes off.
137             #
138 1     1   3 use vars qw( @ALARM_QUEUE );
  1         1  
  1         619  
139             @ALARM_QUEUE = ();
140              
141             restore(1); # Install our alarm handler.
142              
143             # Custom alarm handler.
144             sub _alrm {
145 0 0   0   0 return unless(@ALARM_QUEUE);
146              
147             # Call handler for this alarm and remove it from the queue.
148 0   0     0 my $handler = shift(@ALARM_QUEUE)->[2] || $DEFAULT_HANDLER;
149 0         0 $handler->();
150              
151 0         0 while(@ALARM_QUEUE) {
152 0         0 my $time_remaining = $ALARM_QUEUE[0][1]+$ALARM_QUEUE[0][0]-time;
153 0 0       0 if($time_remaining <= 0) {
154 0   0     0 $handler = shift(@ALARM_QUEUE)->[2] || $DEFAULT_HANDLER;
155 0         0 $handler->(); # Call handler for this alarm.
156             } else {
157 0         0 CORE::alarm($time_remaining);
158 0         0 last;
159             }
160             }
161             }
162              
163              
164             #********************************************************************#
165              
166             =head1 FUNCTIONS
167              
168             The following functions are available for use.
169              
170             =over 4
171              
172             =item setalarm SECONDS CODEREF
173              
174             Sets a new alarm and associates a handler with it.
175             This handler is called when the specified number of
176             seconds have elapsed I all previous alarms
177             have gone off. See L for
178             more information.
179              
180             =cut
181             sub setalarm($$) {
182 0     0 1 0 my ($alarm, $code) = @_;
183              
184 0 0 0     0 unless(not defined($code) or UNIVERSAL::isa($code, 'CODE')) {
185 0         0 croak("Alarm handler must be CODEREF");
186             }
187              
188 0         0 push( @ALARM_QUEUE, [ $alarm, time(), $code ] );
189 0 0       0 CORE::alarm($alarm) if(@ALARM_QUEUE == 1);
190             }
191              
192             =item clearalarm INDEX LENGTH
193              
194             =item clearalarm INDEX
195              
196             =item clearalarm
197              
198             Clears one or more previously set alarms. The index is
199             an array index, with 0 being the currently active alarm
200             and -1 being the last (most recent) alarm that was set.
201              
202             INDEX defaults to 0 and LENGTH defaults to 1.
203              
204             If you clear the active alarm and it was blocking other
205             alarms from going off, those alarms are immediately triggered.
206              
207             =cut
208             sub clearalarm(;$$) {
209 0   0 0 1 0 my $index = shift || 0;
210 0   0     0 my $length = shift || 1;
211              
212 0         0 splice @ALARM_QUEUE, $index, $length;
213              
214 0 0       0 unless($index) {
215 0         0 while(@ALARM_QUEUE) {
216 0         0 my $time_remaining = $ALARM_QUEUE[0][1]+$ALARM_QUEUE[0][0]-time;
217 0 0       0 if($time_remaining <= 0) {
218 0   0     0 my $handler = shift(@ALARM_QUEUE)->[2] || \&default_handler;
219 0         0 $handler->(); # Call handler for this alarm.
220             } else {
221 0         0 CORE::alarm($time_remaining);
222 0         0 last;
223             }
224             }
225             }
226             }
227              
228             =item alarm SECONDS
229              
230             =item alarm
231              
232             Creates a new alarm with no handler. A handler can
233             later be set for it via sethandler() or C<$SIG{ALRM}>,
234             if overridden.
235              
236             For the most part, this function behaves exactly like
237             Perl's built-in alarm function, except that it sets up a
238             concurrent alarm instead. Thus, each call to alarm does
239             not disable previous alarms unless called with a set time
240             of 0.
241              
242             Calling C with a set time of 0 will disable the
243             last alarm set.
244              
245             If SECONDS is not specified, the value stored in C<$_>
246             is used.
247              
248             =cut
249             sub alarm(;$) {
250 0 0   0 1 0 my $alarm = @_ ? shift : $_;
251              
252 0 0       0 if($alarm == 0) {
253 0         0 clearalarm(-1);
254             } else {
255 0         0 push( @ALARM_QUEUE, [ $alarm, time(), undef ] );
256 0 0       0 CORE::alarm($alarm) if(@ALARM_QUEUE == 1);
257             }
258             }
259              
260             =item sethandler INDEX CODEREF
261              
262             =item sethandler CODEREF
263              
264             Sets a handler for the alarm found at INDEX in the queue. This
265             is an array index, so negative values may be used to indicate
266             a position relative to the end of the queue.
267              
268             If INDEX is not specified, the handler is set for the last
269             alarm in the queue that doesn't have one associated with it.
270             This means that if you set multiple alarms using C,
271             you should arrange their respective C's in the
272             I order.
273              
274             =cut
275             sub sethandler($;$) {
276              
277 0 0 0 0 1 0 unless(not defined($_[-1]) or UNIVERSAL::isa($_[-1], 'CODE')) {
278 0         0 croak("Alarm handler must be CODEREF");
279             }
280              
281 0 0       0 if(@_ == 2) {
282 0         0 $ALARM_QUEUE[$_[0]]->[2] = $_[1];
283             } else {
284 0         0 foreach my $alarm (reverse @ALARM_QUEUE) {
285 0 0       0 if(not defined $alarm->[2]) {
286 0         0 $alarm->[2] = shift();
287 0         0 last;
288             }
289             }
290             }
291             }
292              
293             =item gethandler INDEX
294              
295             =item gethandler
296              
297             Returns the handler for the alarm found at INDEX in the queue.
298             This is an array index, so negative values may be used.
299              
300             If INDEX is not specified, returns the handler for the currently
301             active alarm.
302              
303             =cut
304             sub gethandler(;$) {
305 0   0 0 1 0 my $index = shift || 0;
306             return(
307 0 0 0     0 ($index < @ALARM_QUEUE and $index > -1)
308             ?
309             $ALARM_QUEUE[$index][2]
310             :
311             undef
312             );
313             }
314              
315             =item restore FLAG
316              
317             =item restore
318              
319             This function reinstalls the Alarm::Queued alarm handler
320             if it has been replaced by a "legacy alarm handler."
321              
322             If FLAG is present and true, C will save the
323             current handler by setting it as a new queued alarm (as
324             if you had called C for it).
325              
326             This function may not be imported.
327              
328             Note: Do B call this function if you have imported
329             the C<:OVERLOAD> symbol. It can have unpredictable results.
330              
331             =cut
332             sub restore(;$) {
333 1 50 33 1 1 9 return if(defined($SIG{ALRM}) and $SIG{ALRM} == \&_alrm);
334              
335 1         7 my $oldalrm = CORE::alarm(5);
336              
337 1 50 33     6 if($oldalrm and shift) {
338             # Save legacy alarm.
339 0         0 setalarm($oldalrm, $SIG{ALRM});
340             }
341              
342             # Install our alarm handler.
343 1         9 $SIG{ALRM} = \&_alrm;
344             }
345              
346             =head1 CAVEATS
347              
348             =over 4
349              
350             =item *
351              
352             C<%SIG> is Perl magic and should probably not be messed
353             with, though I have not witnessed any problems in the
354             (admittedly limited) testing I've done. I would be
355             interested to hear from anyone who performs extensive
356             testing, with different versions of Perl, of the
357             reliability of doing this.
358              
359             Moreover, since there is no way to just take over
360             C<$SIG{ALRM}>, the entire magic hash is usurped and any
361             other C<%SIG}> accesses are simply passed through to the
362             original magic hash. This means that if there I any
363             problems, they will most likely affect all other signal
364             handlers you have defined, including C<$SIG{__WARN__}>
365             and C<$SIG{__DIE__}> and others.
366              
367             In other words, if you're going to use the :OVERRIDE
368             option, you do so at your own risk (and you'd better be
369             pretty damn sure of yourself, too).
370              
371             =item *
372              
373             The default C<$DEFAULT_HANDLER> simply dies with the
374             message "Alarm clock!\n".
375              
376             =item *
377              
378             All warnings about alarms possibly being off by up to a full
379             second still apply. See the documentation for alarm for more
380             information.
381              
382             =item *
383              
384             The alarm handling routine does not make any allowances
385             for systems that clear the alarm handler before it is
386             called. This may be changed in the future.
387              
388             =item *
389              
390             According to L, doing just about I
391             in signal handling routines is dangerous because it might
392             be called during a non-re-entrant system library routines
393             which could cause a memory fault and core dump.
394              
395             The Alarm::Queued alarm handling routine does quite a bit.
396              
397             You have been warned.
398              
399             =back
400              
401             =head1 AUTHOR
402              
403             Written by Cory Johns (c) 2001.
404              
405             =cut
406              
407             1;