pub struct ServerState {
cfg: Result<ServerConfig, ErrorEnvelope>,
pub script_dir: PathBuf,
pub worker: Mutex<WorkerSlot>,
pub poison: Mutex<PoisonSet>,
pub sem: Semaphore,
pub boot_done: Notify,
pub boot_count: AtomicUsize,
}Fields§
§cfg: Result<ServerConfig, ErrorEnvelope>The resolved configuration, or the failure that resolving it produced.
Held as a Result rather than a ServerConfig so that serve can start, handshake and list
its tools on a machine with no Ghidra install. Resolution still happens ONCE, at construction —
the inputs are CLI flags and environment variables, immutable for the process’s lifetime — so
what is deferred is the FAILURE, not the work. Every call therefore reports the same error, and
no lock or interior mutability is needed to read it on the hot path.
Private on purpose: reach it through ServerState::cfg, which is the ?-able accessor that
makes the deferred failure impossible to ignore at a call site.
script_dir: PathBuf§worker: Mutex<WorkerSlot>§poison: Mutex<PoisonSet>§sem: Semaphore§boot_done: NotifySignalled by spawn_boot when a background boot finishes (success OR failure), so a caller
waiting out warming_deadline (execute.rs §4.7) wakes promptly instead of polling blind.
boot_count: AtomicUsizeCount of worker boots attempted (test-only single-flight assertion; spec §8).
Implementations§
Source§impl ServerState
impl ServerState
Sourcepub fn new(cfg: ServerConfig, script_dir: PathBuf) -> Self
pub fn new(cfg: ServerConfig, script_dir: PathBuf) -> Self
Build from an already-resolved configuration.
Sourcepub fn from_raw(raw: RawConfig, script_dir: PathBuf) -> Self
pub fn from_raw(raw: RawConfig, script_dir: PathBuf) -> Self
Build from unresolved inputs, deferring any resolution failure to the first tool call.
This is what serve uses. A configuration that cannot resolve is no longer fatal at startup:
the server comes up, tools/list answers normally, and the failure is reported by
ServerState::cfg when something actually needs the worker.
fn build(cfg: Result<ServerConfig, ErrorEnvelope>, script_dir: PathBuf) -> Self
Sourcepub fn cfg(&self) -> Result<&ServerConfig, ErrorEnvelope>
pub fn cfg(&self) -> Result<&ServerConfig, ErrorEnvelope>
The resolved configuration, or the deferred configuration failure.
Returns an owned error so callers can ? it out of a Result<_, ErrorEnvelope> without
fighting the borrow of self.
Sourcepub fn is_configured(&self) -> bool
pub fn is_configured(&self) -> bool
Whether a worker could be booted at all. false means there is no usable configuration, so
anything that would launch or talk to a worker must decline instead of trying.
Sourcepub fn boot_count(&self) -> usize
pub fn boot_count(&self) -> usize
Number of worker boots attempted (test-only single-flight assertion; spec §8).
Sourcepub(crate) async fn boot_and_probe(&self) -> Result<WorkerHolder, ErrorEnvelope>
pub(crate) async fn boot_and_probe(&self) -> Result<WorkerHolder, ErrorEnvelope>
Boot a worker, verify version, call worker_info to learn the bootstrap program + geometry, and build the canonicalizer.
Source§impl ServerState
impl ServerState
Sourcepub fn spawn_boot(self: Arc<Self>)
pub fn spawn_boot(self: Arc<Self>)
Spawn the single-flight background boot. Caller must have set the slot to Booting while
holding the lock (so exactly one boot runs). On completion the task stores Ready/Fatal, or
resets to Empty on a transient failure (retryable).
Sourcepub async fn start_warmup(self: &Arc<Self>)
pub async fn start_warmup(self: &Arc<Self>)
Start the single-flight warmup boot: if the slot is Empty, mark it Booting under the lock and
spawn the background boot; a slot already Booting/Ready/Fatal is left alone so exactly one
boot ever runs. This is the ONLY correct way to kick a warmup — calling spawn_boot directly on an
Empty slot leaves it Empty (spawn_boot publishes only when it finds Booting), so a racing
wait_until_ready would launch a SECOND concurrent boot (two JVMs → project LockException).