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