NAME

Linux::Event::Timer - subclass-defined timers for Linux::Event

SYNOPSIS

package LE::Heartbeat;
use parent 'Linux::Event::Timer';

sub on_timer ($timer) {
    $timer->data->send_heartbeat;
}

package main;
use Linux::Event::Loop;

my $loop = Linux::Event::Loop->new;
my $timer = $loop->add(LE::Heartbeat->new(
    every => 30,          # required recurring interval
    data  => $connection, # optional
));
$loop->run;

DESCRIPTION

Linux::Event::Timer is the public subclassing boundary for Loop-owned timers. Each concrete subclass defines one named on_timer method. One immutable native descriptor caches that callback for the subclass, while every Timer instance owns only its schedule, application data, lifecycle, and native heap position.

Timer objects use the same attachment contract as Stream and Listener. Supply loop => $loop during construction or construct the Timer detached and pass it to $loop->add($timer). There are no Timer-construction methods on Loop and no callback-configured compatibility form.

All public times are seconds and may be fractional. Deadlines use CLOCK_MONOTONIC; wall-clock changes do not affect them.

DEFINING A TIMER TYPE

The base class cannot be constructed directly. A subclass must define:

sub on_timer ($timer) {
    my $context = $timer->data;
    $context->{stream}->close;
}

The resolved CV is cached once per subclass and called directly without Perl method lookup at expiration. Inheritance works normally. Per-instance application state belongs in data.

CONSTRUCTION

new(after => $seconds, data => $value)

Creates a one-shot relative Timer. The delay begins when the Timer is attached, not when a detached object is constructed. Zero schedules the callback for a subsequent Loop turn and never calls it inline.

new(at => $deadline, data => $value)

Creates a one-shot Timer for an absolute monotonic deadline expressed in seconds. Use Linux::Event::Timer->now to obtain the current clock. A deadline already in the past fires on a subsequent Loop turn.

new(every => $seconds, data => $value)

Creates a fixed-rate recurring Timer whose first expiration occurs after one interval. The interval must be positive.

after or at may be combined with every to choose a different first expiration. after and at are mutually exclusive.

loop optionally attaches the Timer before new returns. data retains an arbitrary application value until cancellation or final expiration.

METHODS

reschedule(after => $seconds) / reschedule(at => $deadline) / reschedule(every => $seconds)

Replaces an active Timer's schedule and returns the same object. The same schedule combinations and validation as new apply. Rescheduling never calls on_timer inline. It is allowed from inside on_timer; an explicit schedule then replaces the normal recurring schedule or keeps a one-shot Timer active.

Cancelled and finally expired Timers cannot be rescheduled or reattached.

cancel

Idempotently removes the Timer from its Loop, releases retained application data, and makes it terminal. Cancellation during on_timer defers reference cleanup until that callback returns safely. Returns the Timer.

data([$value])

Gets or replaces the application value while the Timer is nonterminal. A one-shot Timer releases this value after its final callback; a recurring Timer retains it until cancellation or Loop destruction.

loop

Returns the owning Loop while attached, otherwise undef.

deadline

Returns the next absolute monotonic deadline in seconds. A detached relative Timer has no absolute deadline and returns undef.

interval

Returns the recurring interval in seconds, or zero for a one-shot Timer.

expirations

Returns the number of periodic ticks represented by the latest callback. When the Loop is delayed, missed intervals are coalesced into one callback rather than delivered as a catch-up storm.

state

Returns unattached, active, expired, or cancelled.

is_active / is_terminal

Report the current lifecycle category.

now

Class method returning the current CLOCK_MONOTONIC time in seconds.

SCHEDULER SEMANTICS

Every Loop lazily creates one nonblocking, close-on-exec timerfd and stores all active Timers in one indexed native minimum heap. Equal deadlines fire in schedule order. Recurring timers retain fixed-rate phase, skip missed periods, and expose the represented count through expirations.

Timer callbacks are delivered in bounded batches so a large deadline cohort cannot permanently starve descriptor readiness. Timers created or rescheduled for immediate delivery from inside a Timer callback wait for a later Loop turn.

Callback exceptions propagate from the Loop. A recurring Timer remains scheduled when its callback throws. A one-shot Timer still completes terminal cleanup.