Processes

alarm#

Schedule a SIGALRM to be delivered to the current process after a whole number of wallclock seconds.

alarm arms a single per-process countdown timer. When the timer expires, the kernel delivers SIGALRM; what happens next is entirely up to the installed signal handler in %SIG. The timer runs in wallclock time, not CPU time, so a sleeping or blocked process still receives the signal on schedule (subject to scheduling jitter).

Synopsis#

alarm SECONDS
alarm

With no argument, the value in $_ is used.

What you get back#

The number of seconds remaining on the previous timer, or 0 if no timer was pending. This lets you save and restore a caller’s alarm across a nested timed operation:

my $prev = alarm 10;
# ... do something that must finish in 10s ...
alarm $prev;                        # restore caller's timer

alarm 0 cancels any pending timer and returns the seconds that were left on it.

Global state it touches#

  • %SIG — the ALRM slot names the handler invoked when the timer fires. Without a handler, the default disposition of SIGALRM is to terminate the process.

  • $_ — read when alarm is called with no argument.

  • $@ — carries the die message out of the canonical eval { alarm ...; ...; alarm 0 } idiom.

  • $! — a blocking syscall interrupted by SIGALRM sets $! to EINTR, but Perl restarts many syscalls automatically on some systems, so you cannot rely on seeing EINTR. Use eval / die instead (see below).

The canonical timeout idiom#

Use alarm with eval and die to put a wall-clock cap on any block of code, including blocking I/O:

eval {
    local $SIG{ALRM} = sub { die "timeout\n" };   # \n matters
    alarm $timeout;
    my $nread = sysread $sock, $buf, 4096;
    alarm 0;                                      # cancel on success
};
if ($@) {
    die $@ unless $@ eq "timeout\n";              # rethrow others
    # ... handle timeout ...
}

Three details are load-bearing:

  • local scopes the handler to the eval block so it does not leak to the caller.

  • The \n in "timeout\n" suppresses the file/line suffix that die would otherwise append, making the exact-match test in $@ reliable.

  • alarm 0 inside the eval cancels the timer on the success path. Without it, a timer left armed can fire during unrelated code after the eval returns.

Examples#

Simple wallclock deadline:

$SIG{ALRM} = sub { die "timeout\n" };
eval {
    alarm 5;
    my $line = <$slow_pipe>;        # may block indefinitely
    alarm 0;
};
warn "gave up waiting\n" if $@ eq "timeout\n";

Nested timers — save and restore:

my $saved = alarm 30;               # remember caller's timer
do_something();
alarm $saved;                       # put it back

Cancel a pending timer:

my $left = alarm 0;                 # 0 if none was pending

Periodic tick without Time::HiRes:

$SIG{ALRM} = sub {
    print "tick\n";
    alarm 1;                        # re-arm from inside the handler
};
alarm 1;
sleep 10;                           # do not mix sleep+alarm in real code

Sub-second delay — use Time::HiRes:

use Time::HiRes qw(alarm);
alarm 0.25;                         # 250 ms

Edge cases#

  • Integer seconds only. The core alarm truncates fractional arguments to whole seconds. For finer granularity, load Time::HiRes, which exports a replacement alarm that accepts floats.

  • Scheduling jitter. The signal may arrive up to roughly one second early or late because of how the kernel counts seconds and schedules your process. Treat alarm N as a not-before-N-minus-1 bound, not a precise deadline.

  • One timer per process. Each alarm call replaces the previous timer; there is no queue. The return value is your only record of what was overwritten.

  • Default disposition is fatal. With no handler installed for ALRM, timer expiry terminates the process with Alarm clock. Install a handler before arming the timer.

  • Do not mix with sleep. On many systems sleep is implemented on top of alarm, so arming one clobbers the other. Pick one per block.

  • EINTR is unreliable. Perl installs signal handlers with SA_RESTART on many platforms, so a SIGALRM that interrupts a blocking syscall transparently restarts the call instead of returning with $! set to EINTR. The portable way to enforce a deadline is eval / die from the handler, as shown above.

  • Signals are delivered between Perl ops. Inside a tight pure-Perl loop the handler runs at the next safe point, not instantly; a CPU-bound XS call can defer delivery further.

  • fork clears the timer. Child processes start with no pending alarm regardless of what the parent had armed.

  • exec clears the timer on Linux; the replacement process image starts with no pending SIGALRM.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • sleep — wallclock delay; often implemented on top of alarm, so the two do not compose

  • die — raise the exception from the ALRM handler that eval catches to implement a timeout

  • eval — catches the die from the handler and lets the program recover from a timeout

  • %SIG — where the ALRM handler is installed; the handler decides what the timer means

  • select — the four-argument form accepts a floating-point timeout and is an alternative to alarm for I/O deadlines

  • Time::HiRes — drop-in alarm replacement that accepts sub-second floats via setitimer(2)