From e38a44430368f6c3a0bd1d889727a235afb97278 Mon Sep 17 00:00:00 2001 From: vasilito Date: Wed, 22 Jul 2026 10:14:55 +0900 Subject: [PATCH] docs(initnsmgr): thread-spawn investigation revises A-vs-B ordering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Investigated the bootstrap thread bring-up needed for Design A (worker-offload). Finding: `rlct_clone_impl` requires a fully-built TCB for the new thread, but bootstrap's freestanding redox_rt has no Tcb::new / TLS allocator / thread shim (only initialize_freestanding's single TCB). So Design A needs, as a prerequisite, a freestanding thread-spawn helper in redox_rt (its own task) — open-coding TCB/TLS in initnsmgr is not acceptable. Revised ordering: keep Step 1 (Arc Send refactor, inert until A), boot-validate on idle + commit; then prefer Design B (kernel O_NONBLOCK on open + single-thread deferred, no bootstrap threads) as the first functional step; Design A later once redox_rt grows the freestanding thread helper. All still require an idle host to validate. --- local/docs/INITNSMGR-CONCURRENCY-DESIGN.md | 52 +++++++++++++++++----- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/local/docs/INITNSMGR-CONCURRENCY-DESIGN.md b/local/docs/INITNSMGR-CONCURRENCY-DESIGN.md index 983abf02de..aea89c8146 100644 --- a/local/docs/INITNSMGR-CONCURRENCY-DESIGN.md +++ b/local/docs/INITNSMGR-CONCURRENCY-DESIGN.md @@ -46,10 +46,27 @@ keeps accepting requests. The worker replies out-of-band when the open completes - **`Socket`** (redox-scheme) is an fd wrapper; `write_response(&self, …)` takes `&self`, and `CallRequest → Tag` is `Send`. Share the socket as `Arc` so a worker can reply. - **`redox_rt::thread::rlct_clone_impl`** (`redox-rt/src/thread.rs`) — the raw thread primitive. - **This is the risky part**: bootstrap is `#![no_std]` and does not link relibc's `pthread`, so a - worker thread must be brought up by hand (stack `mmap`, TCB alloc/init, TLS, then `rlct_clone_impl`) - — the minimal subset of what `relibc/src/pthread/mod.rs:203` + `platform/redox/mod.rs:1089` do. - Budget this as the main implementation cost. + **This is the hard blocker, and it is worse than first estimated.** `rlct_clone_impl(stack, tcb: + &RtTcb)` requires a *fully-constructed TCB for the new thread*. relibc's `pthread_create` builds + that TCB with `Tcb::new(tls_len)` (`relibc/src/pthread/mod.rs:167`), pushes the entry/arg/tcb/shim + onto a freshly `mmap`ed stack (`:177-201`), calls `rlct_clone`, and the `new_thread_shim` + (`:218`) activates the TCB (TLS) + installs the signal handler before jumping to the entry point. + **bootstrap has none of this**: it runs `redox_rt::initialize_freestanding(this_thr_fd)` + (`exec.rs:71`), which sets up exactly ONE TCB (`RtTcb::current()`); there is no `Tcb::new`, no TLS + allocator, no thread shim in the freestanding path. So Design A needs, as a prerequisite, either: + 1. **Port a minimal thread-spawn helper into `redox_rt`'s freestanding path** — allocate a stack, + build a new `RtTcb`, wire the TLS masters pointers, and provide a shim — the low-level, + arch-specific core of `pthread_create`, but without relibc `std`. This is the real cost, and it + is deep `unsafe` in the earliest-boot component. + 2. **Or use worker PROCESSES, not threads.** bootstrap already forks its three services via + `spawn` (`exec.rs:290`). But processes do not share `Arc>`, so the dispatcher + would have to pass each resolved `cap_fd` + reply `Tag` to a worker process over a pipe/socket + and the worker replies on the shared scheme socket — more moving parts than threads. + + **Consequence:** the "just call rlct_clone" framing was too optimistic. Given this, **Design B + (below) is now the more attractive first step** — it needs no bootstrap threads at all. Design A + remains the cleaner end-state *if* a freestanding thread-spawn helper is added to `redox_rt` + first (that helper is independently useful and should be its own task). ### State changes @@ -151,13 +168,28 @@ Avoids the no_std thread bring-up entirely, at the cost of a kernel change with B is architecturally cleaner (no threads in the earliest-boot component) but changes scheme-open semantics for *every* scheme in the system, so it needs the strongest system-wide validation. -## Recommendation +## Recommendation (revised 2026-07-22 after the thread-spawn investigation) -Start with **A**. It is contained in one component and does not change kernel or redox-scheme -semantics for the rest of the system, so a regression is bounded to initnsmgr and reversible by -reverting one file. Its cost is the manual thread bring-up in no_std; budget that explicitly. -Consider **B** later as the cleaner long-term shape, or if upstream Redox moves scheme-open toward -non-blocking semantics anyway. +The original recommendation was "start with A". After confirming that bootstrap's freestanding +`redox_rt` has **no thread-spawn machinery** (no `Tcb::new`, no TLS allocator, no thread shim — see +the `rlct_clone_impl` note above), the ordering changes: + +- **Step 1 (Send refactor) is done and stands regardless of A vs B** — `Arc>` is + a strict improvement and a prerequisite for A; it is inert (single-threaded) until A lands. + Keep it (currently `local/patches/wip-initnsmgr/step1-send-refactor.patch`), boot-validate on an + idle host, and commit. +- **Prefer Design B (kernel `O_NONBLOCK` on open + single-thread deferred) as the first functional + step.** It needs no bootstrap threads, reuses the `RawEventQueue` pattern acpid already runs, and + immediately activates fbcond's existing retry. Its cost is a kernel scheme-open change with a + system-wide blast radius — so it needs strong validation — but it avoids the deepest `unsafe` in + the earliest-boot component. +- **Design A remains the cleaner end-state**, but only after a **freestanding thread-spawn helper** + is added to `redox_rt` as its own, independently-useful task. Do not attempt A's worker bring-up + by open-coding TCB/TLS setup inside initnsmgr. + +Net: **Step 1 → (idle validation + commit) → Design B for the functional fix → Design A later** once +`redox_rt` grows a freestanding thread helper. All of this still requires an idle host or real +hardware; none of it can be validated under the current external load. ## Staged implementation plan (A)