pub fn spawn_dedicated_thread<F>(
name: String,
priority: ThreadPriority,
stack: StackSizeClass,
f: F,
) -> Result<JoinHandle<()>>Expand description
Spawn a dedicated OS thread that runs f at priority with a stack
of StackSizeClass, plus whatever ambient async context
block_on_sync needs on this target.
§Why the stack class is a parameter and not a default
C creates an IOC thread with epicsThreadCreate(name, priority, stackSize, fn, arg) — three attributes. This seam carried the first two and let the
third fall through to whatever std picks, which is 2 MiB on RTEMS:
std/src/sys/thread/unix.rs gates its DEFAULT_MIN_STACK_SIZE on
not(any(l4re, vxworks, espidf, nuttx)), and vxWorks got a 256 KiB
carve-out where RTEMS did not.
That is invisible on the host, where a thread stack is lazily-committed virtual address space, and decisive on the target, where it is carved eagerly out of a fixed pool. Making it a parameter is what stops a new per-connection thread from silently costing 2 MiB: there is no default to inherit, so every caller states what the thread is for.
Not spawn_blocking_with_priority, and the difference is the point.
That one hands the closure to a pool: tokio’s blocking pool on the host,
and on RTEMS a shared callback-pool worker that also drops the priority
(see its exec_backend arm). Both are right for work that finishes. A
server thread that lives as long as its connection would occupy a pool
worker for that whole time, so the pool is the wrong home for it — an IOC
thread that a C IOC would create with epicsThreadCreate wants a thread of
its own, and the priority a C IOC gives it.
§Why the ambient context is part of this, and not the caller’s problem
block_on_sync picks its mechanism from the thread it is called on, but it
cannot create the context a future needs. On the host a fresh
std::thread has no runtime, so a future that spawns tasks or arms timers
panics with “there is no reactor running” the moment it is polled — even
though block_on_sync itself was perfectly happy to park. On RTEMS the
exec backend is process-global (background_init), so a bare thread is
already complete. That asymmetry is a property of the two backends, so it
is resolved here, at the seam, rather than by a cfg in every server that
wants a thread.
The captured context is whatever the calling thread is running under, so call this from the runtime the work should belong to. When there is none (RTEMS always; on the host a caller that is itself outside a runtime) the thread simply runs without one, which is exactly right for a future whose awaits are all runtime-agnostic.
§A current-thread ambient is not inherited, and that is the rule
RuntimeHandle::try_current answers two different questions with one
value: “am I running on this runtime’s thread” and “has this thread
merely entered this handle”. block_on_sync cannot distinguish them, so
it must assume the first and refuse to park under a CurrentThread flavor —
correct on that runtime’s own thread, where parking halts the task that
would wake you, and wrong on a dedicated thread, where it halts nothing.
So the dual meaning is removed here, at the one place a dedicated thread’s
context is decided, rather than left for block_on_sync to guess: a
CurrentThread ambient is not inherited, and the thread runs with no
runtime — the park_on arm, which is sound for it and is the only arm RTEMS
ever takes.
Nothing is lost by declining it. What inheriting buys is stated above —
spawn and the timer inside block_on_sync — and under a CurrentThread
ambient block_on_sync returns
Err(CurrentThreadRuntime), so every one of those
powers is unreachable anyway. Inheriting it can only convert a thread that
would have worked into one that cannot block at all. Measured as exactly
that: the PVA client’s blocking byte pumps
(runtime::blocking_io::spawn_pump) are dedicated threads whose bodies are
pure tokio::sync channel traffic, and every #[tokio::test] that drives
one is CurrentThread by default — inheritance made the reader pump exit on
its first chunk and the connection read as “server closed during handshake”.