docs(initnsmgr): thread-spawn investigation revises A-vs-B ordering
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<Mutex> 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.
This commit is contained in:
@@ -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<Socket>` 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<Mutex<Namespace>>`, 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<Mutex<Namespace>>` 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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user