Add built local::lib
[catagits/Gitalist.git] / local-lib5 / lib / perl5 / IPC / Run / Timer.pm
CommitLineData
3fea05b9 1package IPC::Run::Timer;
2
3=pod
4
5=head1 NAME
6
7IPC::Run::Timer -- Timer channels for IPC::Run.
8
9=head1 SYNOPSIS
10
11 use IPC::Run qw( run timer timeout );
12 ## or IPC::Run::Timer ( timer timeout );
13 ## or IPC::Run::Timer ( :all );
14
15 ## A non-fatal timer:
16 $t = timer( 5 ); # or...
17 $t = IO::Run::Timer->new( 5 );
18 run $t, ...;
19
20 ## A timeout (which is a timer that dies on expiry):
21 $t = timeout( 5 ); # or...
22 $t = IO::Run::Timer->new( 5, exception => "harness timed out" );
23
24=head1 DESCRIPTION
25
26This class and module allows timers and timeouts to be created for use
27by IPC::Run. A timer simply expires when it's time is up. A timeout
28is a timer that throws an exception when it expires.
29
30Timeouts are usually a bit simpler to use than timers: they throw an
31exception on expiration so you don't need to check them:
32
33 ## Give @cmd 10 seconds to get started, then 5 seconds to respond
34 my $t = timeout( 10 );
35 $h = start(
36 \@cmd, \$in, \$out,
37 $t,
38 );
39 pump $h until $out =~ /prompt/;
40
41 $in = "some stimulus";
42 $out = '';
43 $t->time( 5 )
44 pump $h until $out =~ /expected response/;
45
46You do need to check timers:
47
48 ## Give @cmd 10 seconds to get started, then 5 seconds to respond
49 my $t = timer( 10 );
50 $h = start(
51 \@cmd, \$in, \$out,
52 $t,
53 );
54 pump $h until $t->is_expired || $out =~ /prompt/;
55
56 $in = "some stimulus";
57 $out = '';
58 $t->time( 5 )
59 pump $h until $out =~ /expected response/ || $t->is_expired;
60
61Timers and timeouts that are reset get started by start() and
62pump(). Timers change state only in pump(). Since run() and
63finish() both call pump(), they act like pump() with repect to
64timers.
65
66Timers and timeouts have three states: reset, running, and expired.
67Setting the timeout value resets the timer, as does calling
68the reset() method. The start() method starts (or restarts) a
69timer with the most recently set time value, no matter what state
70it's in.
71
72=head2 Time values
73
74All time values are in seconds. Times may be specified as integer or
75floating point seconds, optionally preceded by puncuation-separated
76days, hours, and minutes.\
77
78Examples:
79
80 1 1 second
81 1.1 1.1 seconds
82 60 60 seconds
83 1:0 1 minute
84 1:1 1 minute, 1 second
85 1:90 2 minutes, 30 seconds
86 1:2:3:4.5 1 day, 2 hours, 3 minutes, 4.5 seconds
87
88Absolute date/time strings are *not* accepted: year, month and
89day-of-month parsing is not available (patches welcome :-).
90
91=head2 Interval fudging
92
93When calculating an end time from a start time and an interval, IPC::Run::Timer
94instances add a little fudge factor. This is to ensure that no time will
95expire before the interval is up.
96
97First a little background. Time is sampled in discrete increments. We'll
98call the
99exact moment that the reported time increments from one interval to the
100next a tick, and the interval between ticks as the time period. Here's
101a diagram of three ticks and the periods between them:
102
103
104 -0-0-0-0-0-0-0-0-0-0-1-1-1-1-1-1-1-1-1-1-2-...
105 ^ ^ ^
106 |<--- period 0 ---->|<--- period 1 ---->|
107 | | |
108 tick 0 tick 1 tick 2
109
110To see why the fudge factor is necessary, consider what would happen
111when a timer with an interval of 1 second is started right at the end of
112period 0:
113
114
115 -0-0-0-0-0-0-0-0-0-0-1-1-1-1-1-1-1-1-1-1-2-...
116 ^ ^ ^ ^
117 | | | |
118 | | | |
119 tick 0 |tick 1 tick 2
120 |
121 start $t
122
123Assuming that check() is called many times per period, then the timer
124is likely to expire just after tick 1, since the time reported will have
125lept from the value '0' to the value '1':
126
127 -0-0-0-0-0-0-0-0-0-0-1-1-1-1-1-1-1-1-1-1-2-...
128 ^ ^ ^ ^ ^
129 | | | | |
130 | | | | |
131 tick 0 |tick 1| tick 2
132 | |
133 start $t |
134 |
135 check $t
136
137Adding a fudge of '1' in this example means that the timer is guaranteed
138not to expire before tick 2.
139
140The fudge is not added to an interval of '0'.
141
142This means that intervals guarantee a minimum interval. Given that
143the process running perl may be suspended for some period of time, or that
144it gets busy doing something time-consuming, there are no other guarantees on
145how long it will take a timer to expire.
146
147=head1 SUBCLASSING
148
149INCOMPATIBLE CHANGE: Due to the awkwardness introduced by ripping
150pseudohashes out of Perl, this class I<no longer> uses the fields
151pragma.
152
153=head1 FUNCTIONS & METHODS
154
155=over
156
157=cut
158
159use strict;
160use Carp;
161use Fcntl;
162use Symbol;
163use Exporter;
164use vars qw( $VERSION @ISA @EXPORT_OK %EXPORT_TAGS );
165BEGIN {
166 $VERSION = '0.84';
167 @ISA = qw( Exporter );
168 @EXPORT_OK = qw(
169 check
170 end_time
171 exception
172 expire
173 interval
174 is_expired
175 is_reset
176 is_running
177 name
178 reset
179 start
180 timeout
181 timer
182 );
183
184 %EXPORT_TAGS = ( 'all' => \@EXPORT_OK );
185}
186
187require IPC::Run;
188use IPC::Run::Debug;
189
190##
191## Some helpers
192##
193my $resolution = 1;
194
195sub _parse_time {
196 for ( $_[0] ) {
197 return $_ unless defined $_;
198 return $_ if /^\d*(?:\.\d*)?$/;
199
200 my @f = reverse split( /[^\d\.]+/i );
201 croak "IPC::Run: invalid time string '$_'" unless @f <= 4;
202 my ( $s, $m, $h, $d ) = @f;
203 return
204 ( (
205 ( $d || 0 ) * 24
206 + ( $h || 0 ) ) * 60
207 + ( $m || 0 ) ) * 60
208 + ( $s || 0 );
209 }
210}
211
212sub _calc_end_time {
213 my IPC::Run::Timer $self = shift;
214 my $interval = $self->interval;
215 $interval += $resolution if $interval;
216 $self->end_time( $self->start_time + $interval );
217}
218
219
220=item timer
221
222A constructor function (not method) of IPC::Run::Timer instances:
223
224 $t = timer( 5 );
225 $t = timer( 5, name => 'stall timer', debug => 1 );
226
227 $t = timer;
228 $t->interval( 5 );
229
230 run ..., $t;
231 run ..., $t = timer( 5 );
232
233This convenience function is a shortened spelling of
234
235 IPC::Run::Timer->new( ... );
236
237. It returns a timer in the reset state with a given interval.
238
239If an exception is provided, it will be thrown when the timer notices that
240it has expired (in check()). The name is for debugging usage, if you plan on
241having multiple timers around. If no name is provided, a name like "timer #1"
242will be provided.
243
244=cut
245
246sub timer {
247 return IPC::Run::Timer->new( @_ );
248}
249
250
251=item timeout
252
253A constructor function (not method) of IPC::Run::Timer instances:
254
255 $t = timeout( 5 );
256 $t = timeout( 5, exception => "kablooey" );
257 $t = timeout( 5, name => "stall", exception => "kablooey" );
258
259 $t = timeout;
260 $t->interval( 5 );
261
262 run ..., $t;
263 run ..., $t = timeout( 5 );
264
265A This convenience function is a shortened spelling of
266
267 IPC::Run::Timer->new( exception => "IPC::Run: timeout ...", ... );
268
269. It returns a timer in the reset state that will throw an
270exception when it expires.
271
272Takes the same parameters as L</timer>, any exception passed in overrides
273the default exception.
274
275=cut
276
277sub timeout {
278 my $t = IPC::Run::Timer->new( @_ );
279 $t->exception( "IPC::Run: timeout on " . $t->name )
280 unless defined $t->exception;
281 return $t;
282}
283
284
285=item new
286
287 IPC::Run::Timer->new() ;
288 IPC::Run::Timer->new( 5 ) ;
289 IPC::Run::Timer->new( 5, exception => 'kablooey' ) ;
290
291Constructor. See L</timer> for details.
292
293=cut
294
295my $timer_counter;
296
297
298sub new {
299 my $class = shift;
300 $class = ref $class || $class;
301
302 my IPC::Run::Timer $self = bless {}, $class;
303
304 $self->{STATE} = 0;
305 $self->{DEBUG} = 0;
306 $self->{NAME} = "timer #" . ++$timer_counter;
307
308 while ( @_ ) {
309 my $arg = shift;
310 if ( $arg =~ /^(?:\d+[^\a\d]){0,3}\d*(?:\.\d*)?$/ ) {
311 $self->interval( $arg );
312 }
313 elsif ( $arg eq 'exception' ) {
314 $self->exception( shift );
315 }
316 elsif ( $arg eq 'name' ) {
317 $self->name( shift );
318 }
319 elsif ( $arg eq 'debug' ) {
320 $self->debug( shift );
321 }
322 else {
323 croak "IPC::Run: unexpected parameter '$arg'";
324 }
325 }
326
327 _debug $self->name . ' constructed'
328 if $self->{DEBUG} || _debugging_details;
329
330 return $self;
331}
332
333=item check
334
335 check $t;
336 check $t, $now;
337 $t->check;
338
339Checks to see if a timer has expired since the last check. Has no effect
340on non-running timers. This will throw an exception if one is defined.
341
342IPC::Run::pump() calls this routine for any timers in the harness.
343
344You may pass in a version of now, which is useful in case you have
345it lying around or you want to check several timers with a consistent
346concept of the current time.
347
348Returns the time left before end_time or 0 if end_time is no longer
349in the future or the timer is not running
350(unless, of course, check() expire()s the timer and this
351results in an exception being thrown).
352
353Returns undef if the timer is not running on entry, 0 if check() expires it,
354and the time left if it's left running.
355
356=cut
357
358sub check {
359 my IPC::Run::Timer $self = shift;
360 return undef if ! $self->is_running;
361 return 0 if $self->is_expired;
362
363 my ( $now ) = @_;
364 $now = _parse_time( $now );
365 $now = time unless defined $now;
366
367 _debug(
368 "checking ", $self->name, " (end time ", $self->end_time, ") at ", $now
369 ) if $self->{DEBUG} || _debugging_details;
370
371 my $left = $self->end_time - $now;
372 return $left if $left > 0;
373
374 $self->expire;
375 return 0;
376}
377
378
379=item debug
380
381Sets/gets the current setting of the debugging flag for this timer. This
382has no effect if debugging is not enabled for the current harness.
383
384=cut
385
386
387sub debug {
388 my IPC::Run::Timer $self = shift;
389 $self->{DEBUG} = shift if @_;
390 return $self->{DEBUG};
391}
392
393
394=item end_time
395
396 $et = $t->end_time;
397 $et = end_time $t;
398
399 $t->end_time( time + 10 );
400
401Returns the time when this timer will or did expire. Even if this time is
402in the past, the timer may not be expired, since check() may not have been
403called yet.
404
405Note that this end_time is not start_time($t) + interval($t), since some
406small extra amount of time is added to make sure that the timer does not
407expire before interval() elapses. If this were not so, then
408
409Changing end_time() while a timer is running will set the expiration time.
410Changing it while it is expired has no affect, since reset()ing a timer always
411clears the end_time().
412
413=cut
414
415
416sub end_time {
417 my IPC::Run::Timer $self = shift;
418 if ( @_ ) {
419 $self->{END_TIME} = shift;
420 _debug $self->name, ' end_time set to ', $self->{END_TIME}
421 if $self->{DEBUG} > 2 || _debugging_details;
422 }
423 return $self->{END_TIME};
424}
425
426
427=item exception
428
429 $x = $t->exception;
430 $t->exception( $x );
431 $t->exception( undef );
432
433Sets/gets the exception to throw, if any. 'undef' means that no
434exception will be thrown. Exception does not need to be a scalar: you
435may ask that references be thrown.
436
437=cut
438
439
440sub exception {
441 my IPC::Run::Timer $self = shift;
442 if ( @_ ) {
443 $self->{EXCEPTION} = shift;
444 _debug $self->name, ' exception set to ', $self->{EXCEPTION}
445 if $self->{DEBUG} || _debugging_details;
446 }
447 return $self->{EXCEPTION};
448}
449
450
451=item interval
452
453 $i = interval $t;
454 $i = $t->interval;
455 $t->interval( $i );
456
457Sets the interval. Sets the end time based on the start_time() and the
458interval (and a little fudge) if the timer is running.
459
460=cut
461
462sub interval {
463 my IPC::Run::Timer $self = shift;
464 if ( @_ ) {
465 $self->{INTERVAL} = _parse_time( shift );
466 _debug $self->name, ' interval set to ', $self->{INTERVAL}
467 if $self->{DEBUG} > 2 || _debugging_details;
468
469 $self->_calc_end_time if $self->state;
470 }
471 return $self->{INTERVAL};
472}
473
474
475=item expire
476
477 expire $t;
478 $t->expire;
479
480Sets the state to expired (undef).
481Will throw an exception if one
482is defined and the timer was not already expired. You can expire a
483reset timer without starting it.
484
485=cut
486
487
488sub expire {
489 my IPC::Run::Timer $self = shift;
490 if ( defined $self->state ) {
491 _debug $self->name . ' expired'
492 if $self->{DEBUG} || _debugging;
493
494 $self->state( undef );
495 croak $self->exception if $self->exception;
496 }
497 return undef;
498}
499
500
501=item is_running
502
503=cut
504
505
506sub is_running {
507 my IPC::Run::Timer $self = shift;
508 return $self->state ? 1 : 0;
509}
510
511
512=item is_reset
513
514=cut
515
516sub is_reset {
517 my IPC::Run::Timer $self = shift;
518 return defined $self->state && $self->state == 0;
519}
520
521
522=item is_expired
523
524=cut
525
526sub is_expired {
527 my IPC::Run::Timer $self = shift;
528 return ! defined $self->state;
529}
530
531=item name
532
533Sets/gets this timer's name. The name is only used for debugging
534purposes so you can tell which freakin' timer is doing what.
535
536=cut
537
538sub name {
539 my IPC::Run::Timer $self = shift;
540
541 $self->{NAME} = shift if @_;
542 return defined $self->{NAME}
543 ? $self->{NAME}
544 : defined $self->{EXCEPTION}
545 ? 'timeout'
546 : 'timer';
547}
548
549
550=item reset
551
552 reset $t;
553 $t->reset;
554
555Resets the timer to the non-running, non-expired state and clears
556the end_time().
557
558=cut
559
560sub reset {
561 my IPC::Run::Timer $self = shift;
562 $self->state( 0 );
563 $self->end_time( undef );
564 _debug $self->name . ' reset'
565 if $self->{DEBUG} || _debugging;
566
567 return undef;
568}
569
570
571=item start
572
573 start $t;
574 $t->start;
575 start $t, $interval;
576 start $t, $interval, $now;
577
578Starts or restarts a timer. This always sets the start_time. It sets the
579end_time based on the interval if the timer is running or if no end time
580has been set.
581
582You may pass an optional interval or current time value.
583
584Not passing a defined interval causes the previous interval setting to be
585re-used unless the timer is reset and an end_time has been set
586(an exception is thrown if no interval has been set).
587
588Not passing a defined current time value causes the current time to be used.
589
590Passing a current time value is useful if you happen to have a time value
591lying around or if you want to make sure that several timers are started
592with the same concept of start time. You might even need to lie to an
593IPC::Run::Timer, occasionally.
594
595=cut
596
597sub start {
598 my IPC::Run::Timer $self = shift;
599
600 my ( $interval, $now ) = map { _parse_time( $_ ) } @_;
601 $now = _parse_time( $now );
602 $now = time unless defined $now;
603
604 $self->interval( $interval ) if defined $interval;
605
606 ## start()ing a running or expired timer clears the end_time, so that the
607 ## interval is used. So does specifying an interval.
608 $self->end_time( undef ) if ! $self->is_reset || $interval;
609
610 croak "IPC::Run: no timer interval or end_time defined for " . $self->name
611 unless defined $self->interval || defined $self->end_time;
612
613 $self->state( 1 );
614 $self->start_time( $now );
615 ## The "+ 1" is in case the START_TIME was sampled at the end of a
616 ## tick (which are one second long in this module).
617 $self->_calc_end_time
618 unless defined $self->end_time;
619
620 _debug(
621 $self->name, " started at ", $self->start_time,
622 ", with interval ", $self->interval, ", end_time ", $self->end_time
623 ) if $self->{DEBUG} || _debugging;
624 return undef;
625}
626
627
628=item start_time
629
630Sets/gets the start time, in seconds since the epoch. Setting this manually
631is a bad idea, it's better to call L</start>() at the correct time.
632
633=cut
634
635
636sub start_time {
637 my IPC::Run::Timer $self = shift;
638 if ( @_ ) {
639 $self->{START_TIME} = _parse_time( shift );
640 _debug $self->name, ' start_time set to ', $self->{START_TIME}
641 if $self->{DEBUG} > 2 || _debugging;
642 }
643
644 return $self->{START_TIME};
645}
646
647
648=item state
649
650 $s = state $t;
651 $t->state( $s );
652
653Get/Set the current state. Only use this if you really need to transfer the
654state to/from some variable.
655Use L</expire>, L</start>, L</reset>, L</is_expired>, L</is_running>,
656L</is_reset>.
657
658Note: Setting the state to 'undef' to expire a timer will not throw an
659exception.
660
661=cut
662
663sub state {
664 my IPC::Run::Timer $self = shift;
665 if ( @_ ) {
666 $self->{STATE} = shift;
667 _debug $self->name, ' state set to ', $self->{STATE}
668 if $self->{DEBUG} > 2 || _debugging;
669 }
670 return $self->{STATE};
671}
672
673
6741;
675
676=pod
677
678=back
679
680=head1 TODO
681
682use Time::HiRes; if it's present.
683
684Add detection and parsing of [[[HH:]MM:]SS formatted times and intervals.
685
686=head1 AUTHOR
687
688Barrie Slaymaker <barries@slaysys.com>
689
690=cut