From 4307425b27457751160ecb2af5ac748f37b61950 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 13 Nov 2026 08:21:16 +0100 Subject: [PATCH] docs: SHARED-ENGINES' Net::FTP example described code that has since changed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "a deadline belongs to the engine's API" section is the worked example for the whole shared-engine argument, and it described the binding in the past tense as having no timeout and no read deadline "anywhere". That was true when it was written and is not true now: #921 is merged. A reader arriving at that page would conclude rbgo still has neither. The argument is unchanged -- an unbounded read in an engine four languages share is still a shared denial of service, and the neutral engine should still take a deadline in its own API. What changed is the consumer's half, so that is what the new subsection records: - open_timeout (default nil, unbounded) and read_timeout (default 60), from the options Hash and from the attr writers, with the deadline armed PER READ. Non-positive means no bound, as in MRI. - the GVL released around the control connection, plus an AST gate that refuses a new blocking socket call holding it (#924), with the dose-response that proved the mechanism. ⛔ And the honest limit, which is the reason the extraction warning STAYS: the measurement did not move. The library/net-ftp specs are byte-identical after both changes -- still 39 killed, 459/17, -442. Both fixes are necessary and proved on a minimal reproduction, but at least one cause remains and it is in the spec-harness path. The three candidates eliminated so far are named, with how they were eliminated (by reading, not by timing, since the machine was too loaded for a timeout to mean anything). Writing "fixed" here while the number sits where it was is exactly how a docs page stops being evidence. Refs #916 Co-Authored-By: Claude Opus 5 --- docs/SHARED-ENGINES.md | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/SHARED-ENGINES.md b/docs/SHARED-ENGINES.md index dcbed9b6..d84ab96a 100644 --- a/docs/SHARED-ENGINES.md +++ b/docs/SHARED-ENGINES.md @@ -67,8 +67,37 @@ an engine four languages share is a shared denial of service**, needing no exploit, only silence. When `net-*` is extracted, the neutral engine takes a deadline in its own API rather than trusting every caller to impose one. -⛔ `net-ftp` is **mid-change in this repository** and is not available for -extraction until #916 settles. +#### Where the consumer's half now stands (2026-11-13) + +The binding side has since been done, which changes what a reader should expect +from the code without changing the conclusion above: + +- **Bounded** — `Net::FTP` takes MRI's `open_timeout` (default `nil`, an + unbounded connect) and `read_timeout` (default `60`), from the constructor's + options Hash and from the attr writers, and arms a deadline **per read** + rather than per exchange ([#921](https://github.com/go-embedded-ruby/ruby/pull/921), + merged). A non-positive value means *no bound*, as in MRI — not "expire at + once". +- **The GVL is released** around the control connection's blocking calls, and + an AST gate refuses a new blocking socket call that holds it + ([#924](https://github.com/go-embedded-ruby/ruby/pull/924)). rbgo emulates a + GVL, so a native call that blocks while holding it stops every other Ruby + thread: a spec that serves itself had its server thread return from `Accept` + and then park on a lock the client was sitting on. Dose-response: a 2 s client + deadline made the accept complete at 2.308 s, a 5 s one at 5.307 s, and + `ioBlock` at 0.305 s. + +⛔ **And yet #916 is not closed, because the measurement did not move.** The +`library/net-ftp` specs are byte-identical after both changes: still 39 killed, +still 459/17, still −442. Both fixes are necessary and proved on a minimal +reproduction; at least one further cause remains, and it is in the +spec-harness path. Three candidates have been eliminated by reading rather than +by timing — `setsockopt`/`SO_OOBINLINE` exist, every read in `socket.go` +already releases the GVL, and the fixture's `ruby_version_is ""..."4.1"` guard +does open at rbgo's `RUBY_VERSION`. + +⛔ `net-ftp` is therefore still **mid-change in this repository** and is not +available for extraction until #916 settles. ## First inventory of the 178 `go-ruby-*` modules rbgo binds