Repository navigation
Conversation
petermm
force-pushed
the
nif_select_write/2
branch
3 times, most recently
from
October 13, 2026 12:48
0e71177 to
de4ce2a
Compare
Signed-off-by: harmon25 <dougwright1@gmail.com>
Make socket:send/2 retry partial stream sends and wait for write readiness when the native send path reports eagain. This keeps gen_tcp callers on the OTP-like success path instead of leaking {ok, Rest} or transient backpressure.
Add write-select plumbing for BSD and lwIP, including distinct read/write select state and lwIP tcp_sent/tcp_poll wakeups. Use the same readiness wait for SSL WANT_WRITE and make distribution/EPMD send failures explicit instead of dropping data.
Signed-off-by: Peter M <petermm@gmail.com>
Signed-off-by: Peter M <petermm@gmail.com>
Blocking sends require read and write readiness to coexist on one socket. Sharing their owner lets a writer replace a reader, misroutes close notifications, and cancels both directions when one selector exits. Give each direction its own owner, monitor and reference, initialized for both opened and accepted sockets. Implement ERL_NIF_SELECT_CANCEL so selector death cancels only its direction, disposes its pending message, and leaves the other direction armed. Retain socket resources while lwIP write/error events are queued and detach callbacks on close. Notify established-socket waiters of terminal errors through direction-specific abort messages, independently of the connect trap. Keep distribution output event-driven so backpressure cannot block incoming traffic or ticks. Preserve pending frame suffixes and queue ticks behind them to maintain byte ordering. Send empty binaries through the native socket path so closed sockets still fail and connected UDP sockets transmit zero-length datagrams. Add regressions for accepted-socket close, writer death, both selector registration orders, exact-data backpressure recovery, cancellation cleanup, and empty UDP sends. Move the changelog entry to beta.1. See also: atomvm#2345 Signed-off-by: Peter M <petermm@gmail.com>
A cancelled selection retains its event for reuse. If the operating system later assigns the same descriptor to another resource, dispatch can find the inactive registration first and silently lose readiness for the new socket. Match only registrations that are open and armed for a reported direction. Extend the cancellation regression to verify that another resource using the same event receives readiness and both resources are released. Evaluate the test heap reservations outside assert expressions so assert macro expansion does not introduce duplicate unevaluated calls into the allocation-budget analysis. Signed-off-by: Peter M <petermm@gmail.com>
lwIP can free a TCP PCB before task-context error handling runs. Queuing raw PCBs or treating listeners as connections can therefore corrupt memory. Taking the VM socket lock from a callback would also invert the task-context lock order. A full wake queue must not turn an accepted payload into a failed enqueue and cause its resource reference to be released twice. Invalidate reset PCBs in the lwIP synchronization domain and retain socket resources for deferred work without resurrecting dying resources. Keep notification and monitor cleanup in task context. Use stable pending-accept slots to preserve pre-accept EOF and discard reset children without closing the listener. Retain critical work independently of the bounded payload queue. Leave refused TCP buffers with lwIP, make RP2 wakeups durable, and report payload acceptance independently of global wake hints. Share the RP2 CAS lock across translation units and protect reference updates from interrupts in single-scheduler builds as well. Detach callbacks according to the PCB type and guard PCB access with the lwIP lock. Preserve bytes accepted by tcp_write when tcp_output fails so callers cannot duplicate them on retry. Release replaced selector monitors and inactive BSD events on close, and provide read-only selection cancellation for the public receive wrappers. Signed-off-by: Peter M <petermm@gmail.com>
Receive and accept error cleanup currently stops both selections on a socket. A read-side EOF can consequently strand an independent writer that is waiting for its peer to drain buffered data. Cancel only the read selection in these cleanup paths. Keep the public send contract as ok or an error; document that sendto/3 is unchanged. Exercise the public receive path with a blocked public send in both selector registration orders. Fill the socket until backpressure is observed rather than relying on a fixed payload size, then verify that half-close preserves the writer and draining delivers every queued byte and the final marker. Keep close and writer-death coverage alongside this regression. The half-close case times out with the old socket wrapper and passes with read-only cleanup. Update the changelog with the user-visible half-close behavior. Signed-off-by: Peter M <petermm@gmail.com>
sendto/3 currently exposes transient backpressure instead of waiting for acceptance like the default OTP call. Retrying a partial result as a new datagram would also change packet boundaries. Wait for write readiness and retry the original payload and destination. Keep empty datagrams on the native path and return partial results without resending their tails. Back off retries for 10 ms because raw lwIP reports UDP write readiness immediately even after ERR_MEM. Reject oversized IPv4 UDP payloads before conversion to lwIP packet lengths, and preserve BSD sendto errors instead of reporting them as closed sockets. Extend the UDP tests for empty and iodata packets, oversized rejection, and sends on closed sockets. Signed-off-by: Peter M <petermm@gmail.com>
Socket backpressure leaves ticks queued instead of completing their send. Treating outgoing activity as proof of peer liveness lets a silent connection reset its timeout indefinitely. Renew the tick timeout only when the receive counter changes, and report pending controller bytes so ticks are not queued behind blocked output. Keep a peer alive when it continues sending traffic, matching OTP keepalive behavior. Exercise a real TCP distribution handshake with blocked output, outgoing-only activity, and inbound ticks arriving at the deadline. Verify silence disconnects after four ticks and queued ticks stay bounded. See also: atomvm#2424 Signed-off-by: Peter M <petermm@gmail.com>
Align TCP writes with available send capacity while preserving empty sends. Keep select-cancellation setup and mailbox operations running when assertions are disabled. Signed-off-by: Peter M <petermm@gmail.com>
Preserve real send errors and bytes accepted before a reset or full shutdown. Defer closed notifications until queued TCP payloads have reached task context, and avoid accessing a freed PCB while draining. Pace TCP allocation retries with sent or poll callbacks. Report UDP allocation errors directly because immediate readiness cannot signal memory recovery and the platform timeout pool cannot support retries. Add directional write cancellation without disturbing an independent reader, including shared ownership. Validate selection states before replacing monitors and notify closed selections with their references. Exercise public native socket operations and real OS errors. Evaluate test setup, mailbox and cleanup operations outside assertions so they still execute when NDEBUG is defined. Signed-off-by: Peter Madsen-Mygdal <petermm@gmail.com>
Registration can change the event list before marking the cached count dirty. Always recount while holding the list lock so allocation and population use the same snapshot. Publish the rebuilt count before unlocking to avoid overwriting a concurrent registration dirty marker and losing its wakeup. Signed-off-by: Peter Madsen-Mygdal <petermm@gmail.com>
Expose send/3 and sendto/4 with timeout, nowait and caller reference forms. Use one monotonic deadline across retries and return the unsent suffix when a stream send fails after making progress. Cancel only write readiness on timeout so an independent reader keeps its original selection, even when both directions share an owner. Preserve datagram boundaries instead of retrying a partial suffix. Cover timeout recovery, partial results, closed sockets and datagram boundaries through public APIs. Replace silence-based backpressure assumptions with explicit readiness, handshakes and byte accounting. Signed-off-by: Peter Madsen-Mygdal <petermm@gmail.com>
A blocking send in a socket server prevents receive and close requests from completing under backpressure. Use nowait sends and resume queued output on write readiness while preserving FIFO order. Release pending send callers on close, abort or controlling-process death, monitor passive owners, and return closed when send races a normally stopped server. Receive cleanup cancels only read selection. Test receive and close responsiveness during an in-progress TCP send, ordered draining, and UDP error recovery with intact packet boundaries. Signed-off-by: Peter Madsen-Mygdal <petermm@gmail.com>
A node can disconnect before its ALIVE2 response is sent. Close that registration socket on send failure without crashing epmd, changing existing registrations or consuming a creation value. Use the public registration protocol to verify failure recovery. The deterministic response-write shutdown uses OTP socket registry and monitor APIs, so that fault injection runs only on BEAM. Signed-off-by: Peter Madsen-Mygdal <petermm@gmail.com>
Explain timeout and asynchronous send results, unsent stream suffixes, directional cancellation and preserved datagram boundaries. Document raw-lwIP UDP allocation errors rather than promising automatic retry. Record the send APIs, responsive socket servers, native lifetime and poll fixes, and epmd recovery under the upcoming release. Signed-off-by: Peter Madsen-Mygdal <petermm@gmail.com>
petermm
force-pushed
the
nif_select_write/2
branch
from
November 6, 2026 17:46
de4ce2a to
8c0b058
Compare
Live socket owners cancel selections from resource-down callbacks during context destruction. Keep platform services alive for those callbacks, then stop platform event producers before dismantling shared event lists. Mark directly destroyed contexts killed under the scheduler-list lock so late platform notifications cannot requeue a dying context. Add a live read/write owner shutdown regression and changelog entry. The regression reports eight Valgrind invalid-access contexts before the ordering fix and none after it. Signed-off-by: Peter Madsen-Mygdal <petermm@gmail.com>
Completed socket operations retained their timer workers until expiry. Expiry bursts overloaded the timer manager during backpressured receives under Valgrind, causing new timer registrations to time out. Cancel accept and receive timers on completion, abort and termination. Allocate timers only after successful selection, and leave infinite receives without the old artificial 30-second timeout. Add a regression for timer cleanup and receive recovery after timeout, and record the fix in the changelog. Signed-off-by: Peter Madsen-Mygdal <petermm@gmail.com>
Module teardown freed the import pointer array but leaked its owned unresolved and resolved function descriptors. Free those allocations, including native-code descriptors, without freeing borrowed BIF or NIF registry entries. Keep the import count in the module so cleanup does not read BEAM data that another module may already have freed. Record the count before allocating descriptors to support partially initialized tables. Strict Valgrind checks cover genTCP, native-code imports, allocation failures and repeated code:load_binary teardown with compressed literals. Signed-off-by: Peter Madsen-Mygdal <petermm@gmail.com>
petermm
force-pushed
the
nif_select_write/2
branch
from
November 7, 2026 07:50
2dd4ae0 to
0f8bb30
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
little bit of mess with these PRs - so lets land a single one
fixes a plethora of issues with httpd etc.
this is the (original) work from #2345 (that PR was a git history rewrite of my work) progressed to PR readiness, also relates to #2416
These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).
SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later