Revision history for Linux-Event
0.104 2026-08-28
- Make the performance-regression and Timer benchmark smoke tests portable
to systems whose process CPU clock does not advance for extremely small
workloads. The benchmarks still reject non-positive timing samples.
- Publish complete META spec 2 repository, bugtracker, and public-module
provider metadata, plus security and contribution policies.
0.103 2026-08-27
- Make raw Loop registration handles stable lifecycle tokens. Cancelled,
replaced, and Loop-destroyed handles are now inert even after native
watcher storage or file-descriptor numbers are reused, and retained Perl
state is released as soon as dispatch safety permits.
- Restore Loop driver state after callback exceptions, reject recursive
driving of the same Loop, reject event-capacity changes during dispatch,
let run_once ignore an old stop request, and correct idle run_for
statistics.
- Apply Stream's normal high/low-watermark contract to output queued before
attachment or connection readiness, including pending-byte reporting and
exactly one delayed on_drain notification after the transport is usable.
- Set adopted Stream descriptors nonblocking and close-on-exec, install the
native drain callback only when requested by the subclass, and make
callback-driven close safe throughout readiness, transition, drain, EOF,
and transport-error dispatch.
- Close Process stdin after max_pending_stdin overflow before reporting the
typed output_limit error, so an over-limit producer cannot continue
feeding that pipe.
- Release Wakeup owner state on cancellation and reject attachment of a
terminal Wakeup.
- Add regression coverage for registration reuse and dispatch recovery,
Loop driver contracts, Stream pre-connect flow control, adopted descriptor
flags, callback-close safety, Process stdin limits, Signal recovery,
Wakeup lifecycle, and TLS protocol transitions with leftover input.
- Remove private implementation layers without changing the public API:
Listener now uses its XS implementation directly, Stream and Datagram
share Linux::Event::_Resolver, and the tiny Stream deadline helper lives
in Stream.pm.
0.102 2026-08-21
- Fix Linux::Event::Wakeup compilation on Perl builds without
PERL_IMPLICIT_CONTEXT, including ordinary non-threaded Perl. Such builds
now use the sole interpreter identity while threaded/multiplicity builds
retain pointer-based interpreter ownership checks.
- Add regression coverage for interpreter identity on both multiplicity
and non-multiplicity Perl configurations.
0.101 2026-08-21
- Publish the completed API as a stable release and synchronize every
bundled Perl and XS component at version 0.101.
- Add Linux::Event::Wakeup, a subclass-defined eventfd boundary with
coalesced Loop-thread callbacks, safe fork signalling, and per-ithread
descriptor duplication that keeps callbacks and data owner-confined.
- Add production Stream socket policy at class and construction time:
local address/port binding, TCP_NODELAY, keepalive tuning,
TCP_USER_TIMEOUT in seconds, send/receive buffers, SO_BINDTODEVICE, live
getters/setters, and a cached configure_socket hook.
- Apply Stream socket policy before outbound bind/connect and before
accepted or adopted transport attachment; expose local addresses and
report family/configuration failures as structured Error values.
- Extend the private asynchronous resolver with SOCK_DGRAM requests while
preserving its typed native completion queue and cancellation model.
- Add Linux::Event::Datagram for connected and unconnected UDP and Unix
datagrams, native recvmsg/sendto packet I/O, lazy peer Addresses, whole-
packet queues, soft backpressure, hard byte/packet limits, truncation
detection, socket policy, ownership, detach, and Unix-path cleanup.
- Add Linux::Event::Process using posix_spawnp, pidfd_open,
waitid(P_PIDFD), and pidfd_send_signal, with asynchronous pipe stdio,
decoded exit status, replacement environments, cwd support, SIGPIPE-safe
stdin, atomic close-on-exec pipes, child-side closure of caller stdio
source descriptors, deterministic final output draining, and
partial-failure cleanup.
- Make native resource objects interpreter-owned and non-clonable except
for Wakeup's deliberately restricted signalling handle; rebuild cached
native class descriptors lazily in a child ithread and reject stale
Wakeup handles round-tripped from a worker interpreter.
- Complete API, lifecycle, failure, ownership, thread/fork, local-binding,
Datagram, and Process regression tests, including callback-exception and
descriptor-reuse safety cases.
- Add focused Wakeup, Datagram, and Process examples and microbenchmarks;
update architecture, lifecycle, transport, roadmap, and module POD around
the completed public surface with concrete annotated examples.
- Harden distribution configuration for Linux, required libc/OpenSSL
capabilities, CPAN metadata, manifest coverage, and clean distribution
testing.
0.100_030 2026-08-21
- Make TLS declarative Stream policy: use Linux::Event::TLS on a Stream
subclass and let connect or Listener acceptance select the client or
server handshake role automatically.
- Default outbound TLS server_name, SNI, and hostname verification to the
connect host while retaining an explicit override for different service
identities and adopted handles.
- Load and validate accepted TLS certificate and key policy during Listener
construction and create fresh native server state for every connection.
- Pass Listener data automatically to each accepted Stream and remove the
cumbersome accepted_stream_options hook from the public design.
- Expose negotiated ALPN, protocol, cipher, and native TLS statistics
directly on Stream without requiring access to its internal provider.
- Add declaration validation, inheritance, role, callback-order, metadata,
and integrated client/server regression coverage; update all current
Listener, Stream, connection, and transport documentation to one model.
0.100_029 2026-08-21
- Add optional Listener on_accept($listener, $stream) after Stream
construction and Loop attachment, before plain Stream readiness or TLS
handshake completion.
- Contain on_accept exceptions by closing only the affected Stream,
suppressing its pending on_ready, and delivering a nonfatal callback
Error through the Listener's on_error policy.
- Make Listener family reporting consistent with Address: family returns
inet, inet6, unix, or unknown; family_number retains the native value;
is_tcp and is_unix provide convenience predicates.
- Replace undefined Listener documentation placeholders with complete TCP,
Unix, and adopted-socket examples annotated as required, default, or
optional.
- Add plain and TLS callback-order coverage plus callback-failure cleanup
and family-accessor regression tests.
0.100_028 2026-08-21
- Correct inbound acquisition ownership: remove the accidental
MyStream->listen() proxy and make Linux::Event::Listener->new with an
explicit stream_class the sole Listener construction API.
- Move runtime Listener error policy off Stream classes. The base Listener
remains fatal; applications may override on_error in a Listener subclass.
- Add established Stream idle, read, and write inactivity deadlines with
cached subclass defaults and per-connection constructor overrides.
- Add constructor and runtime overall-operation deadlines through
deadline, set_deadline(), clear_deadline(), and monotonic after/at forms.
- Start established deadlines only after plain or TLS transport readiness,
leaving resolver, connection, TLS handshake, and TLS shutdown deadline
ownership unchanged.
- Track successful read and write progress natively only for Streams that
enable inactivity policy; ordinary Streams perform no activity clock
reads in their I/O path.
- Use at most one private Timer per deadline-enabled Stream, sharing the
Loop's existing timerfd and native deadline heap without exposing the
internal Timer object.
- Deliver typed timeout errors with operation, duration, and absolute
deadline context, then follow ordinary on_error/on_close cleanup.
- Add plain, TLS, transition, pause/resume, EOF, queued-write, lifecycle,
validation, and benchmark regression coverage.
0.100_027 2026-08-21
- Move hostname resolution off the reactor thread into a private XS
resolver with two lazy native pthread workers per Loop.
- Deliver copied getaddrinfo results through one eventfd watched by the
ordinary raw Loop API; no public eventfd, post, or threaded-Perl API is
introduced.
- Interleave IPv6 and IPv4 candidates, stagger pending attempts by 250 ms,
transfer the first successful socket, and deterministically close losers.
- Make cancellation discard late completion safely, include DNS in the
connection deadline, retain literal-address bypass, and document that
processes must fork before starting resolver workers.
- Add native delivery, cancellation, hostname connection, ordering, and
resolver microbenchmark coverage.
- Add subclass-defined Linux::Event::Signal with one lazy signalfd and
native fan-out registry per Loop, supporting several signals per object
and several objects per signal.
- Aggregate complete signalfd drains before callback delivery, preserve
attachment-order fan-out, and make self/cross-cancellation callback-safe.
- Track signal-mask ownership exactly, reject cross-Loop consumption of one
signal number, restore only Loop-owned entries, and make resolver workers
block signals independently.
- Add Signal API, delivery, lifecycle, mask, error, and benchmark coverage
plus explicit thread and fork ownership documentation.
0.100_026 2026-08-21
- Add Linux::Event::Timer as an abstract subclass-defined public object
with cached on_timer callbacks and the same Loop->add attachment contract
as Stream and Listener.
- Support relative, absolute monotonic, and fixed-rate recurring schedules,
including distinct first deadlines, in-callback rescheduling, and
idempotent terminal cancellation.
- Give each Loop one lazy timerfd and one indexed native minimum heap for
every active Timer, with FIFO equal-deadline order and nanosecond internal
deadlines.
- Coalesce missed recurring ticks, retain fixed-rate phase, bound callback
batches for descriptor fairness, and defer zero-delay callbacks to a
later Loop turn.
- Define deterministic ownership and cleanup: Loop retains active Timers;
final expiration, cancellation, and Loop destruction release application
data safely, including cancellation during a callback.
- Extend statistics, lifecycle/API/scheduling tests, the release regression
contract, and a dedicated scaling benchmark for Timer lifecycle,
rescheduling, and expiration delivery.
0.100_025 2026-08-21
- Simplify the public hierarchy to Linux::Event::Loop, Stream, Listener,
TLS, Framer, Error, and Address. Remove the public Watcher, IO, Connect,
Connector, Listen, XSLoop, and XSWatcher compatibility modules.
- Make MyStream->connect() the sole public outbound acquisition API and
retain one Stream identity across connection, optional TLS readiness,
established I/O, and close. Keep the acquisition engine private.
- Make MyStream->listen() the normal inbound API and keep accept mechanics
in a private Listener engine. Accepted descriptors become the configured
Stream subclass directly, without a temporary public registration.
- Support both loop => $loop construction and detached construction plus
Loop->add() for Stream and Listener. Both forms attach the same object;
add() sets its Loop and returns it.
- Return only an opaque native registration from the low-level watch API;
raw registrations are not a named public class hierarchy.
- Consolidate errors under Linux::Event::Error, peer addresses under
Linux::Event::Address, and native framing declarations under
Linux::Event::Framer::*.
- Rewrite the module POD, README, lifecycle, connection, Listener, core,
architecture, and benchmark documentation around the reduced API.
- Replace obsolete Connect/Listen benchmark modes with raw baselines and
direct comparisons of loop => and Loop->add() attachment styles.
- Add a permanent capture/compare performance-regression suite covering
reactor registration, Stream lifecycle and throughput, native delimiter
framing, and integrated connect/listen acquisition.
- Align active XS source and build names with the reduced public model and
remove stale XSLoop/XSWatcher terminology from the reactor source.
0.100_024 2026-08-16
- Introduce Linux::Event::Watcher as the public lifecycle contract and
Linux::Event::Loop as the canonical XS-first loop name.
- Add Loop->add() for detached high-level Watchers while retaining watch()
as the immediate raw-IO registration convenience.
- Return Linux::Event::IO objects from raw watch/watch_fd registration;
XSWatcher remains their compatibility native-method base.
- Make Stream, Connect, and Listen Watchers with detached construction and
temporary loop-constructor compatibility.
- Add MyStream->connect(), preserving one Stream identity through outbound
connection, optional verified TLS negotiation, established I/O, and
terminal close. Writes before readiness use the bounded Stream queue.
- Add MyStream->listen() and Linux::Event::Listener, which construct and
attach accepted Stream subclasses without application socket plumbing.
- Add the noun-named Connector and Listener error/peer public aliases while
retaining Connect and Listen as advanced compatibility layers.
- Expand lifecycle tests through automatic plain and TLS client/server
paths, strict Watcher attachment, raw IO typing, and stable identity.
- Harden the Connect lifecycle benchmark with balanced order, abortive
teardown, configurable deadlines, correctness checks, and JSON output;
add integrated Stream and automatic Listener comparison rows.
0.100_023 2026-08-16
- Split the Listen benchmark's previous manual-to-raw gap with a handoff
row that constructs the same Perl filehandle and lazy Peer representation
without invoking Listen control or subclass callback machinery.
- Remove an avoidable array shift from Listen's accepted-batch traversal.
- Use eight rotating repeats by default so all four benchmark modes occupy
every execution position equally.
0.100_022 2026-08-16
- Use equal abortive client teardown in every Listen benchmark mode so
large matrices do not exhaust ephemeral ports through TIME_WAIT buildup.
The complete default 540,000-connection matrix now runs without later
rows failing from state accumulated by earlier rows.
0.100_021 2026-08-16
- Add a manual XSLoop/native-accept baseline to the permanent Listen
lifecycle benchmark, separating Listen handoff cost from Stream cost.
- Rotate benchmark mode order across repeats to reduce execution-order
bias and print the tested Linux::Event version in the report.
- Replace the overly aggressive hardcoded two-second connection deadline
with a configurable --timeout option that defaults to 30 seconds.
0.100_020 2026-08-16
- Add Linux::Event::Listen as the inbound stream-socket acquisition layer.
- Create TCP and Unix listeners or adopt an existing listening handle.
- Drain accept4 in XS with atomic nonblocking and close-on-exec flags.
- Add bounded level-triggered accept fairness and safe edge-trigger rules.
- Add lazy peer addresses, typed failures, resource-error pause/recovery,
ownership-aware close/detach behavior, and direct Stream handoff.
- Add a runnable line-delimited echo server and permanent Listen lifecycle
microbenchmark under the distribution examples and bench directories.
- Recover from watched descriptor-number reuse by falling back from epoll
MOD/ENOENT to ADD during same-fd watcher replacement.
0.100_019 2026-08-15
- Merge a redesigned Linux::Event::Connect into the main distribution.
Concrete subclasses define cached on_connect and on_error methods while
each request stores only target, lifecycle, and application data.
- Transfer a generic connected nonblocking filehandle rather than requiring
or constructing Linux::Event::Stream. Stream, TLS, raw watchers, and
specialized protocol engines remain independent consumers.
- Add typed Linux::Event::Connect::Error failures, a default 10-second
connection deadline, silent idempotent cancellation, strict address-mode
validation, and loop-dispatched callbacks for immediate outcomes.
- Create sockets atomically with SOCK_NONBLOCK and SOCK_CLOEXEC. A small
native timerfd helper supplies connection deadlines and deferred terminal
delivery while candidate policy remains in the cold Perl control path.
- Replace same-fd watchers through one EPOLL_CTL_MOD instead of DEL plus ADD.
Old watcher handles remain inert, so Connect can hand a socket to Stream
during on_connect and safely cancel only its original registration.
- Retain synchronous getaddrinfo and sequential fallback as documented
initial limitations. The public contract and internal attempt collection
are prepared for a later asynchronous Resolver and Happy Eyeballs.
0.100_018 2026-08-15
- Prevent OpenSSL socket writes from delivering SIGPIPE when a TLS peer
closes abruptly. The TLS extension now uses a non-owning custom socket
BIO whose writes use Linux MSG_NOSIGNAL.
- Preserve application signal policy: TLS does not install a process-wide
SIGPIPE handler or add per-operation signal-mask syscalls.
0.100_017 2026-08-15
- Merge Linux::Event::TLS into the Linux-Event distribution so the reactor,
Stream, and OpenSSL transport build and test with one top-level command.
- Keep TLS in its own native extension and preserve Stream's specialized
plain fast path; plain operations still make no OpenSSL calls.
- Remove the duplicate transport ABI header and build the TLS provider
against the canonical header owned by XSStream.
- Move TLS integration, deadline, EOF, and certificate fixtures into the
main test suite and simplify the TLS microbenchmark to use one blib tree.
- Add an OpenSSL 1.1.1 configuration probe with a direct diagnostic for
missing development headers or libraries.
0.100_016 2026-08-15
- Add generic cold-path transport lifecycle hooks used by adjacent
providers to install, disarm, reuse, and destroy deadline watchers.
- Preserve Stream/XSLoop layering: the core still knows no OpenSSL policy,
while transport timeout failures use the existing typed error lifecycle.
- Keep ordinary plain Streams free of auxiliary watchers and provider-hook
calls in their read/write syscall paths.
- Add the permanent top-level run-tls-microbench.pl same-Stream comparison
for specialized plain and adjacent OpenSSL transports.
0.100_015 2026-08-15
- Publish transport => $provider construction for established descriptors
through an exact-version native Stream transport ABI.
- Retain provider lifetime in XS and coordinate cross-direction readiness
for nonblocking handshakes, reads, writes, and transport shutdown.
- Add transport(), is_transport_ready(), and the optional cached
on_transport_ready callback while preserving the specialized plain path.
- Reject detach() for non-plain transports because an encrypted descriptor
cannot safely be returned as an application plaintext handle.
- Support the adjacent Linux::Event::TLS OpenSSL provider without adding an
OpenSSL dependency to the Linux-Event distribution.
0.100_014 2026-08-15
- Introduce an internal native transport operation contract beneath Stream
buffering, framing, backpressure, and lifecycle semantics.
- Route read, write, writev queue draining, retry classification, errors,
EOF, and writable shutdown through the connection's transport provider.
- Keep the ordinary plain-fd provider on a specialized direct-syscall path
with no Perl callback or indirect function call per syscall.
- Distinguish WANT_READ and WANT_WRITE in the native result contract for a
future nonblocking OpenSSL provider.
- Add transport_name(), plain-provider contract tests, regression benchmark
coverage, and a detailed TLS/provider/STARTTLS boundary specification.
0.100_013 2026-08-14
- Add the optional class-level max_pending_bytes safety limit while keeping
the existing high/low-watermark write() return contract unchanged.
- Enforce the bound in XS before allocating an unsent queue segment, so the
native pending-output queue never grows beyond its configured limit.
- Report overflow as a typed output_limit Stream error with attempted
pending_bytes and limit details, invoke on_error, and close the Stream.
- Reject protocol transitions atomically when existing queued output exceeds
the target class's nonzero max_pending_bytes policy.
- Add deterministic output-limit tests, native overflow instrumentation,
documentation, and capped/uncapped Stream transport benchmark rows.
0.100_012 2026-08-14
- Add in-place Stream protocol transitions through transition_to(). A live
connection may change to another Stream subclass without replacing its
filehandle, watcher, XSState, output queue, lifecycle, or application data.
- Preserve unread native input across raw/framed protocol boundaries and
accept an explicit raw-callback suffix through input => $bytes.
- Stop the old native parser immediately after an input callback changes
descriptors, then reinterpret remaining bytes with the new descriptor
without waiting for another readiness event.
- Make transition validation atomic, including target max_buffer checks,
and retain pause, EOF, backpressure, queued-output, and instrumentation state.
- Add transition contract tests, native transition counters, a dedicated
transition benchmark, benchmark smoke coverage, and protocol-upgrade docs.
0.100_011 2026-08-14
- Redesign Linux::Event::Stream as a subclass-defined API. Callbacks,
framing, and transport policy are class behavior; constructor state is
limited to loop, fh, and optional per-connection data.
- Resolve callbacks and framer/transport configuration once per concrete
subclass into a shared immutable XS descriptor, with independent mutable
parser and queue state for every connection.
- Replace the framer factory and per-connection framer objects with
declarative `use Linux::Event::Stream::Framer 'Name', @args` syntax.
Exact package-name resolution removes the duplicate keyword registry.
- Remove the arbitrary custom-framer object contract and
Linux::Event::Stream::Framer::Buffer. Application-specific protocols now
parse raw on_data bytes; generally useful families remain native built-ins.
- Add cached class-level stream_options for read size, watermarks, and
framed-buffer limits.
- Rewrite Stream/framer tests, benchmarks, POD, guides, architecture notes,
metadata, and examples for the canonical subclass-descriptor model.
0.100_010 2026-08-14
- Add the versioned Stream lifecycle and retained-memory benchmark used to
capture the object-configured contract-1 baseline before the API redesign.
0.100_009 2026-08-13
- Add native inbound ASCII DecimalLength framing for wire forms such as
RFC 6587 octet-counted syslog: "5 HELLO".
- Support one configurable non-digit separator, include_prefix, max_frame,
shared definitions, Perl fallback, and Perl outbound frame()/send().
- Reject invalid, overlong, overflowing, and non-canonical decimal lengths.
- Extend native-framer tests, benchmarks, and the framer-selection guide.
0.100_008 2026-08-13
- Add canonical unsigned LEB128 Varint framing with native inbound parsing.
- Preserve Perl outbound frame() compatibility and the custom-framer fallback.
- Reject overflowing, overlong, and non-canonical Varint prefixes.
- Extend native-framer benchmarks and simplify the framer-selection guide.
0.100_007 2026-08-13
- Add named Loop watch(fh => ...) and watch(fd => ...) construction.
- Add Linux::Event::Stream::Framer factory methods for built-in framers.
- Document and test safe reuse of built-in framer definitions across Streams.
- Keep watch_fd and concrete Framer::* constructors available for low-level and subclass use.
0.100_006 2026-08-13
- Merge Linux::Event::Stream into the main Linux::Event distribution.
- Build Linux::Event::XSLoop and Linux::Event::Stream native extensions from
one source distribution and one top-level build/test/install workflow.
- Keep the raw reactor and high-level Stream APIs as separate namespaces.
- Unify development package versions for the merged native ABI snapshot.
- Add a novice-oriented framer-selection guide in Markdown and POD.
- Preserve native Delimiter, Fixed, LengthPrefix, U32BE, and Netstring
framing plus the custom native-backed Buffer plug-in path.
- Preserve the reactor, Stream, framing, and native-framer benchmark tools.