IPC::Run::Timer(3)
π NAME π
IPC::Run::Timer β timer channels for IPC::Run. yes bestie, that's literally the whole thing. this is the IPC::Run::Timer(3) page from the User Contributed Perl Documentation, and we're about to make timers make sense. π«Ά
πΈ SYNOPSIS πΈ
okay so here's the whole menu, take whatever you need:
use IPC::Run qw( run timer timeout );
## or IPC::Run::Timer ( timer timeout );
## or IPC::Run::Timer ( :all );
## A non-fatal timer:
$t = timer( 5 ); # or...
$t = IO::Run::Timer->new( 5 );
run $t, ...;
## A timeout (which is a timer that dies on expiry):
$t = timeout( 5 ); # or...
$t = IO::Run::Timer->new( 5, exception => "harness timed out" );
β¨ DESCRIPTION β¨
This class and module lets you create timers and timeouts for IPC::Run to use. the tea β:
- a timer simply expires when its time is up. no drama, it just vibes until it's done.
- a timeout is a timer with main character energy β when it expires it throws an exception. π
Timeouts are usually a lil bit simpler to use than timers, because they throw an exception on expiration, so you literally don't need to check them:
## Give @cmd 10 seconds to get started, then 5 seconds to respond
my $t = timeout( 10 );
$h = start(
\@cmd, \$in, \$out,
$t,
);
pump $h until $out =~ /prompt/;
$in = "some stimulus";
$out = '';
$t->time( 5 )
pump $h until $out =~ /expected response/;
Timers tho? you DO need to check those, bestie:
## Give @cmd 10 seconds to get started, then 5 seconds to respond
my $t = timer( 10 );
$h = start(
\@cmd, \$in, \$out,
$t,
);
pump $h until $t->is_expired || $out =~ /prompt/;
$in = "some stimulus";
$out = '';
$t->time( 5 )
pump $h until $out =~ /expected response/ || $t->is_expired;
so timers and timeouts that get reset get started by start() and pump(). and here's the important part β timers only change state in pump(). and since run() and finish() both call pump() under the hood, they act exactly like pump() when it comes to timers. β¨
Timers and timeouts have three states:
- reset
- running
- expired
Setting the timeout value resets the timer, and calling the reset() method does the same thing. Meanwhile start() starts (or restarts) a timer using the most recently set time value β no matter what state it's in. iconic, honestly.
β° Time values β°
Every time value is in seconds. a time can be any kind of perl number β integer or floating point seconds β and it can optionally be preceded by days, hours and minutes separated by punctuation. π°οΈ
Examples:
1 1 second
1.1 1.1 seconds
60 60 seconds
1:0 1 minute
1:1 1 minute, 1 second
1:90 2 minutes, 30 seconds
1:2:3:4.5 1 day, 2 hours, 3 minutes, 4.5 seconds
'inf' the infinity perl special number (the timer never finishes)
π¨ absolute date/time strings are NOT accepted! year, month and day-of-month parsing is not available (patches welcome :-). so don't roll up with a calendar date expecting it to slay, because it will not. π
π Interval fudging π
When it's calculating an end time from a start time plus an interval, IPC::Run::Timer instances add a lil fudge factor. why? to make sure that no time will expire before the interval is up. it's giving protective bestie energy. π«Ά
first, some background, because the lore matters. time gets sampled in discrete increments. the exact moment the reported time jumps from one interval to the next? we're calling that a tick. and the interval between ticks is the time period. here's a diagram of three ticks and the periods between them:
-0-0-0-0-0-0-0-0-0-0-1-1-1-1-1-1-1-1-1-1-2-...
^ ^ ^
|<--- period 0 ---->|<--- period 1 ---->|
| | |
tick 0 tick 1 tick 2
now, to see why the fudge factor is even necessary, think about what would happen when a timer with an interval of 1 second gets started right at the end of period 0:
-0-0-0-0-0-0-0-0-0-0-1-1-1-1-1-1-1-1-1-1-2-...
^ ^ ^ ^
| | | |
| | | |
tick 0 |tick 1 tick 2
|
start $t
assuming check() gets called many times per period, that timer is likely to expire just after tick 1, because the time reported will have lept from the value 0 to the value 1:
-0-0-0-0-0-0-0-0-0-0-1-1-1-1-1-1-1-1-1-1-2-...
^ ^ ^ ^ ^
| | | | |
| | | | |
tick 0 |tick 1| tick 2
| |
start $t |
|
check $t
adding a fudge of 1 in this example means the timer is guaranteed not to expire before tick 2. slay. β¨
π
heads up bestie: the fudge is not added to an interval of 0.
so what does that mean for you? it means intervals guarantee a minimum interval. but given that the process running perl may be suspended for some period of time, or that it gets busy doing something time-consuming, there are no other guarantees on how long it'll actually take a timer to expire. that's just the vibe. π¦
π¦ SUBCLASSING π¦
π¨ INCOMPATIBLE CHANGE: because of the awkwardness introduced by ripping pseudohashes out of perl, this class no longer uses the fields pragma. periodt. π
π FUNCTIONS & METHODS π
π timer
okay so this is a constructor function, not a method, that makes IPC::Run::Timer instances. it's giving baby-timer-factory:
$t = timer( 5 );
$t = timer( 5, name => 'stall timer', debug => 1 );
$t = timer;
$t->interval( 5 );
run ..., $t;
run ..., $t = timer( 5 );
this convenience function is literally just a shortened spelling of
IPC::Run::Timer->new( ... );
periodt. it hands you back a timer in the reset state with a given interval. π
if you pass an exception, it gets thrown when the timer notices it has expired (in check()). the name is for debugging, bestie β use it if you're planning on having a whole friend group of timers around. if you don't name it, it'll get a name like "timer #1". π·οΈ
β¨ timeout
also a constructor function (not a method) of IPC::Run::Timer instances:
$t = timeout( 5 );
$t = timeout( 5, exception => "kablooey" );
$t = timeout( 5, name => "stall", exception => "kablooey" );
$t = timeout;
$t->interval( 5 );
run ..., $t;
run ..., $t = timeout( 5 );
this convenience function is a shortened spelling of
IPC::Run::Timer->new( exception => "IPC::Run: timeout ...", ... );
it returns a timer in the reset state that will throw an exception when it expires. no chill, no mercy. π€
takes the same parameters as "timer", and any exception you pass in overrides the default exception. π₯
π¦ new
IPC::Run::Timer->new() ;
IPC::Run::Timer->new( 5 ) ;
IPC::Run::Timer->new( 5, exception => 'kablooey' ) ;
the Constructor, capital C. see "timer" for the deets. πΈ
π check
check $t;
check $t, $now;
$t->check;
checks whether a timer has expired since the last check. it does nothing to non-running timers, lowkey. it will throw an exception if one is defined. π»
IPC::Run::pump() calls this routine for any timers in the harness. yes, automatically, you're welcome.
you can pass in a version of now, which is highkey useful if you happen to have it lying around or you want to check several timers with a consistent concept of the current time. β°
returns the time left before end_time, or 0 if end_time is no longer in the future or the timer isn't running (unless, of course, check() expire()s the timer and that results in an exception being thrown β dramatic π
).
returns undef if the timer isn't running on entry, 0 if check() expires it, and the time left if it's still left running. that's the whole vibe check.
π₯ debug
sets/gets the current setting of the debugging flag for this timer. this has no effect if debugging isn't enabled for the current harness. so set it up first, bestie. π
β³ end_time
$et = $t->end_time;
$et = end_time $t;
$t->end_time( time + 10 );
returns the time when this timer will or did expire. even if that time is in the past, the timer may not be expired, since check() may not have been called yet. the audacity honestly. π
note that this end_time is not start_time($t) + interval($t), because some small extra amount of time is added to make sure that the timer does not expire before interval() elapses. if this were not so, then
changing end_time() while a timer is running will set the expiration time. changing it while it's expired has no affect, since reset()ing a timer always clears the end_time(). π§Ή
π exception
$x = $t->exception;
$t->exception( $x );
$t->exception( undef );
sets/gets the exception to throw, if any. undef means no exception will be thrown β peace and quiet, finally. exception does not need to be a scalar: you may ask that references be thrown. icon behavior, throwing whole refs. π
π interval
$i = interval $t;
$i = $t->interval;
$t->interval( $i );
sets the interval. sets the end time based on the start_time() and the interval (and a little fudge β¨) if the timer is running.
π«Ά expire
expire $t;
$t->expire;
sets the state to expired (undef). will throw an exception if one is defined and the timer wasn't already expired. you can expire a reset timer without starting it β no warm-up needed, it just expires. π
π is_running
π is_reset
π is_expired
π·οΈ name
sets/gets this timer's name. the name is only used for debugging purposes, so you can tell which freakin' timer is doing what. genuinely a public service. π
π§ reset
reset $t;
$t->reset;
resets the timer to the non-running, non-expired state and clears the end_time(). fresh start energy. π±
β start
start $t;
$t->start;
start $t, $interval;
start $t, $interval, $now;
starts or restarts a timer. this always sets the start_time. it sets the end_time based on the interval if the timer is running or if no end time has been set.
you may pass an optional interval or current time value.
not passing a defined interval causes the previous interval setting to be re-used, unless the timer is reset and an end_time has been set (an exception is thrown if no interval has been set). so like, set an interval, bestie. π
not passing a defined current time value causes the current time to be used.
passing a current time value is useful if you happen to have a time value lying around, or if you want to make sure that several timers are started with the same concept of start time. you might even need to lie to an IPC::Run::Timer, occasionally. π€₯ no cap, that's in the docs.
πΈ start_time
sets/gets the start time, in seconds since the epoch. setting this manually is a bad idea β it's better to call "start"() at the correct time. hands off the wheel, let the timer drive. π
π¦ state
$s = state $t;
$t->state( $s );
get/set the current state. only use this if you really need to transfer the state to/from some variable. use "expire", "start", "reset", "is_expired", "is_running", "is_reset" instead. those are the main characters here.
note: setting the state to 'undef' to expire a timer will not throw an exception. sneaky. π
π TODO
- use
Time::HiRes; if it's present. - add detection and parsing of
[[[HH:]MM:]SSformatted times and intervals.
(the devs are working on it, okay, manifesting πβ¨)
π AUTHOR
Barrie Slaymaker <barries@slaysys.com>
that's the whole page bestie, you ate it up fr fr π this was perl v5.42.0, dated 2025-08-11, and it's IPC::Run::Timer(3) β go forth and time things slayfully, periodt. ππ¦π
π¦ where this page comes from
- fedora 43: perl-IPC-Run 20250809.0-1.fc43 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms