Established Stream deadlines

Established deadlines protect a Stream after its byte transport is usable. They do not replace the separate resolver, connection, TLS handshake, or TLS shutdown deadlines.

Configuration

Subclass defaults belong in the cached Stream descriptor:

sub stream_options ($class) {
    return (
        idle_timeout  => 60,
        read_timeout  => 30,
        write_timeout => 10,
    );
}

All values are non-negative seconds and may be fractional. Zero disables the policy. A constructor value overrides its subclass default for one Stream:

my $stream = ClientStream->connect(
    host => $host,
    port => $port,
    idle_timeout => 120,
    read_timeout => 20,
    write_timeout => 5,
);

The same options work with new(fh => $connected_socket). A Listener-created Stream uses the accepted Stream subclass's stream_options defaults. An explicit zero constructor value disables a nonzero subclass default. Constructor overrides remain in force across transition_to; policy that was not overridden changes to the target subclass default.

Inactivity policies

For TLS, activity means successful plaintext progress through the Stream transport boundary. TLS handshake control traffic occurs before established policy starts and remains governed by the provider handshake timeout.

Overall-operation deadline

One explicit fixed deadline may coexist with inactivity policy. It can be provided at construction:

my $stream = ClientStream->new(
    fh => $socket,
    deadline => { after => 30, operation => 'authentication' },
);

Or set and replaced at runtime:

$stream->set_deadline(after => 5, operation => 'response');
$stream->set_deadline(
    at => Linux::Event::Timer->now + 10,
    operation => 'request',
);
$stream->clear_deadline;

after starts when the Stream becomes usable if supplied before readiness. at is an absolute CLOCK_MONOTONIC deadline. Ordinary reads and writes do not extend an overall-operation deadline. deadline returns its active absolute time, or undef for a detached relative deadline; deadline_operation returns its label.

Expiration and ordering

Expiration creates a Linux::Event::Error with:

Stream calls on_error and then follows its normal terminal close path, including on_close. When exact deadlines tie, an explicit operation wins, followed by write, read, and idle policy. This ordering affects only the error label; every expiration is terminal.

Scheduler and hot path

Every deadline-enabled Stream owns at most one private Timer representing the earliest applicable condition. Those Timers use the Loop's existing timerfd and indexed native heap. No Stream creates a deadline fd and no internal Timer is exposed publicly.

Successful native reads and writes update monotonic timestamps only when at least one inactivity policy is enabled. A Stream with all three inactivity values at zero performs no activity clock reads. Pause, resume, EOF, and output drain also skip deadline candidate rebuilding unless the corresponding read or write timeout is enabled. I/O progress does not enter Perl merely to reschedule a Timer. If progress moves a deadline, an early Timer callback reads the latest native snapshot and reschedules itself.

Closing, detaching, failure, and Loop teardown cancel scheduler ownership. Protocol transitions retain an explicit operation deadline and apply the target subclass's non-overridden inactivity defaults.