NAME

Linux::Event::Loop - Linux-native epoll event loop

SYNOPSIS

use Linux::Event::Loop;

my $loop = Linux::Event::Loop->new;
my $stream = $loop->add(MyStream->connect(
    host => '127.0.0.1', # required
    port => 9999,        # required
));
$loop->run;

DESCRIPTION

Linux::Event::Loop owns the native epoll instance, descriptor registry, event buffer, and readiness dispatch. It is the only public loop class.

High-level objects may be attached in either of two equivalent ways:

my $stream = MyStream->connect(
    loop => $loop,        # optional: attach immediately
    host => '127.0.0.1',  # required
    port => 9999,         # required
);

my $stream = MyStream->connect(
    host => '127.0.0.1', # required
    port => 9999,        # required
);
$loop->add($stream);

add invokes the concrete object's attachment implementation and returns the same object. Stream, Listener, Datagram, Timer, Signal, Wakeup, and Process reject attachment to a second Loop or attachment after reaching a terminal state.

watch is the low-level descriptor API. It registers immediately and returns an opaque native registration handle. The handle is not a public class or a subclassing API.

HIGH-LEVEL OBJECTS

add($object)

Attaches a detached Linux::Event::Stream, Linux::Event::Listener, Linux::Event::Datagram, Linux::Event::Timer, Linux::Event::Signal, Linux::Event::Wakeup, or Linux::Event::Process and returns that exact object. The object becomes owned by this Loop. Attaching it again, attaching it to another Loop, or attaching a terminal object throws an exception.

The following are equivalent:

my $a = MyStream->connect(
    loop => $loop,       # optional: attach immediately
    host => '127.0.0.1', # required
    port => 9999,        # required
);
my $b = $loop->add(MyStream->connect(
    host => '127.0.0.1', # required
    port => 9999,        # required
));

my $timer = $loop->add(MyTimer->new(
    after => 0.25, # required one-shot delay
));

my $socket = $loop->add(MyDatagram->new(
    host => '0.0.0.0', # required
    port => 9999,      # required
));

The loop constructor option and add are both primary public APIs. Timer construction and scheduling deliberately use this generic attachment path; Loop has no Timer-specific factory methods.

RAW DESCRIPTOR API

watch(fh => $fh, read => $callback) / watch(fd => $fd, read => $callback)

Registers exactly one filehandle or integer descriptor. Supported options are:

  • read, write, error

    Coderefs for readable, writable, and terminal/error readiness. Only read and write control ordinary interest; terminal flags are always observed. For one returned event, callback order is error, read, then write. Cancellation after any callback suppresses the remaining callbacks for that event.

  • data

    An arbitrary retained value available through $registration->data.

  • no_args => 1

    Calls readiness coderefs without an argument. By default each receives the opaque registration handle.

  • lean => 1

    With no_args, avoids retaining references used only by handle accessors. This is an expert registration-throughput optimization.

  • edge_triggered => 1

    Uses EPOLLET. The callback must drain the descriptor until EAGAIN.

  • oneshot => 1

    Uses EPOLLONESHOT. The application is responsible for its rearm policy.

Registering an fd that is already registered replaces its native registration with EPOLL_CTL_MOD. Cancelling the obsolete handle cannot remove the new registration.

watch_fd($fd, read => $callback)

Low-level positional form used by Linux::Event internals and specialized code. It creates the same native registration and has the same dispatch path as watch. Normal application code should prefer watch.

unwatch_fd($fd)

Cancels the current registration for $fd, if any. Prefer the registration's cancel method when the handle is available.

REGISTRATION METHODS

The opaque result of watch supports fd, fh, data, loop, lean, cancel, enable_read, disable_read, enable_write, and disable_write. cancel is idempotent and makes an obsolete handle inert, including after native watcher storage is reused. Cancellation releases the registration's retained Perl state. An fd-only registration returns undef from fh.

DRIVING THE LOOP

run

Waits and dispatches until stop is called.

run_once($timeout_ms = -1)

Runs one epoll_wait. A negative timeout blocks indefinitely, zero polls, and a positive value is a maximum wait in milliseconds. Returns the number of events returned by epoll. A prior stop request does not suppress a later run_once call.

run_for($seconds)

Runs against a monotonic deadline for the supplied non-negative number of seconds.

Only one driver method may be active for a given Loop. Calling run, run_once, or run_for recursively on that same Loop throws an exception; a callback may drive a different Loop. set_event_capacity is likewise rejected while its Loop is running or dispatching.

stop

Requests that the active run or run_for return after the current dispatch work completes.

DIAGNOSTICS AND TUNING

stats returns counters for epoll waits, event classes, callbacks, registrations, Timer scheduling and delivery, dispatch batching, and lifecycle activity. reset_stats resets them. enable_profile(1) additionally records nanosecond timing and changes the measured workload, so it should be disabled for normal benchmarks.

event_capacity and set_event_capacity inspect or change the reusable event array. callback_scope_limit and set_callback_scope_limit control bounded Perl temporary scopes. enable_watcher_reclaim exposes an experimental native memory/throughput tradeoff. The measured defaults should normally remain unchanged.

INTERPRETER OWNERSHIP

A Loop and every native object it owns belong to the Perl interpreter that created them. They are not cloned into a new ithread. Only a cloned Linux::Event::Wakeup handle may signal its owner through eventfd; it cannot manage the Loop, invoke callbacks, or access owner-interpreter data.

PLATFORM

Linux only. The implementation uses epoll directly.