From 2045cec9c1148779a827f07c2dc46074a396d0ce Mon Sep 17 00:00:00 2001 From: Weidong Cui Date: Wed, 23 Sep 2026 15:30:30 -0700 Subject: [PATCH 1/8] Complete duplication startup publication Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ee779b34-31e2-4e38-8068-21fe8fce7674 --- litebox_broker_core/src/lib.rs | 10 +- litebox_broker_core/src/process.rs | 164 ++++++++++++------ litebox_broker_host/src/lib.rs | 68 +++++++- litebox_broker_host/src/test_support.rs | 2 +- .../src/process_launcher.rs | 28 ++- litebox_broker_userland/src/runtime.rs | 19 +- 6 files changed, 215 insertions(+), 76 deletions(-) diff --git a/litebox_broker_core/src/lib.rs b/litebox_broker_core/src/lib.rs index d2a5191c9..8c5519f62 100644 --- a/litebox_broker_core/src/lib.rs +++ b/litebox_broker_core/src/lib.rs @@ -53,7 +53,7 @@ pub use process::{ AssociationCancellation, BrokerProcess, BrokerThread, CallerCredential, DuplicationTransaction, ObjectRights, ProcessLifecycleSink, ProcessShutdown, }; -use process::{ObjectReference, ProcessParent, ProcessRoot}; +use process::{ObjectReference, ProcessParent, ProcessRoot, ProcessStartKind}; use random::RandomProvider; use socket::{BrokerSocketPorts, SocketProvider}; use stdio::StdioProvider; @@ -348,17 +348,19 @@ impl BrokerCore { caller_credential, Some(ProcessParent::new(&parent)), Some(root), + ProcessStartKind::Association, ) })?; } - self.register_process(caller_credential, None, None) + self.register_process(caller_credential, None, None, ProcessStartKind::Association) } - fn register_process( + pub(crate) fn register_process( &self, caller_credential: CallerCredential, parent: Option, root: Option>, + start_kind: ProcessStartKind, ) -> Result> { let mut processes = self.processes.write(); if processes.len() >= self.limits.max_processes { @@ -375,6 +377,7 @@ impl BrokerCore { id, root, parent, + start_kind, caller_credential, )) } else { @@ -385,6 +388,7 @@ impl BrokerCore { id, Arc::new(ProcessRoot::new(root_process.clone())), None, + start_kind, caller_credential, ) }) diff --git a/litebox_broker_core/src/process.rs b/litebox_broker_core/src/process.rs index a69f94416..d35bce625 100644 --- a/litebox_broker_core/src/process.rs +++ b/litebox_broker_core/src/process.rs @@ -148,8 +148,6 @@ pub struct BrokerProcess { /// Assigned process ID and internal authority. pub(crate) id: ProcessId, root: Arc, - /// Parent that created this record; unlike the wait parent, never changes. - creation_parent: Option>, state: Mutex, /// Broker-entry-authenticated caller credential for this process. pub(crate) caller_credential: CallerCredential, @@ -217,30 +215,93 @@ pub(crate) enum ProcessRequestOrigin { /// Broker-owned state for one admitted process-duplication attempt. /// /// At most one transaction may be active for a process. Initial admission does -/// not allocate a child; [`Self::publish`] accepts the fully prepared staged -/// child and owns its rollback while arbitrating publication. +/// not allocate a child; [`Self::create_child`] allocates and binds the exact +/// staged child later committed by [`Self::publish`]. pub struct DuplicationTransaction { owner: Arc, - /// Child retained during publication so transaction drop can roll it back. + /// Child retained from allocation through publication for rollback. child: Option>, active: bool, } impl DuplicationTransaction { + /// Allocates and binds the staged child owned by this transaction. + /// + /// The child's wait parent reflects any owner death that completed before + /// allocation. Once returned, dropping the transaction rolls the child + /// back if publication has not committed it. + pub fn create_child(&mut self) -> Result<(Arc, ThreadId)> { + if !self.active || self.child.is_some() { + return Err(BrokerError::Internal); + } + + let child = { + let owner_state = self.owner.state.lock(); + if owner_state.owner_alive { + let child = self.owner.core.register_process( + self.owner.caller_credential, + Some(ProcessParent::new(&self.owner)), + Some(Arc::clone(&self.owner.root)), + ProcessStartKind::Duplication, + )?; + drop(owner_state); + child + } else { + drop(owner_state); + let root = self + .owner + .root + .process() + .filter(|root| !Arc::ptr_eq(root, &self.owner)); + if let Some(root) = root { + let state = root.state.lock(); + let parent = (state.owner_alive + && matches!(state.retirement, ProcessRetirement::Active { .. })) + .then(|| ProcessParent::new(&root)); + let child = self.owner.core.register_process( + self.owner.caller_credential, + parent, + Some(Arc::clone(&self.owner.root)), + ProcessStartKind::Duplication, + )?; + drop(state); + child + } else { + self.owner.core.register_process( + self.owner.caller_credential, + None, + Some(Arc::clone(&self.owner.root)), + ProcessStartKind::Duplication, + )? + } + } + }; + let initial_thread_id = match child.create_thread() { + Ok(initial_thread_id) => initial_thread_id, + Err(error) => { + child.retire(true); + return Err(error); + } + }; + self.child = Some(Arc::clone(&child)); + Ok((child, initial_thread_id)) + } + /// Publishes a staged child after successful installation and validation. /// /// Publication transitions the child to running and releases the owner's /// transaction slot under the same lock. Parent cancellation or death does /// not veto a child that completed setup successfully. - pub fn publish(mut self, child: Arc) -> Result { - if !self.active - || Arc::ptr_eq(&self.owner, &child) - || !Arc::ptr_eq(&self.owner.core.processes, &child.core.processes) - || !child - .creation_parent - .as_ref() - .is_some_and(|parent| Weak::ptr_eq(parent, &Arc::downgrade(&self.owner))) - { + pub fn publish(mut self, process: &Arc) -> Result { + if !self.active { + return Err(BrokerError::Internal); + } + let child = self + .child + .as_ref() + .map(Arc::clone) + .ok_or(BrokerError::Internal)?; + if !Arc::ptr_eq(&child, process) { return Err(BrokerError::Internal); } @@ -249,8 +310,6 @@ impl DuplicationTransaction { self.active = false; return Err(BrokerError::Internal); } - self.child = Some(Arc::clone(&child)); - let mut child_state = child.state.lock(); let child_threads = child.threads.lock(); let child_starting = matches!( @@ -499,16 +558,15 @@ impl BrokerProcess { id: ProcessId, root: Arc, parent: Option, + start_kind: ProcessStartKind, caller_credential: CallerCredential, ) -> Self { - let creation_parent = parent.as_ref().map(|parent| Weak::clone(&parent.process)); Self { core, id, root, - creation_parent, state: Mutex::new(BrokerProcessState { - record: ProcessRecordState::Starting(ProcessStartKind::Association), + record: ProcessRecordState::Starting(start_kind), parent, owner_alive: true, duplication_active: false, @@ -1552,19 +1610,14 @@ mod tests { } fn staged_duplication( - broker: &BrokerCore, parent: &Arc, ) -> ( super::DuplicationTransaction, Arc, ProcessIdentity, ) { - let transaction = parent.begin_duplication().unwrap(); - let child = broker - .create_process(parent.caller_credential(), Some(parent.id())) - .unwrap(); - child.state.lock().record = ProcessRecordState::Starting(ProcessStartKind::Duplication); - let initial_thread_id = child.create_thread().unwrap(); + let mut transaction = parent.begin_duplication().unwrap(); + let (child, initial_thread_id) = transaction.create_child().unwrap(); let identity = ProcessIdentity { process_id: child.id(), initial_thread_id, @@ -1715,10 +1768,10 @@ mod tests { .create_process(CallerCredential::Unauthenticated, None) .unwrap(); parent.complete_start().unwrap(); - let (transaction, child, identity) = staged_duplication(&broker, &parent); + let (transaction, child, identity) = staged_duplication(&parent); assert_eq!(child.complete_start(), Err(BrokerError::Internal)); - assert_eq!(transaction.publish(Arc::clone(&child)), Ok(identity)); + assert_eq!(transaction.publish(&child), Ok(identity)); assert_eq!(child.state.lock().record, ProcessRecordState::Running); assert!(parent.begin_duplication().is_ok()); @@ -1726,8 +1779,8 @@ mod tests { .create_process(CallerCredential::Unauthenticated, None) .unwrap(); second_parent.complete_start().unwrap(); - let (transaction, second_child, identity) = staged_duplication(&broker, &second_parent); - assert_eq!(transaction.publish(Arc::clone(&second_child)), Ok(identity)); + let (transaction, second_child, identity) = staged_duplication(&second_parent); + assert_eq!(transaction.publish(&second_child), Ok(identity)); second_parent.handle_owner_death(); @@ -1739,7 +1792,7 @@ mod tests { } #[test] - fn duplication_publication_rejects_owner_and_unrelated_child() { + fn duplication_transaction_owns_staged_child() { let broker = TestBrokerCoreBuilder::new( PolicyEngine::with_unauthenticated_rights(ObjectRights::all()) .with_process_duplication_enabled(true), @@ -1752,9 +1805,19 @@ mod tests { .unwrap(); owner.complete_start().unwrap(); let transaction = owner.begin_duplication().unwrap(); - assert_eq!( - transaction.publish(Arc::clone(&owner)), + assert_eq!(transaction.publish(&owner), Err(BrokerError::Internal)); + assert!(owner.begin_duplication().is_ok()); + + let mut transaction = owner.begin_duplication().unwrap(); + let (child, _) = transaction.create_child().unwrap(); + assert!(matches!( + transaction.create_child(), Err(BrokerError::Internal) + )); + drop(transaction); + assert_eq!( + child.state.lock().record, + ProcessRecordState::Failed(BrokerError::PeerClosed) ); assert!(owner.begin_duplication().is_ok()); @@ -1762,26 +1825,24 @@ mod tests { .create_process(CallerCredential::Unauthenticated, None) .unwrap(); first_parent.complete_start().unwrap(); - let first_transaction = first_parent.begin_duplication().unwrap(); - + let (first_transaction, first_child, _) = staged_duplication(&first_parent); let second_parent = broker .create_process(CallerCredential::Unauthenticated, None) .unwrap(); second_parent.complete_start().unwrap(); let (second_transaction, second_child, second_identity) = - staged_duplication(&broker, &second_parent); + staged_duplication(&second_parent); assert_eq!( - first_transaction.publish(Arc::clone(&second_child)), + first_transaction.publish(&second_child), Err(BrokerError::Internal) ); assert_eq!( - second_child.state.lock().record, - ProcessRecordState::Starting(ProcessStartKind::Duplication) + first_child.state.lock().record, + ProcessRecordState::Failed(BrokerError::PeerClosed) ); - assert!(first_parent.begin_duplication().is_ok()); assert_eq!( - second_transaction.publish(Arc::clone(&second_child)), + second_transaction.publish(&second_child), Ok(second_identity) ); } @@ -1799,8 +1860,7 @@ mod tests { .create_process(CallerCredential::Unauthenticated, None) .unwrap(); cancelled_parent.complete_start().unwrap(); - let (transaction, cancelled_child, identity) = - staged_duplication(&broker, &cancelled_parent); + let (transaction, cancelled_child, identity) = staged_duplication(&cancelled_parent); let shutdowns = Arc::new(AtomicUsize::new(0)); let shutdown_count = Arc::clone(&shutdowns); cancelled_child.install_shutdown(Arc::new(move || { @@ -1808,10 +1868,7 @@ mod tests { })); cancelled_parent.request_cancellation(); - assert_eq!( - transaction.publish(Arc::clone(&cancelled_child)), - Ok(identity) - ); + assert_eq!(transaction.publish(&cancelled_child), Ok(identity)); assert_eq!( cancelled_child.state.lock().record, ProcessRecordState::Running @@ -1826,10 +1883,15 @@ mod tests { .create_process(CallerCredential::Unauthenticated, None) .unwrap(); dead_parent.complete_start().unwrap(); - let (transaction, dead_child, identity) = staged_duplication(&broker, &dead_parent); + let mut transaction = dead_parent.begin_duplication().unwrap(); dead_parent.handle_owner_death(); + let (dead_child, initial_thread_id) = transaction.create_child().unwrap(); + let identity = ProcessIdentity { + process_id: dead_child.id(), + initial_thread_id, + }; - assert_eq!(transaction.publish(Arc::clone(&dead_child)), Ok(identity)); + assert_eq!(transaction.publish(&dead_child), Ok(identity)); assert_eq!(dead_child.state.lock().record, ProcessRecordState::Running); assert_eq!(parent_id(&dead_child), None); @@ -1837,13 +1899,13 @@ mod tests { .create_process(CallerCredential::Unauthenticated, None) .unwrap(); live_parent.complete_start().unwrap(); - let (transaction, failed_child, _) = staged_duplication(&broker, &live_parent); + let (transaction, failed_child, _) = staged_duplication(&live_parent); assert_eq!( failed_child.fail_start(BrokerError::PeerClosed, false, true), Err(BrokerError::PeerClosed) ); assert_eq!( - transaction.publish(Arc::clone(&failed_child)), + transaction.publish(&failed_child), Err(BrokerError::WouldBlock) ); assert!(live_parent.begin_duplication().is_ok()); diff --git a/litebox_broker_host/src/lib.rs b/litebox_broker_host/src/lib.rs index a343af86d..694b50954 100644 --- a/litebox_broker_host/src/lib.rs +++ b/litebox_broker_host/src/lib.rs @@ -24,7 +24,9 @@ extern crate std; use alloc::{sync::Arc, vec::Vec}; use litebox_broker_core::readiness::ReadinessSink; -use litebox_broker_core::{BrokerCore, BrokerError, BrokerProcess, CallerCredential}; +use litebox_broker_core::{ + BrokerCore, BrokerError, BrokerProcess, CallerCredential, DuplicationTransaction, +}; use litebox_broker_protocol::error::ErrorCode; use litebox_broker_protocol::event::{AddEventResponse, CreateEventResponse}; use litebox_broker_protocol::fs::{ @@ -96,6 +98,14 @@ struct AssociationState { shared_buffer_usage: SharedBufferUsage, } +/// Broker-core action that commits one validated runner association. +pub enum ProcessStartupCompletion { + /// Completes ordinary association startup. + Association, + /// Publishes the exact staged child owned by a duplication transaction. + Duplication(DuplicationTransaction), +} + impl BrokerHostAssociation { fn new( process: Arc, @@ -113,9 +123,20 @@ impl BrokerHostAssociation { } } - /// Marks the process running after deployment-specific association activation. - pub fn activate_process(&self) -> litebox_broker_core::Result<()> { - self.process.complete_start() + /// Commits process startup after deployment-specific installation and validation. + /// + /// A duplication completion must remain paired with the exact process + /// association supplied by its transaction. + pub fn complete_startup( + &self, + completion: ProcessStartupCompletion, + ) -> litebox_broker_core::Result<()> { + match completion { + ProcessStartupCompletion::Association => self.process.complete_start(), + ProcessStartupCompletion::Duplication(transaction) => { + transaction.publish(&self.process).map(|_| ()) + } + } } /// Treats association loss as owner death; cleanup waits for confirmed runner teardown. @@ -791,11 +812,15 @@ pub fn read_shared_buffer( /// fails. Success means process startup reached `Running`. pub trait ProcessLauncher: Send + Sync { /// Starts one process and waits for startup to commit or fail. + /// + /// The launcher transfers `completion` to the runner association and + /// consumes it only after deployment-specific installation and validation. fn launch( self: Arc, process: Arc, initial_thread_id: ThreadId, startup: ProcessStartupData, + completion: ProcessStartupCompletion, ) -> core::result::Result<(), BrokerError>; } @@ -879,6 +904,7 @@ fn start_child_process( payload, inherited_objects, }, + ProcessStartupCompletion::Association, ) .map_err(RequestFailure::from)?; Ok(ProcessIdentity { @@ -1613,7 +1639,8 @@ mod tests { ); let broker = TestBrokerCoreBuilder::new( PolicyEngine::with_unauthenticated_rights(ObjectRights::all()) - .with_socket_policy(SocketPolicy::guest_network()), + .with_socket_policy(SocketPolicy::guest_network()) + .with_process_duplication_enabled(true), ) .with_socket_provider(Arc::new(TestSocketProvider)) .with_random_provider(Arc::new(TestRandomProvider)) @@ -1637,6 +1664,7 @@ mod tests { test_channel_aborts_without_response_on_shared_memory_failure(&broker); setup_failure_transfers_process_to_the_deployment_owner(&broker); precreated_root_negotiates_without_startup_data(&broker); + duplication_startup_completion_publishes_after_activation(&broker); test_channel_rejects_incompatible_shared_buffer_layout(&broker); active_request_allocates_and_releases_thread_id(&broker); active_request_closes_object_reference(&broker); @@ -1713,8 +1741,34 @@ mod tests { .unwrap(); assert_eq!(association.process.id(), process.id()); - association.activate_process().unwrap(); + association + .complete_startup(ProcessStartupCompletion::Association) + .unwrap(); + association.finish(); + } + + fn duplication_startup_completion_publishes_after_activation(broker: &BrokerCore) { + let parent = broker + .create_process(CallerCredential::Unauthenticated, None) + .unwrap(); + parent.complete_start().unwrap(); + let mut transaction = parent.begin_duplication().unwrap(); + let (child, _) = transaction.create_child().unwrap(); + let association = BrokerHostAssociation::new( + Arc::clone(&child), + Arc::new(test_shared_buffers()), + test_readiness_sink(), + ); + + assert!(!child.is_running()); + association + .complete_startup(ProcessStartupCompletion::Duplication(transaction)) + .unwrap(); + assert!(child.is_running()); + association.finish(); + drop(child); + parent.retire(true); } fn association_shared_buffer_sequences_stage_file_data(broker: &BrokerCore) { @@ -2951,7 +3005,7 @@ mod tests { Err(termination) => return Ok(termination), }; association - .activate_process() + .complete_startup(ProcessStartupCompletion::Association) .expect("test broker process must activate once"); let result = (|| { loop { diff --git a/litebox_broker_host/src/test_support.rs b/litebox_broker_host/src/test_support.rs index e42f3ae75..aa00a031a 100644 --- a/litebox_broker_host/src/test_support.rs +++ b/litebox_broker_host/src/test_support.rs @@ -66,7 +66,7 @@ impl InProcessBrokerSetup { .take() .expect("the in-process local endpoint must negotiate before activation"); association - .activate_process() + .complete_startup(crate::ProcessStartupCompletion::Association) .expect("the in-process broker process must activate once"); InProcessBrokerChannel { association: Some(association), diff --git a/litebox_broker_userland/src/process_launcher.rs b/litebox_broker_userland/src/process_launcher.rs index bab5c445c..9b8e2084e 100644 --- a/litebox_broker_userland/src/process_launcher.rs +++ b/litebox_broker_userland/src/process_launcher.rs @@ -12,7 +12,7 @@ use std::time::Instant; use litebox_broker_core::{ BrokerCore, BrokerError, BrokerProcess, CallerCredential, ProcessLifecycleSink, }; -use litebox_broker_host::ProcessLauncher; +use litebox_broker_host::{ProcessLauncher, ProcessStartupCompletion}; use litebox_broker_protocol::ThreadId; use litebox_broker_protocol::process::ProcessStartupData; @@ -30,6 +30,7 @@ pub(crate) struct PendingRunnerAssociation { pub(super) process: Arc, initial_thread_id: ThreadId, data: Option, + completion: ProcessStartupCompletion, } impl PendingRunnerAssociation { @@ -37,18 +38,28 @@ impl PendingRunnerAssociation { process: Arc, initial_thread_id: ThreadId, data: Option, + completion: ProcessStartupCompletion, ) -> Self { Self { process, initial_thread_id, data, + completion, } } pub(crate) fn into_process_and_startup( self, - ) -> ((Arc, ThreadId), Option) { - ((self.process, self.initial_thread_id), self.data) + ) -> ( + (Arc, ThreadId), + Option, + ProcessStartupCompletion, + ) { + ( + (self.process, self.initial_thread_id), + self.data, + self.completion, + ) } } @@ -136,8 +147,12 @@ impl UserlandProcessLauncher { return Err(broker_io_error(error)); } }; - let association = - PendingRunnerAssociation::new(Arc::clone(&process), initial_thread_id, None); + let association = PendingRunnerAssociation::new( + Arc::clone(&process), + initial_thread_id, + None, + ProcessStartupCompletion::Association, + ); let (completion_sender, completion_receiver) = sync_channel(1); let startup = Arc::clone(&launcher).launch_runner(association, config, Some(completion_sender)); @@ -213,10 +228,11 @@ impl ProcessLauncher for UserlandProcessLauncher { process: Arc, initial_thread_id: ThreadId, data: ProcessStartupData, + completion: ProcessStartupCompletion, ) -> Result<(), BrokerError> { let config = self.started_runner_config.clone(); self.launch_runner( - PendingRunnerAssociation::new(process, initial_thread_id, Some(data)), + PendingRunnerAssociation::new(process, initial_thread_id, Some(data), completion), config, None, ) diff --git a/litebox_broker_userland/src/runtime.rs b/litebox_broker_userland/src/runtime.rs index e6c91ff9a..88008f024 100644 --- a/litebox_broker_userland/src/runtime.rs +++ b/litebox_broker_userland/src/runtime.rs @@ -27,8 +27,8 @@ use std::time::{Duration, Instant}; use litebox_broker_core::BrokerCore; use litebox_broker_host::{ - BrokerHostAssociation, BrokerHostError, ConnectionTermination, handle_process_operation, - setup_connection, + BrokerHostAssociation, BrokerHostError, ConnectionTermination, ProcessStartupCompletion, + handle_process_operation, setup_connection, }; use litebox_broker_protocol::error::ErrorCode; use litebox_broker_protocol::message::BrokerRequest; @@ -201,12 +201,12 @@ where NotificationChannel: HostNotificationChannel + Send, Shutdown: HostAssociationShutdown + Send + Sync + 'static, { - let (process, startup) = match startup { + let (process, startup, completion) = match startup { Some(startup) => { - let (process, data) = startup.into_process_and_startup(); - (Some(process), data) + let (process, data, completion) = startup.into_process_and_startup(); + (Some(process), data, completion) } - None => (None, None), + None => (None, None, ProcessStartupCompletion::Association), }; let finish_process = process.is_none(); let shared_memory = create_shared_memory()?; @@ -270,6 +270,7 @@ where shutdown, launcher, finish_process, + completion, )) } @@ -454,6 +455,7 @@ fn dispatch_requests>, finish_process: bool, + completion: ProcessStartupCompletion, ) -> AssociationOutcome where Memory: SharedMemory, @@ -464,10 +466,10 @@ where { let association = Arc::new(association); let failure_coordinator = Arc::new(HostAssociationFailureCoordinator::new(shutdown)); - if let Err(error) = association.activate_process() { + if let Err(error) = association.complete_startup(completion) { return AssociationOutcome { result: Err(IoError::other(format!( - "failed to activate broker process association: {error}" + "failed to complete broker process startup: {error}" ))), abnormal: true, }; @@ -941,6 +943,7 @@ mod tests { shutdown, None, true, + ProcessStartupCompletion::Association, ) .result, ) From 848281e2ff1bec9aa1b021e15f74b8a366ae13b5 Mon Sep 17 00:00:00 2001 From: Weidong Cui Date: Wed, 23 Sep 2026 17:54:08 -0700 Subject: [PATCH 2/8] Refactor duplication startup publication Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ee779b34-31e2-4e38-8068-21fe8fce7674 --- litebox_broker_core/src/lib.rs | 34 +- litebox_broker_core/src/process.rs | 362 ++++++------------ litebox_broker_host/src/lib.rs | 103 ++--- litebox_broker_host/src/test_support.rs | 2 +- .../src/process_launcher.rs | 27 +- litebox_broker_userland/src/runtime.rs | 4 +- 6 files changed, 218 insertions(+), 314 deletions(-) diff --git a/litebox_broker_core/src/lib.rs b/litebox_broker_core/src/lib.rs index 8c5519f62..f043c7e48 100644 --- a/litebox_broker_core/src/lib.rs +++ b/litebox_broker_core/src/lib.rs @@ -39,7 +39,7 @@ use alloc::sync::{Arc, Weak}; use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use hashbrown::HashMap; -use litebox_broker_protocol::{ObjectHandle, ProcessId}; +use litebox_broker_protocol::{ObjectHandle, ProcessId, ThreadId}; use spin::{Mutex, rwlock::RwLock}; pub use error::BrokerError; @@ -53,7 +53,7 @@ pub use process::{ AssociationCancellation, BrokerProcess, BrokerThread, CallerCredential, DuplicationTransaction, ObjectRights, ProcessLifecycleSink, ProcessShutdown, }; -use process::{ObjectReference, ProcessParent, ProcessRoot, ProcessStartKind}; +use process::{ObjectReference, ProcessParent, ProcessRoot}; use random::RandomProvider; use socket::{BrokerSocketPorts, SocketProvider}; use stdio::StdioProvider; @@ -348,11 +348,34 @@ impl BrokerCore { caller_credential, Some(ProcessParent::new(&parent)), Some(root), - ProcessStartKind::Association, ) })?; } - self.register_process(caller_credential, None, None, ProcessStartKind::Association) + self.register_process(caller_credential, None, None) + } + + /// Allocates one process and its initial thread. + /// + /// If initial-thread creation fails, the process is retired before the + /// error is returned. + /// + /// # Panics + /// + /// Panics if the shared ID allocator violates its range or uniqueness + /// invariants. + pub fn create_process_with_initial_thread( + &self, + caller_credential: CallerCredential, + parent_id: Option, + ) -> Result<(Arc, ThreadId)> { + let process = self.create_process(caller_credential, parent_id)?; + match process.create_thread() { + Ok(initial_thread_id) => Ok((process, initial_thread_id)), + Err(error) => { + process.retire(true); + Err(error) + } + } } pub(crate) fn register_process( @@ -360,7 +383,6 @@ impl BrokerCore { caller_credential: CallerCredential, parent: Option, root: Option>, - start_kind: ProcessStartKind, ) -> Result> { let mut processes = self.processes.write(); if processes.len() >= self.limits.max_processes { @@ -377,7 +399,6 @@ impl BrokerCore { id, root, parent, - start_kind, caller_credential, )) } else { @@ -388,7 +409,6 @@ impl BrokerCore { id, Arc::new(ProcessRoot::new(root_process.clone())), None, - start_kind, caller_credential, ) }) diff --git a/litebox_broker_core/src/process.rs b/litebox_broker_core/src/process.rs index d35bce625..337df4f12 100644 --- a/litebox_broker_core/src/process.rs +++ b/litebox_broker_core/src/process.rs @@ -148,6 +148,8 @@ pub struct BrokerProcess { /// Assigned process ID and internal authority. pub(crate) id: ProcessId, root: Arc, + /// Parent that created this record; unlike the wait parent, never changes. + creation_parent: Option>, state: Mutex, /// Broker-entry-authenticated caller credential for this process. pub(crate) caller_credential: CallerCredential, @@ -170,32 +172,13 @@ struct BrokerProcessState { owner_alive: bool, /// Whether one admitted duplication transaction owns the publication slot. duplication_active: bool, + /// Whether a starting child continues after its parent dies. + reparent_startup_on_parent_death: bool, retirement: ProcessRetirement, shutdown_request: ProcessShutdownRequest, shutdown: Option, } -/// Origin of a process entering the starting state. -/// -/// Design section 5.2 calls [`Self::Duplication`] `Fork` and -/// [`Self::ImageReplacement`] `Exec`; broker core uses host-neutral names. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[cfg_attr( - not(test), - expect( - dead_code, - reason = "later process lifecycle PRs construct these kinds" - ) -)] -pub(crate) enum ProcessStartKind { - /// Existing runner association startup. - Association, - /// Child creation by duplicating an existing process image. - Duplication, - /// Child creation by replacing a virtual child's process image. - ImageReplacement, -} - /// Origin of a request concerning one process record. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr( @@ -214,9 +197,9 @@ pub(crate) enum ProcessRequestOrigin { /// Broker-owned state for one admitted process-duplication attempt. /// -/// At most one transaction may be active for a process. Initial admission does -/// not allocate a child; [`Self::create_child`] allocates and binds the exact -/// staged child later committed by [`Self::publish`]. +/// At most one transaction may be active for a process. The common process +/// creation path allocates the staged child, then [`Self::retain_child`] +/// transfers rollback and publication ownership to this transaction. pub struct DuplicationTransaction { owner: Arc, /// Child retained from allocation through publication for rollback. @@ -225,66 +208,36 @@ pub struct DuplicationTransaction { } impl DuplicationTransaction { - /// Allocates and binds the staged child owned by this transaction. + /// Retains the staged child owned by this transaction. /// - /// The child's wait parent reflects any owner death that completed before - /// allocation. Once returned, dropping the transaction rolls the child - /// back if publication has not committed it. - pub fn create_child(&mut self) -> Result<(Arc, ThreadId)> { - if !self.active || self.child.is_some() { + /// The child must have been created from this transaction's owner through + /// the common process creation path. Once retained, dropping the + /// transaction rolls the child back if publication has not committed it. + pub fn retain_child(&mut self, child: Arc) -> Result<()> { + if !self.active + || self.child.is_some() + || Arc::ptr_eq(&self.owner, &child) + || !Arc::ptr_eq(&self.owner.core.processes, &child.core.processes) + || !child + .creation_parent + .as_ref() + .is_some_and(|parent| Weak::ptr_eq(parent, &Arc::downgrade(&self.owner))) + { return Err(BrokerError::Internal); } - let child = { - let owner_state = self.owner.state.lock(); - if owner_state.owner_alive { - let child = self.owner.core.register_process( - self.owner.caller_credential, - Some(ProcessParent::new(&self.owner)), - Some(Arc::clone(&self.owner.root)), - ProcessStartKind::Duplication, - )?; - drop(owner_state); - child - } else { - drop(owner_state); - let root = self - .owner - .root - .process() - .filter(|root| !Arc::ptr_eq(root, &self.owner)); - if let Some(root) = root { - let state = root.state.lock(); - let parent = (state.owner_alive - && matches!(state.retirement, ProcessRetirement::Active { .. })) - .then(|| ProcessParent::new(&root)); - let child = self.owner.core.register_process( - self.owner.caller_credential, - parent, - Some(Arc::clone(&self.owner.root)), - ProcessStartKind::Duplication, - )?; - drop(state); - child - } else { - self.owner.core.register_process( - self.owner.caller_credential, - None, - Some(Arc::clone(&self.owner.root)), - ProcessStartKind::Duplication, - )? - } - } - }; - let initial_thread_id = match child.create_thread() { - Ok(initial_thread_id) => initial_thread_id, - Err(error) => { - child.retire(true); - return Err(error); + { + let mut child_state = child.state.lock(); + if !child_state.owner_alive + || !matches!(child_state.record, ProcessRecordState::Starting) + || !matches!(child_state.retirement, ProcessRetirement::Active { .. }) + { + return Err(BrokerError::Internal); } - }; - self.child = Some(Arc::clone(&child)); - Ok((child, initial_thread_id)) + child_state.reparent_startup_on_parent_death = true; + } + self.child = Some(child); + Ok(()) } /// Publishes a staged child after successful installation and validation. @@ -312,10 +265,8 @@ impl DuplicationTransaction { } let mut child_state = child.state.lock(); let child_threads = child.threads.lock(); - let child_starting = matches!( - child_state.record, - ProcessRecordState::Starting(ProcessStartKind::Duplication) - ); + let child_starting = child_state.record == ProcessRecordState::Starting + && child_state.reparent_startup_on_parent_death; let initial_thread_id = (child_threads.len() == 1) .then(|| child_threads.keys().next().copied()) .flatten(); @@ -344,6 +295,7 @@ impl DuplicationTransaction { initial_thread_id, }; child_state.record.transition(ProcessRecordState::Running)?; + child_state.reparent_startup_on_parent_death = false; owner_state.duplication_active = false; self.active = false; drop(child_threads); @@ -381,12 +333,14 @@ impl DuplicationTransaction { if let Some(child) = &self.child { let mut child_state = child.state.lock(); match child_state.record { - ProcessRecordState::Starting(ProcessStartKind::Duplication) - if matches!(child_state.retirement, ProcessRetirement::Active { .. }) => + ProcessRecordState::Starting + if child_state.reparent_startup_on_parent_death + && matches!(child_state.retirement, ProcessRetirement::Active { .. }) => { child_state .record .transition(ProcessRecordState::Failed(error))?; + child_state.reparent_startup_on_parent_death = false; if child_state.shutdown_request == ProcessShutdownRequest::None { child_state.shutdown_request = ProcessShutdownRequest::Expected; } @@ -398,13 +352,8 @@ impl DuplicationTransaction { | ProcessRecordState::Collected | ProcessRecordState::Reaped | ProcessRecordState::Expired - | ProcessRecordState::Starting(ProcessStartKind::Duplication) => {} - ProcessRecordState::Reserved - | ProcessRecordState::Starting( - ProcessStartKind::Association | ProcessStartKind::ImageReplacement, - ) - | ProcessRecordState::VirtualRunning - | ProcessRecordState::Running => { + | ProcessRecordState::Starting => {} + ProcessRecordState::Reserved | ProcessRecordState::Running => { state.duplication_active = false; self.active = false; return Err(BrokerError::Internal); @@ -448,9 +397,7 @@ pub(crate) enum ProcessRecordState { /// Identity reserved, with no host process selected yet. Reserved, /// Host process setup is in progress. - Starting(ProcessStartKind), - /// A virtual child is executing in its owner's address space. - VirtualRunning, + Starting, /// The process is published and may issue guest-originated operations. Running, /// Startup failed and host cleanup is still pending. @@ -481,30 +428,16 @@ impl ProcessRecordState { fn admits_request_origin(self, origin: ProcessRequestOrigin) -> bool { match origin { ProcessRequestOrigin::Lifecycle => true, - ProcessRequestOrigin::Guest => matches!(self, Self::VirtualRunning | Self::Running), + ProcessRequestOrigin::Guest => matches!(self, Self::Running), } } fn transition(&mut self, next: Self) -> Result<()> { let allowed = matches!( (*self, next), - ( - Self::Reserved, - Self::VirtualRunning - | Self::Starting( - ProcessStartKind::Duplication | ProcessStartKind::ImageReplacement - ) - | Self::Expired, - ) | ( - Self::Starting(ProcessStartKind::Association | ProcessStartKind::Duplication), - Self::Running | Self::Failed(_), - ) | ( - Self::Starting(ProcessStartKind::ImageReplacement), - Self::Running | Self::VirtualRunning | Self::Zombie, - ) | ( - Self::VirtualRunning, - Self::Starting(ProcessStartKind::ImageReplacement) | Self::Zombie, - ) | (Self::Running, Self::Zombie) + (Self::Reserved, Self::Starting | Self::Expired) + | (Self::Starting, Self::Running | Self::Failed(_)) + | (Self::Running, Self::Zombie) | (Self::Zombie, Self::Reaped) | (Self::Failed(_), Self::Collected) ); @@ -558,18 +491,20 @@ impl BrokerProcess { id: ProcessId, root: Arc, parent: Option, - start_kind: ProcessStartKind, caller_credential: CallerCredential, ) -> Self { + let creation_parent = parent.as_ref().map(|parent| Weak::clone(&parent.process)); Self { core, id, root, + creation_parent, state: Mutex::new(BrokerProcessState { - record: ProcessRecordState::Starting(start_kind), + record: ProcessRecordState::Starting, parent, owner_alive: true, duplication_active: false, + reparent_startup_on_parent_death: false, retirement: ProcessRetirement::Active { abnormal: false }, shutdown_request: ProcessShutdownRequest::None, shutdown: None, @@ -642,8 +577,8 @@ impl BrokerProcess { /// Returns the completed startup outcome, or `None` while startup is pending. pub fn startup_result(&self) -> Option> { match self.state.lock().record { - ProcessRecordState::Reserved | ProcessRecordState::Starting(_) => None, - ProcessRecordState::Running | ProcessRecordState::VirtualRunning => Some(Ok(())), + ProcessRecordState::Reserved | ProcessRecordState::Starting => None, + ProcessRecordState::Running => Some(Ok(())), ProcessRecordState::Failed(error) => Some(Err(error)), ProcessRecordState::Zombie | ProcessRecordState::Collected @@ -660,11 +595,10 @@ impl BrokerProcess { return Err(BrokerError::PeerClosed); } match state.record { - ProcessRecordState::Starting(ProcessStartKind::Association) => {} - ProcessRecordState::Starting( - ProcessStartKind::Duplication | ProcessStartKind::ImageReplacement, - ) - | ProcessRecordState::Running => return Err(BrokerError::Internal), + ProcessRecordState::Starting if !state.reparent_startup_on_parent_death => {} + ProcessRecordState::Starting | ProcessRecordState::Running => { + return Err(BrokerError::Internal); + } ProcessRecordState::Failed(error) => return Err(error), _ => return Err(BrokerError::PeerClosed), } @@ -696,12 +630,7 @@ impl BrokerProcess { let shutdown = { let mut state = self.state.lock(); match state.record { - ProcessRecordState::Starting( - ProcessStartKind::Association | ProcessStartKind::Duplication, - ) => {} - ProcessRecordState::Starting(ProcessStartKind::ImageReplacement) => { - return Err(BrokerError::Internal); - } + ProcessRecordState::Starting => {} ProcessRecordState::Running => return Ok(()), ProcessRecordState::Failed(error) => return Err(error), _ => return Err(BrokerError::PeerClosed), @@ -710,6 +639,7 @@ impl BrokerProcess { state.retirement.mark_abnormal(); } state.record.transition(ProcessRecordState::Failed(error))?; + state.reparent_startup_on_parent_death = false; if state.shutdown_request == ProcessShutdownRequest::None { state.shutdown_request = if expected_shutdown { ProcessShutdownRequest::Expected @@ -748,10 +678,10 @@ impl BrokerProcess { /// Applies owner-death handling to every direct child process. /// - /// Reserved children expire, association startup fails, duplication startup - /// continues after reparenting, virtual children become zombies, and live or - /// zombie children reparent to the tree root. Zombies are reaped immediately - /// when the root owner is gone. + /// Reserved children expire, ordinary startup fails, retained duplication + /// startup continues after reparenting, and live or zombie children reparent + /// to the tree root. Zombies are reaped immediately when the root owner is + /// gone. pub fn handle_owner_death(self: &Arc) { { let mut state = self.state.lock(); @@ -841,7 +771,8 @@ impl BrokerProcess { .expect("reserved child expiration must be a valid transition"); false } - ProcessRecordState::Starting(ProcessStartKind::Association) => { + ProcessRecordState::Starting if state.reparent_startup_on_parent_death => true, + ProcessRecordState::Starting => { state .record .transition(ProcessRecordState::Failed(BrokerError::PeerClosed)) @@ -852,27 +783,7 @@ impl BrokerProcess { shutdown.clone_from(&state.shutdown); false } - ProcessRecordState::Starting(ProcessStartKind::ImageReplacement) => { - state - .record - .transition(ProcessRecordState::Zombie) - .expect("image replacement rejection must create a zombie"); - if state.shutdown_request == ProcessShutdownRequest::None { - state.shutdown_request = ProcessShutdownRequest::Expected; - } - shutdown.clone_from(&state.shutdown); - true - } - ProcessRecordState::VirtualRunning => { - state - .record - .transition(ProcessRecordState::Zombie) - .expect("virtual child owner death must create a zombie"); - true - } - ProcessRecordState::Starting(ProcessStartKind::Duplication) - | ProcessRecordState::Running - | ProcessRecordState::Zombie => true, + ProcessRecordState::Running | ProcessRecordState::Zombie => true, ProcessRecordState::Failed(_) | ProcessRecordState::Collected | ProcessRecordState::Reaped @@ -1564,7 +1475,7 @@ mod tests { use super::{ BrokerProcess, ProcessLifecycleSink, ProcessRecordState, ProcessReferences, - ProcessRequestOrigin, ProcessStartKind, release_pending_reference, + ProcessRequestOrigin, release_pending_reference, }; use crate::test_platform::TestPlatform; use crate::test_support::{TestBrokerCoreBuilder, TestStdioProvider}; @@ -1616,8 +1527,12 @@ mod tests { Arc, ProcessIdentity, ) { + let (child, initial_thread_id) = parent + .core + .create_process_with_initial_thread(parent.caller_credential(), Some(parent.id())) + .unwrap(); let mut transaction = parent.begin_duplication().unwrap(); - let (child, initial_thread_id) = transaction.create_child().unwrap(); + transaction.retain_child(Arc::clone(&child)).unwrap(); let identity = ProcessIdentity { process_id: child.id(), initial_thread_id, @@ -1625,16 +1540,12 @@ mod tests { (transaction, child, identity) } - fn process_record_states() -> [ProcessRecordState; 11] { + fn process_record_states() -> [ProcessRecordState; 8] { use ProcessRecordState as State; - use ProcessStartKind as Start; [ State::Reserved, - State::Starting(Start::Association), - State::Starting(Start::Duplication), - State::Starting(Start::ImageReplacement), - State::VirtualRunning, + State::Starting, State::Running, State::Failed(BrokerError::PeerClosed), State::Zombie, @@ -1647,30 +1558,14 @@ mod tests { #[test] fn process_record_state_transition_matrix() { use ProcessRecordState as State; - use ProcessStartKind as Start; let failed = State::Failed(BrokerError::PeerClosed); let states = process_record_states(); let allowed = [ - (State::Reserved, State::VirtualRunning), - (State::Reserved, State::Starting(Start::Duplication)), - (State::Reserved, State::Starting(Start::ImageReplacement)), + (State::Reserved, State::Starting), (State::Reserved, State::Expired), - (State::Starting(Start::Association), State::Running), - (State::Starting(Start::Association), failed), - (State::Starting(Start::Duplication), State::Running), - (State::Starting(Start::Duplication), failed), - (State::Starting(Start::ImageReplacement), State::Running), - ( - State::Starting(Start::ImageReplacement), - State::VirtualRunning, - ), - (State::Starting(Start::ImageReplacement), State::Zombie), - ( - State::VirtualRunning, - State::Starting(Start::ImageReplacement), - ), - (State::VirtualRunning, State::Zombie), + (State::Starting, State::Running), + (State::Starting, failed), (State::Running, State::Zombie), (State::Zombie, State::Reaped), (failed, State::Collected), @@ -1699,7 +1594,7 @@ mod tests { assert!(state.admits_request_origin(Origin::Lifecycle), "{state:?}"); assert_eq!( state.admits_request_origin(Origin::Guest), - matches!(state, State::VirtualRunning | State::Running), + matches!(state, State::Running), "{state:?}" ); } @@ -1808,10 +1703,13 @@ mod tests { assert_eq!(transaction.publish(&owner), Err(BrokerError::Internal)); assert!(owner.begin_duplication().is_ok()); + let (child, _) = broker + .create_process_with_initial_thread(owner.caller_credential(), Some(owner.id())) + .unwrap(); let mut transaction = owner.begin_duplication().unwrap(); - let (child, _) = transaction.create_child().unwrap(); + transaction.retain_child(Arc::clone(&child)).unwrap(); assert!(matches!( - transaction.create_child(), + transaction.retain_child(Arc::clone(&child)), Err(BrokerError::Internal) )); drop(transaction); @@ -1847,6 +1745,40 @@ mod tests { ); } + #[test] + fn duplication_transaction_rejects_a_child_created_by_another_owner() { + let broker = TestBrokerCoreBuilder::new( + PolicyEngine::with_unauthenticated_rights(ObjectRights::all()) + .with_process_duplication_enabled(true), + ) + .build() + .unwrap(); + let owner = broker + .create_process(CallerCredential::Unauthenticated, None) + .unwrap(); + owner.complete_start().unwrap(); + let other_owner = broker + .create_process(CallerCredential::Unauthenticated, None) + .unwrap(); + other_owner.complete_start().unwrap(); + let (child, _) = broker + .create_process_with_initial_thread(owner.caller_credential(), Some(owner.id())) + .unwrap(); + + let mut wrong_transaction = other_owner.begin_duplication().unwrap(); + assert_eq!( + wrong_transaction.retain_child(Arc::clone(&child)), + Err(BrokerError::Internal) + ); + drop(wrong_transaction); + assert_eq!(child.startup_result(), None); + + let mut transaction = owner.begin_duplication().unwrap(); + transaction.retain_child(Arc::clone(&child)).unwrap(); + drop(transaction); + assert_eq!(child.startup_result(), Some(Err(BrokerError::PeerClosed))); + } + #[test] fn duplication_publication_survives_parent_teardown_and_refuses_child_failure() { let broker = TestBrokerCoreBuilder::new( @@ -1883,13 +1815,8 @@ mod tests { .create_process(CallerCredential::Unauthenticated, None) .unwrap(); dead_parent.complete_start().unwrap(); - let mut transaction = dead_parent.begin_duplication().unwrap(); + let (transaction, dead_child, identity) = staged_duplication(&dead_parent); dead_parent.handle_owner_death(); - let (dead_child, initial_thread_id) = transaction.create_child().unwrap(); - let identity = ProcessIdentity { - process_id: dead_child.id(), - initial_thread_id, - }; assert_eq!(transaction.publish(&dead_child), Ok(identity)); assert_eq!(dead_child.state.lock().record, ProcessRecordState::Running); @@ -1911,29 +1838,6 @@ mod tests { assert!(live_parent.begin_duplication().is_ok()); } - #[test] - fn generic_startup_failure_rejects_image_replacement() { - let broker = TestBrokerCoreBuilder::new(PolicyEngine::with_unauthenticated_rights( - ObjectRights::all(), - )) - .build() - .unwrap(); - let process = broker - .create_process(CallerCredential::Unauthenticated, None) - .unwrap(); - process.state.lock().record = - ProcessRecordState::Starting(ProcessStartKind::ImageReplacement); - - assert_eq!( - process.fail_start(BrokerError::PeerClosed, false, true), - Err(BrokerError::Internal) - ); - assert_eq!( - process.state.lock().record, - ProcessRecordState::Starting(ProcessStartKind::ImageReplacement) - ); - } - #[test] fn process_and_thread_ids_share_one_numeric_namespace() { let broker = TestBrokerCoreBuilder::new(PolicyEngine::with_unauthenticated_rights( @@ -2012,10 +1916,6 @@ mod tests { .record .transition(ProcessRecordState::Zombie) .unwrap(); - let virtual_child = broker - .create_process(CallerCredential::Unauthenticated, Some(parent.id())) - .unwrap(); - virtual_child.state.lock().record = ProcessRecordState::VirtualRunning; let reserved = broker .create_process(CallerCredential::Unauthenticated, Some(parent.id())) .unwrap(); @@ -2028,11 +1928,6 @@ mod tests { assert_eq!(running.state.lock().record, ProcessRecordState::Running); assert_eq!(parent_id(&zombie), Some(root.id())); assert_eq!(zombie.state.lock().record, ProcessRecordState::Zombie); - assert_eq!(parent_id(&virtual_child), Some(root.id())); - assert_eq!( - virtual_child.state.lock().record, - ProcessRecordState::Zombie - ); assert_eq!(reserved.state.lock().record, ProcessRecordState::Expired); assert!(matches!( broker.create_process(CallerCredential::Unauthenticated, Some(parent.id())), @@ -2066,35 +1961,12 @@ mod tests { .record .transition(ProcessRecordState::Zombie) .unwrap(); - let virtual_child = broker - .create_process(CallerCredential::Unauthenticated, Some(root.id())) - .unwrap(); - virtual_child.state.lock().record = ProcessRecordState::VirtualRunning; - let replacing = broker - .create_process(CallerCredential::Unauthenticated, Some(root.id())) - .unwrap(); - replacing.state.lock().record = - ProcessRecordState::Starting(ProcessStartKind::ImageReplacement); - let shutdowns = Arc::new(AtomicUsize::new(0)); - let shutdown_count = Arc::clone(&shutdowns); - replacing.install_shutdown(Arc::new(move || { - shutdown_count.fetch_add(1, Ordering::Relaxed); - })); - root.handle_owner_death(); assert_eq!(parent_id(&running), None); assert_eq!(running.state.lock().record, ProcessRecordState::Running); assert_eq!(parent_id(&zombie), None); assert_eq!(zombie.state.lock().record, ProcessRecordState::Reaped); - assert_eq!(parent_id(&virtual_child), None); - assert_eq!( - virtual_child.state.lock().record, - ProcessRecordState::Reaped - ); - assert_eq!(parent_id(&replacing), None); - assert_eq!(replacing.state.lock().record, ProcessRecordState::Reaped); - assert_eq!(shutdowns.load(Ordering::Relaxed), 1); } #[test] diff --git a/litebox_broker_host/src/lib.rs b/litebox_broker_host/src/lib.rs index 694b50954..5ed001015 100644 --- a/litebox_broker_host/src/lib.rs +++ b/litebox_broker_host/src/lib.rs @@ -100,10 +100,10 @@ struct AssociationState { /// Broker-core action that commits one validated runner association. pub enum ProcessStartupCompletion { - /// Completes ordinary association startup. - Association, + /// Completes ordinary process startup. + CompleteStart, /// Publishes the exact staged child owned by a duplication transaction. - Duplication(DuplicationTransaction), + PublishDuplication(DuplicationTransaction), } impl BrokerHostAssociation { @@ -132,13 +132,18 @@ impl BrokerHostAssociation { completion: ProcessStartupCompletion, ) -> litebox_broker_core::Result<()> { match completion { - ProcessStartupCompletion::Association => self.process.complete_start(), - ProcessStartupCompletion::Duplication(transaction) => { + ProcessStartupCompletion::CompleteStart => self.process.complete_start(), + ProcessStartupCompletion::PublishDuplication(transaction) => { transaction.publish(&self.process).map(|_| ()) } } } + /// Commits ordinary process startup after installation and validation. + pub fn activate_process(&self) -> litebox_broker_core::Result<()> { + self.complete_startup(ProcessStartupCompletion::CompleteStart) + } + /// Treats association loss as owner death; cleanup waits for confirmed runner teardown. pub fn association_ending(&self) { self.process.handle_owner_death(); @@ -353,27 +358,13 @@ where .map_err(BrokerHostError::Channel)?; return Ok(Err(ConnectionTermination::Rejected(error))); } - None => match core.create_process(caller_credential, None) { - Ok(process) => match process.create_thread() { - Ok(initial_thread_id) => (process, initial_thread_id), - Err( - error @ (litebox_broker_core::BrokerError::ResourceExhausted - | litebox_broker_core::BrokerError::OutOfMemory), - ) => { - process.retire(true); - let error = ErrorCode::from(error); - setup_channel - .send_handshake_response(&BrokerHandshakeResponse::Error(error)) - .map_err(BrokerHostError::Channel)?; - return Ok(Err(ConnectionTermination::Rejected(error))); - } - Err(error) => { - process.retire(true); - return Err(BrokerHostError::from(error)); - } - }, - Err(litebox_broker_core::BrokerError::ResourceExhausted) => { - let error = ErrorCode::ResourceExhausted; + None => match core.create_process_with_initial_thread(caller_credential, None) { + Ok(process) => process, + Err( + error @ (litebox_broker_core::BrokerError::ResourceExhausted + | litebox_broker_core::BrokerError::OutOfMemory), + ) => { + let error = ErrorCode::from(error); setup_channel .send_handshake_response(&BrokerHandshakeResponse::Error(error)) .map_err(BrokerHostError::Channel)?; @@ -812,16 +803,38 @@ pub fn read_shared_buffer( /// fails. Success means process startup reached `Running`. pub trait ProcessLauncher: Send + Sync { /// Starts one process and waits for startup to commit or fail. - /// - /// The launcher transfers `completion` to the runner association and - /// consumes it only after deployment-specific installation and validation. fn launch( self: Arc, process: Arc, initial_thread_id: ThreadId, startup: ProcessStartupData, - completion: ProcessStartupCompletion, ) -> core::result::Result<(), BrokerError>; + + /// Starts one process with a non-default startup completion action. + /// + /// Launchers that support duplication publication transfer `completion` + /// to the runner association and consume it only after deployment-specific + /// installation and validation. + fn launch_with_completion( + self: Arc, + process: Arc, + initial_thread_id: ThreadId, + startup: ProcessStartupData, + completion: ProcessStartupCompletion, + ) -> core::result::Result<(), BrokerError> { + match completion { + ProcessStartupCompletion::CompleteStart => { + self.launch(process, initial_thread_id, startup) + } + ProcessStartupCompletion::PublishDuplication(transaction) => { + let error = BrokerError::UnsupportedOperation; + let _ = process.fail_start(error, false, true); + drop(transaction); + process.retire(true); + Err(error) + } + } + } } /// Handles a process operation using the configured platform launcher. @@ -868,8 +881,8 @@ fn start_child_process( if !parent.is_running() { return Err(RequestFailure::Abort(ErrorCode::ProtocolState)); } - let process = broker - .create_process(parent.caller_credential(), Some(parent.id())) + let (process, initial_thread_id) = broker + .create_process_with_initial_thread(parent.caller_credential(), Some(parent.id())) .map_err(RequestFailure::from)?; let inherited_objects = match parent .duplicate_object_references_to(requested_inherited_objects.as_slice(), &process) @@ -880,13 +893,6 @@ fn start_child_process( return Err(RequestFailure::from(error)); } }; - let initial_thread_id = match process.create_thread() { - Ok(initial_thread_id) => initial_thread_id, - Err(error) => { - process.retire(true); - return Err(RequestFailure::from(error)); - } - }; let inherited_objects = InheritedProcessObjects::new(&inherited_objects) .expect("child handle count must match the bounded inheritance request"); let process_id = process.id(); @@ -904,7 +910,6 @@ fn start_child_process( payload, inherited_objects, }, - ProcessStartupCompletion::Association, ) .map_err(RequestFailure::from)?; Ok(ProcessIdentity { @@ -1716,10 +1721,9 @@ mod tests { } fn precreated_root_negotiates_without_startup_data(broker: &BrokerCore) { - let process = broker - .create_process(CallerCredential::Unauthenticated, None) + let (process, initial_thread_id) = broker + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) .unwrap(); - let initial_thread_id = process.create_thread().unwrap(); let mut channel = FakeHostControlChannel::new( std::vec::Vec::from([Ok(HostReceive::Message(BrokerHandshakeRequest { protocol_version: BROKER_PROTOCOL_VERSION, @@ -1741,9 +1745,7 @@ mod tests { .unwrap(); assert_eq!(association.process.id(), process.id()); - association - .complete_startup(ProcessStartupCompletion::Association) - .unwrap(); + association.activate_process().unwrap(); association.finish(); } @@ -1752,8 +1754,11 @@ mod tests { .create_process(CallerCredential::Unauthenticated, None) .unwrap(); parent.complete_start().unwrap(); + let (child, _) = broker + .create_process_with_initial_thread(parent.caller_credential(), Some(parent.id())) + .unwrap(); let mut transaction = parent.begin_duplication().unwrap(); - let (child, _) = transaction.create_child().unwrap(); + transaction.retain_child(Arc::clone(&child)).unwrap(); let association = BrokerHostAssociation::new( Arc::clone(&child), Arc::new(test_shared_buffers()), @@ -1762,7 +1767,7 @@ mod tests { assert!(!child.is_running()); association - .complete_startup(ProcessStartupCompletion::Duplication(transaction)) + .complete_startup(ProcessStartupCompletion::PublishDuplication(transaction)) .unwrap(); assert!(child.is_running()); @@ -3005,7 +3010,7 @@ mod tests { Err(termination) => return Ok(termination), }; association - .complete_startup(ProcessStartupCompletion::Association) + .activate_process() .expect("test broker process must activate once"); let result = (|| { loop { diff --git a/litebox_broker_host/src/test_support.rs b/litebox_broker_host/src/test_support.rs index aa00a031a..e42f3ae75 100644 --- a/litebox_broker_host/src/test_support.rs +++ b/litebox_broker_host/src/test_support.rs @@ -66,7 +66,7 @@ impl InProcessBrokerSetup { .take() .expect("the in-process local endpoint must negotiate before activation"); association - .complete_startup(crate::ProcessStartupCompletion::Association) + .activate_process() .expect("the in-process broker process must activate once"); InProcessBrokerChannel { association: Some(association), diff --git a/litebox_broker_userland/src/process_launcher.rs b/litebox_broker_userland/src/process_launcher.rs index 9b8e2084e..ddcfaee44 100644 --- a/litebox_broker_userland/src/process_launcher.rs +++ b/litebox_broker_userland/src/process_launcher.rs @@ -136,22 +136,15 @@ impl UserlandProcessLauncher { pub(crate) fn run_root(config: RunnerConfig, broker: &BrokerCore) -> IoResult { let launcher = Self::new(config.without_initial_arguments(), broker.clone()); - let process = launcher + let (process, initial_thread_id) = launcher .broker - .create_process(CallerCredential::HostGuaranteed, None) + .create_process_with_initial_thread(CallerCredential::HostGuaranteed, None) .map_err(broker_io_error)?; - let initial_thread_id = match process.create_thread() { - Ok(initial_thread_id) => initial_thread_id, - Err(error) => { - process.retire(true); - return Err(broker_io_error(error)); - } - }; let association = PendingRunnerAssociation::new( Arc::clone(&process), initial_thread_id, None, - ProcessStartupCompletion::Association, + ProcessStartupCompletion::CompleteStart, ); let (completion_sender, completion_receiver) = sync_channel(1); let startup = @@ -228,6 +221,20 @@ impl ProcessLauncher for UserlandProcessLauncher { process: Arc, initial_thread_id: ThreadId, data: ProcessStartupData, + ) -> Result<(), BrokerError> { + self.launch_with_completion( + process, + initial_thread_id, + data, + ProcessStartupCompletion::CompleteStart, + ) + } + + fn launch_with_completion( + self: Arc, + process: Arc, + initial_thread_id: ThreadId, + data: ProcessStartupData, completion: ProcessStartupCompletion, ) -> Result<(), BrokerError> { let config = self.started_runner_config.clone(); diff --git a/litebox_broker_userland/src/runtime.rs b/litebox_broker_userland/src/runtime.rs index 88008f024..b0dda9f3a 100644 --- a/litebox_broker_userland/src/runtime.rs +++ b/litebox_broker_userland/src/runtime.rs @@ -206,7 +206,7 @@ where let (process, data, completion) = startup.into_process_and_startup(); (Some(process), data, completion) } - None => (None, None, ProcessStartupCompletion::Association), + None => (None, None, ProcessStartupCompletion::CompleteStart), }; let finish_process = process.is_none(); let shared_memory = create_shared_memory()?; @@ -943,7 +943,7 @@ mod tests { shutdown, None, true, - ProcessStartupCompletion::Association, + ProcessStartupCompletion::CompleteStart, ) .result, ) From 9a75ce957e5c83395dedb28d1567171c738638de Mon Sep 17 00:00:00 2001 From: Weidong Cui Date: Wed, 23 Sep 2026 20:12:26 -0700 Subject: [PATCH 3/8] Restrict low-level process creation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ee779b34-31e2-4e38-8068-21fe8fce7674 --- litebox_broker_core/src/lib.rs | 89 +++++++++---------- litebox_broker_core/src/test_support.rs | 24 ++++- litebox_broker_host/src/lib.rs | 24 ++--- .../src/socket/tests/mod.rs | 4 +- .../src/socket/tests/tcp.rs | 88 +++++++++--------- .../src/socket/tests/udp.rs | 66 +++++++------- 6 files changed, 155 insertions(+), 140 deletions(-) diff --git a/litebox_broker_core/src/lib.rs b/litebox_broker_core/src/lib.rs index f043c7e48..c302ffe68 100644 --- a/litebox_broker_core/src/lib.rs +++ b/litebox_broker_core/src/lib.rs @@ -331,11 +331,48 @@ impl BrokerCore { /// /// Panics if the shared ID allocator violates its range or uniqueness /// invariants. - pub fn create_process( + pub(crate) fn create_process( &self, caller_credential: CallerCredential, parent_id: Option, ) -> Result> { + let allocate_process = |parent: Option, root: Option>| { + let mut processes = self.processes.write(); + if processes.len() >= self.limits.max_processes { + return Err(BrokerError::ResourceExhausted); + } + processes + .try_reserve(1) + .map_err(|_| BrokerError::OutOfMemory)?; + let raw_id = self.ids.lock().allocate()?; + let id = ProcessId(raw_id); + let process = if let Some(root) = root { + Arc::new(BrokerProcess::new( + self.clone(), + id, + root, + parent, + caller_credential, + )) + } else { + assert!(parent.is_none(), "a root process cannot have a parent"); + Arc::new_cyclic(|root_process| { + BrokerProcess::new( + self.clone(), + id, + Arc::new(ProcessRoot::new(root_process.clone())), + None, + caller_credential, + ) + }) + }; + assert!( + processes.insert(id, Arc::downgrade(&process)).is_none(), + "the ID allocator returned an occupied process ID" + ); + Ok(process) + }; + if let Some(parent_id) = parent_id { let parent = self .processes @@ -344,14 +381,10 @@ impl BrokerCore { .and_then(Weak::upgrade) .ok_or(BrokerError::UnknownObject)?; return parent.with_live_owner(|root| { - self.register_process( - caller_credential, - Some(ProcessParent::new(&parent)), - Some(root), - ) + allocate_process(Some(ProcessParent::new(&parent)), Some(root)) })?; } - self.register_process(caller_credential, None, None) + allocate_process(None, None) } /// Allocates one process and its initial thread. @@ -377,46 +410,4 @@ impl BrokerCore { } } } - - pub(crate) fn register_process( - &self, - caller_credential: CallerCredential, - parent: Option, - root: Option>, - ) -> Result> { - let mut processes = self.processes.write(); - if processes.len() >= self.limits.max_processes { - return Err(BrokerError::ResourceExhausted); - } - processes - .try_reserve(1) - .map_err(|_| BrokerError::OutOfMemory)?; - let raw_id = self.ids.lock().allocate()?; - let id = ProcessId(raw_id); - let process = if let Some(root) = root { - Arc::new(BrokerProcess::new( - self.clone(), - id, - root, - parent, - caller_credential, - )) - } else { - assert!(parent.is_none(), "a root process cannot have a parent"); - Arc::new_cyclic(|root_process| { - BrokerProcess::new( - self.clone(), - id, - Arc::new(ProcessRoot::new(root_process.clone())), - None, - caller_credential, - ) - }) - }; - assert!( - processes.insert(id, Arc::downgrade(&process)).is_none(), - "the ID allocator returned an occupied process ID" - ); - Ok(process) - } } diff --git a/litebox_broker_core/src/test_support.rs b/litebox_broker_core/src/test_support.rs index 9e7ee8a6a..de93ccea9 100644 --- a/litebox_broker_core/src/test_support.rs +++ b/litebox_broker_core/src/test_support.rs @@ -7,11 +7,13 @@ use alloc::collections::VecDeque; use alloc::sync::Arc; use alloc::vec::Vec; +use litebox_broker_protocol::ProcessId; use litebox_broker_protocol::stdio::{StdioOutputStream, StdioStream}; use spin::Mutex; use crate::{ - AssociationCancellation, BrokerCore, BrokerCoreLimits, PolicyEngine, Result, + AssociationCancellation, BrokerCore, BrokerCoreLimits, BrokerProcess, CallerCredential, + PolicyEngine, Result, fs::{FileService, UnsupportedFileService}, random::{RandomProvider, RandomProviderError}, socket::{SocketProvider, UnsupportedSocketProvider}, @@ -94,6 +96,26 @@ impl TestBrokerCoreBuilder { } } +/// Test-only access to low-level broker process construction. +pub trait BrokerCoreTestExt { + /// Creates a process without allocating its initial thread. + fn create_test_process( + &self, + caller_credential: CallerCredential, + parent_id: Option, + ) -> Result>; +} + +impl BrokerCoreTestExt for BrokerCore { + fn create_test_process( + &self, + caller_credential: CallerCredential, + parent_id: Option, + ) -> Result> { + self.create_process(caller_credential, parent_id) + } +} + struct FailingRandomProvider; impl RandomProvider for FailingRandomProvider { diff --git a/litebox_broker_host/src/lib.rs b/litebox_broker_host/src/lib.rs index 5ed001015..64ded4a1a 100644 --- a/litebox_broker_host/src/lib.rs +++ b/litebox_broker_host/src/lib.rs @@ -1320,7 +1320,9 @@ mod tests { AcceptedPlatformSocket, PlatformConnectError, PlatformDatagramReceive, PlatformSocket, PlatformSocketStatus, PlatformStreamReceive, SocketProvider, }; - use litebox_broker_core::test_support::{TestBrokerCoreBuilder, TestStdioProvider}; + use litebox_broker_core::test_support::{ + BrokerCoreTestExt, TestBrokerCoreBuilder, TestStdioProvider, + }; use litebox_broker_core::{ObjectRights, PolicyEngine, SocketPolicy}; use litebox_broker_protocol::event::{ AddEventRequest, ConsumeEventRequest, CreateEventRequest, EventConsumeMode, @@ -1751,7 +1753,7 @@ mod tests { fn duplication_startup_completion_publishes_after_activation(broker: &BrokerCore) { let parent = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); parent.complete_start().unwrap(); let (child, _) = broker @@ -1778,7 +1780,7 @@ mod tests { fn association_shared_buffer_sequences_stage_file_data(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let shared_buffers = test_shared_buffers(); shared_buffers @@ -1890,7 +1892,7 @@ mod tests { fn association_shared_buffer_sequence_stages_random_data(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let shared_buffers = test_shared_buffers(); shared_buffers @@ -1945,7 +1947,7 @@ mod tests { provider: &TestStdioProvider, ) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let shared_buffers = test_shared_buffers(); shared_buffers @@ -2158,7 +2160,7 @@ mod tests { assert!(!setup_called.get()); assert_eq!( broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap() .id(), root_process_id(5) @@ -2373,7 +2375,7 @@ mod tests { fn active_request_closes_object_reference(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let response = handle_test_request( &process, @@ -2405,7 +2407,7 @@ mod tests { fn active_request_allocates_and_releases_thread_id(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let response = handle_test_request(&process, BrokerOperation::CreateThread); let BrokerResult::ThreadCreated(thread_id) = response else { @@ -2424,7 +2426,7 @@ mod tests { fn association_shared_buffer_sequences_stage_pipe_data(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let memory = TestSharedMemory::new(SHARED_BUFFER_POOL_SIZE); let shared_buffers = SharedBufferPool::new(memory.clone(), SHARED_BUFFER_LAYOUT).unwrap(); @@ -2485,7 +2487,7 @@ mod tests { fn association_shared_buffer_sequences_stage_socket_data(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let shared_buffers = test_shared_buffers(); let created = handle_test_request_with_buffers( @@ -2907,7 +2909,7 @@ mod tests { ) -> BrokerHostAssociation { BrokerHostAssociation { process: broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(), shared_buffers, readiness_sink: test_readiness_sink(), diff --git a/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs b/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs index 4ce729a0c..5715ad76a 100644 --- a/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs +++ b/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs @@ -10,7 +10,7 @@ use std::time::{Duration, Instant}; use super::*; use litebox_broker_core::readiness::ReadinessSink; use litebox_broker_core::socket::{GUEST_IPV4_ADDRESS, HOST_GATEWAY_IPV4_ADDRESS}; -use litebox_broker_core::test_support::TestBrokerCoreBuilder; +use litebox_broker_core::test_support::{BrokerCoreTestExt, TestBrokerCoreBuilder}; use litebox_broker_core::{ BrokerCore, BrokerCoreLimits, BrokerProcess, CallerCredential, DestinationPortRange, DestinationRule, Ipv4Cidr, ObjectRights, PolicyEngine, SocketPolicy, @@ -378,7 +378,7 @@ fn directional_shutdown_survives_readiness_publication_failure() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); diff --git a/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs b/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs index 03c901ae6..e53e7171f 100644 --- a/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs +++ b/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs @@ -24,10 +24,10 @@ fn connected_guest_tcp_pair(port: u16) -> GuestTcpPair { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -154,7 +154,7 @@ fn reactor_drives_a_loopback_tcp_socket() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -483,7 +483,7 @@ fn external_tcp_deferred_abortive_close_resets_peer() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -528,7 +528,7 @@ fn external_tcp_gateway_uses_host_loopback_and_keeps_guest_identity() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -604,7 +604,7 @@ fn external_tcp_route_keeps_guest_private_identity() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -645,7 +645,7 @@ fn tcp_connect_to_zero_port_returns_an_ordinary_socket_outcome() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); @@ -683,7 +683,7 @@ fn tcp_receive_survives_readiness_publication_failure() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -745,7 +745,7 @@ fn tcp_status_publication_failure_preserves_consumed_error() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -819,7 +819,7 @@ fn external_tcp_readiness_failure_does_not_fail_shared_reactor() { .unwrap(); let process_a = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published_a, publications_a) = channel(); let (retired_a, _retirements_a) = channel(); @@ -846,7 +846,7 @@ fn external_tcp_readiness_failure_does_not_fail_shared_reactor() { // Process B gets its own readiness sink, mirroring production's // per-association sinks. let process_b = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published_b, publications_b) = channel(); let (retired_b, _retirements_b) = channel(); @@ -942,7 +942,7 @@ fn external_tcp_connect_completion_readiness_failure_does_not_fail_shared_reacto ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -1029,7 +1029,7 @@ fn exhausted_tcp_peek_cache_refreshes_before_terminal_eof() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -1112,10 +1112,10 @@ fn accepted_guest_tcp_close_with_unread_data_preserves_reset() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -1470,10 +1470,10 @@ fn guest_tcp_namespace_routes_across_processs_and_hides_private_backend() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let client_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -1612,10 +1612,10 @@ fn tcp_exact_bindings_coexist_and_wildcard_accepts_concrete_destinations() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -1764,10 +1764,10 @@ fn connector_and_process_teardown_clean_bounded_pending_state() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -1826,7 +1826,7 @@ fn connector_and_process_teardown_clean_bounded_pending_state() { assert_ne!(retirements.recv_timeout(TEST_TIMEOUT).unwrap(), listener); let final_connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let final_connector = create_socket(&final_connector_process, readiness); assert!(matches!( @@ -1870,10 +1870,10 @@ fn graceful_connector_close_preserves_late_accept_and_eof() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -1964,10 +1964,10 @@ fn guest_tcp_zero_backlog_accepts_one_unspecified_destination() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, _publications) = channel(); let (retired, retirements) = channel(); @@ -2052,10 +2052,10 @@ fn guest_tcp_backlog_relisten_and_fifo_are_bounded() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -2171,10 +2171,10 @@ fn guest_tcp_stream_preserves_options_peek_waitall_and_half_close() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -2631,10 +2631,10 @@ fn guest_tcp_connect_publication_failure_purges_committed_queue() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, _publications) = channel(); let (retired, retirements) = channel(); @@ -2686,10 +2686,10 @@ fn guest_tcp_accept_publication_failure_purges_registered_endpoint() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -2751,10 +2751,10 @@ fn queued_guest_accept_transfers_capacity_without_global_growth() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, _publications) = channel(); let (retired, retirements) = channel(); @@ -2777,7 +2777,7 @@ fn queued_guest_accept_transfers_capacity_without_global_growth() { ); assert_eq!(provider.reactor.queued_guest_connection_count(), 1); let capacity_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let _global_capacity = create_socket(&capacity_process, readiness.clone()); assert_eq!( @@ -2811,10 +2811,10 @@ fn queued_guest_accept_rejects_exhausted_listener_process_capacity() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, _publications) = channel(); let (retired, retirements) = channel(); @@ -2868,10 +2868,10 @@ fn abortive_connector_close_releases_descriptor_capacity() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -2949,10 +2949,10 @@ fn stop_listening_cleanup_survives_readiness_failure() { ) .unwrap(); let listener_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -3033,7 +3033,7 @@ fn reactor_drives_a_loopback_tcp_listener() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); diff --git a/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs b/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs index 3421e967a..19638e40a 100644 --- a/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs +++ b/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs @@ -48,7 +48,7 @@ fn udp_gateway_translates_sources_filters_spoofing_and_reuses_endpoint() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -133,7 +133,7 @@ fn connected_udp_gateway_preserves_guest_visible_mapping() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -188,7 +188,7 @@ fn unmatched_guest_udp_destinations_fail_closed() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); @@ -232,7 +232,7 @@ fn failed_initial_udp_readiness_does_not_retain_process_state() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); @@ -268,10 +268,10 @@ fn guest_udp_readiness_failure_rolls_back_enqueue() { ) .unwrap(); let receiver_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let sender_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); @@ -365,7 +365,7 @@ fn external_udp_readiness_failure_does_not_fail_shared_reactor() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -477,7 +477,7 @@ fn udp_status_publication_failure_still_rearms_native_endpoint() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -550,7 +550,7 @@ fn udp_status_republishes_when_another_error_remains_pending() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -602,10 +602,10 @@ fn guest_udp_queue_pressure_drops_new_datagrams_successfully() { ) .unwrap(); let receiver_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let sender_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); @@ -693,7 +693,7 @@ fn udp_external_peer_authorization_is_bounded_without_eviction() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -785,7 +785,7 @@ fn reactor_preserves_udp_datagram_semantics() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -1139,10 +1139,10 @@ fn guest_udp_namespace_routes_across_processes_and_filters_private_endpoints() { ) .unwrap(); let receiver_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let sender_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -1403,10 +1403,10 @@ fn udp_exact_bindings_coexist_and_wildcard_covers_guest_addresses() { ) .unwrap(); let receiver_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let sender_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -1591,7 +1591,7 @@ fn udp_native_endpoint_is_reused_and_retired() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, _publications) = channel(); let (retired, retirements) = channel(); @@ -1656,7 +1656,7 @@ fn udp_endpoint_staging_error_rolls_back_external_peer_reservation() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); @@ -1694,10 +1694,10 @@ fn stale_udp_datagrams_are_not_relabelled_after_guest_port_reuse() { ) .unwrap(); let receiver_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let source_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -1801,16 +1801,16 @@ fn udp_queued_datagrams_survive_source_process_teardown() { ) .unwrap(); let source_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let first_receiver_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let second_receiver_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let replacement_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); @@ -1946,10 +1946,10 @@ fn connected_guest_udp_enforces_barriers_peek_and_peer_generations() { ) .unwrap(); let first_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let second_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -2078,7 +2078,7 @@ fn connected_guest_udp_filters_other_wildcard_peer_aliases() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -2157,7 +2157,7 @@ fn wildcard_udp_reconnect_updates_guest_source_identity() { ) .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); @@ -2244,10 +2244,10 @@ fn externally_connected_udp_preserves_guest_routing_identity() { ) .unwrap(); let source_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let receiver_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); @@ -2354,10 +2354,10 @@ fn internally_connected_udp_drains_external_datagrams_without_delivering_them() ) .unwrap(); let receiver_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let sender_process = broker - .create_process(CallerCredential::Unauthenticated, None) + .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); From 7b13563668a69ed201d821377ab0b5ecf632ac72 Mon Sep 17 00:00:00 2001 From: Weidong Cui Date: Wed, 23 Sep 2026 20:26:17 -0700 Subject: [PATCH 4/8] Simplify duplication startup publication Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ee779b34-31e2-4e38-8068-21fe8fce7674 --- litebox_broker_core/src/lib.rs | 4 +- litebox_broker_core/src/process.rs | 460 +++++++---------------------- litebox_broker_host/src/lib.rs | 23 +- 3 files changed, 111 insertions(+), 376 deletions(-) diff --git a/litebox_broker_core/src/lib.rs b/litebox_broker_core/src/lib.rs index c302ffe68..b39d6c15c 100644 --- a/litebox_broker_core/src/lib.rs +++ b/litebox_broker_core/src/lib.rs @@ -50,8 +50,8 @@ pub use policy::{ PolicyProfile, SocketPolicy, SocketPolicyError, }; pub use process::{ - AssociationCancellation, BrokerProcess, BrokerThread, CallerCredential, DuplicationTransaction, - ObjectRights, ProcessLifecycleSink, ProcessShutdown, + AssociationCancellation, BrokerProcess, BrokerThread, CallerCredential, ObjectRights, + ProcessLifecycleSink, ProcessShutdown, }; use process::{ObjectReference, ProcessParent, ProcessRoot}; use random::RandomProvider; diff --git a/litebox_broker_core/src/process.rs b/litebox_broker_core/src/process.rs index 337df4f12..215ef8289 100644 --- a/litebox_broker_core/src/process.rs +++ b/litebox_broker_core/src/process.rs @@ -13,7 +13,6 @@ use crate::pipe::PipeObject; use crate::socket::SocketObject; use crate::{BrokerCore, BrokerError, Result}; use hashbrown::HashMap; -use litebox_broker_protocol::process::ProcessIdentity; use litebox_broker_protocol::readiness::ReadinessFlags; use litebox_broker_protocol::{ObjectHandle, ProcessId, ThreadId}; use spin::{Mutex, rwlock::RwLock}; @@ -170,8 +169,6 @@ struct BrokerProcessState { /// Immediate wait parent; `None` on a non-root means future zombies auto-reap. parent: Option, owner_alive: bool, - /// Whether one admitted duplication transaction owns the publication slot. - duplication_active: bool, /// Whether a starting child continues after its parent dies. reparent_startup_on_parent_death: bool, retirement: ProcessRetirement, @@ -195,195 +192,6 @@ pub(crate) enum ProcessRequestOrigin { Guest, } -/// Broker-owned state for one admitted process-duplication attempt. -/// -/// At most one transaction may be active for a process. The common process -/// creation path allocates the staged child, then [`Self::retain_child`] -/// transfers rollback and publication ownership to this transaction. -pub struct DuplicationTransaction { - owner: Arc, - /// Child retained from allocation through publication for rollback. - child: Option>, - active: bool, -} - -impl DuplicationTransaction { - /// Retains the staged child owned by this transaction. - /// - /// The child must have been created from this transaction's owner through - /// the common process creation path. Once retained, dropping the - /// transaction rolls the child back if publication has not committed it. - pub fn retain_child(&mut self, child: Arc) -> Result<()> { - if !self.active - || self.child.is_some() - || Arc::ptr_eq(&self.owner, &child) - || !Arc::ptr_eq(&self.owner.core.processes, &child.core.processes) - || !child - .creation_parent - .as_ref() - .is_some_and(|parent| Weak::ptr_eq(parent, &Arc::downgrade(&self.owner))) - { - return Err(BrokerError::Internal); - } - - { - let mut child_state = child.state.lock(); - if !child_state.owner_alive - || !matches!(child_state.record, ProcessRecordState::Starting) - || !matches!(child_state.retirement, ProcessRetirement::Active { .. }) - { - return Err(BrokerError::Internal); - } - child_state.reparent_startup_on_parent_death = true; - } - self.child = Some(child); - Ok(()) - } - - /// Publishes a staged child after successful installation and validation. - /// - /// Publication transitions the child to running and releases the owner's - /// transaction slot under the same lock. Parent cancellation or death does - /// not veto a child that completed setup successfully. - pub fn publish(mut self, process: &Arc) -> Result { - if !self.active { - return Err(BrokerError::Internal); - } - let child = self - .child - .as_ref() - .map(Arc::clone) - .ok_or(BrokerError::Internal)?; - if !Arc::ptr_eq(&child, process) { - return Err(BrokerError::Internal); - } - - let mut owner_state = self.owner.state.lock(); - if !owner_state.duplication_active { - self.active = false; - return Err(BrokerError::Internal); - } - let mut child_state = child.state.lock(); - let child_threads = child.threads.lock(); - let child_starting = child_state.record == ProcessRecordState::Starting - && child_state.reparent_startup_on_parent_death; - let initial_thread_id = (child_threads.len() == 1) - .then(|| child_threads.keys().next().copied()) - .flatten(); - let child_failed = matches!( - child_state.record, - ProcessRecordState::Failed(_) - | ProcessRecordState::Zombie - | ProcessRecordState::Collected - | ProcessRecordState::Reaped - | ProcessRecordState::Expired - ) || !child_state.owner_alive - || !matches!(child_state.retirement, ProcessRetirement::Active { .. }) - || initial_thread_id.is_none(); - if !child_starting && !child_failed { - owner_state.duplication_active = false; - self.active = false; - return Err(BrokerError::Internal); - } - - if child_starting - && !child_failed - && let Some(initial_thread_id) = initial_thread_id - { - let identity = ProcessIdentity { - process_id: child.id(), - initial_thread_id, - }; - child_state.record.transition(ProcessRecordState::Running)?; - child_state.reparent_startup_on_parent_death = false; - owner_state.duplication_active = false; - self.active = false; - drop(child_threads); - drop(child_state); - drop(owner_state); - self.owner.core.process_lifecycle_sink.changed(); - return Ok(identity); - } - - drop(child_threads); - drop(child_state); - drop(owner_state); - self.abort_prepublication(BrokerError::PeerClosed)?; - Err(BrokerError::WouldBlock) - } - - /// Refuses this attempt before publication. - pub fn refuse(mut self) -> Result<()> { - self.abort_prepublication(BrokerError::PeerClosed)?; - Err(BrokerError::WouldBlock) - } - - fn abort_prepublication(&mut self, error: BrokerError) -> Result<()> { - if !self.active { - return Err(BrokerError::Internal); - } - - let mut state = self.owner.state.lock(); - if !state.duplication_active { - self.active = false; - return Err(BrokerError::Internal); - } - let mut shutdown = None; - let mut child_changed = false; - if let Some(child) = &self.child { - let mut child_state = child.state.lock(); - match child_state.record { - ProcessRecordState::Starting - if child_state.reparent_startup_on_parent_death - && matches!(child_state.retirement, ProcessRetirement::Active { .. }) => - { - child_state - .record - .transition(ProcessRecordState::Failed(error))?; - child_state.reparent_startup_on_parent_death = false; - if child_state.shutdown_request == ProcessShutdownRequest::None { - child_state.shutdown_request = ProcessShutdownRequest::Expected; - } - shutdown.clone_from(&child_state.shutdown); - child_changed = true; - } - ProcessRecordState::Failed(_) - | ProcessRecordState::Zombie - | ProcessRecordState::Collected - | ProcessRecordState::Reaped - | ProcessRecordState::Expired - | ProcessRecordState::Starting => {} - ProcessRecordState::Reserved | ProcessRecordState::Running => { - state.duplication_active = false; - self.active = false; - return Err(BrokerError::Internal); - } - } - } - state.duplication_active = false; - self.active = false; - drop(state); - if child_changed { - self.owner.core.process_lifecycle_sink.changed(); - } - if let Some(shutdown) = shutdown { - shutdown(); - } - Ok(()) - } -} - -impl Drop for DuplicationTransaction { - fn drop(&mut self) { - if self.active && self.abort_prepublication(BrokerError::PeerClosed).is_err() { - debug_assert!(false, "failed to abort an active duplication transaction"); - let mut state = self.owner.state.lock(); - state.duplication_active = false; - self.active = false; - } - } -} - /// Authoritative lifecycle state of one broker process record. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr( @@ -503,7 +311,6 @@ impl BrokerProcess { record: ProcessRecordState::Starting, parent, owner_alive: true, - duplication_active: false, reparent_startup_on_parent_death: false, retirement: ProcessRetirement::Active { abnormal: false }, shutdown_request: ProcessShutdownRequest::None, @@ -533,37 +340,46 @@ impl BrokerProcess { self.caller_credential } - /// Opens one process-duplication transaction for this running process. + /// Prepares a newly created child for duplication startup. /// - /// Duplication must be enabled by policy, and only one transaction may be - /// active for the process. Dropping the returned transaction releases that - /// active slot. - pub fn begin_duplication(self: &Arc) -> Result { + /// The child must have been created directly from this running process. + /// Holding the parent state lock while marking the child ensures parent + /// death either rejects ordinary startup or reparents prepared startup. + pub fn prepare_duplication_child(&self, child: &BrokerProcess) -> Result<()> { if !self.core.policy.process_duplication_enabled() { return Err(BrokerError::PolicyDenied); } if self.cancellation.is_cancelled() { return Err(BrokerError::PeerClosed); } + if core::ptr::eq(self, child) + || !Arc::ptr_eq(&self.core.processes, &child.core.processes) + || !child + .creation_parent + .as_ref() + .and_then(Weak::upgrade) + .is_some_and(|parent| core::ptr::eq(parent.as_ref(), self)) + { + return Err(BrokerError::Internal); + } - let mut state = self.state.lock(); + let state = self.state.lock(); if !state.owner_alive || !matches!(state.record, ProcessRecordState::Running) || !matches!(state.retirement, ProcessRetirement::Active { .. }) { return Err(BrokerError::PeerClosed); } - if state.duplication_active { - return Err(BrokerError::WouldBlock); + let mut child_state = child.state.lock(); + if !child_state.owner_alive + || !matches!(child_state.record, ProcessRecordState::Starting) + || child_state.reparent_startup_on_parent_death + || !matches!(child_state.retirement, ProcessRetirement::Active { .. }) + { + return Err(BrokerError::Internal); } - state.duplication_active = true; - drop(state); - - Ok(DuplicationTransaction { - owner: Arc::clone(self), - child: None, - active: true, - }) + child_state.reparent_startup_on_parent_death = true; + Ok(()) } /// Returns whether this process completed broker startup. @@ -608,6 +424,31 @@ impl BrokerProcess { Ok(()) } + /// Publishes a prepared duplication child after its association is active. + pub fn complete_duplication_start(&self) -> Result<()> { + { + let mut state = self.state.lock(); + if !state.owner_alive || !matches!(state.retirement, ProcessRetirement::Active { .. }) { + return Err(BrokerError::PeerClosed); + } + match state.record { + ProcessRecordState::Starting if state.reparent_startup_on_parent_death => {} + ProcessRecordState::Starting | ProcessRecordState::Running => { + return Err(BrokerError::Internal); + } + ProcessRecordState::Failed(error) => return Err(error), + _ => return Err(BrokerError::PeerClosed), + } + if self.threads.lock().len() != 1 { + return Err(BrokerError::Internal); + } + state.record.transition(ProcessRecordState::Running)?; + state.reparent_startup_on_parent_death = false; + } + self.core.process_lifecycle_sink.changed(); + Ok(()) + } + /// Installs the host runner termination action. pub fn install_shutdown(&self, shutdown: ProcessShutdown) { let shutdown = { @@ -1487,7 +1328,6 @@ mod tests { use litebox_broker_protocol::fs::{ FileAccessMode, FileError, FileMode, FileOpenFlags, FileSeekWhence, FileType, FileUser, }; - use litebox_broker_protocol::process::ProcessIdentity; use litebox_broker_protocol::readiness::ReadinessFlags; use litebox_broker_protocol::stdio::StdioOutputStream; use litebox_broker_protocol::{ObjectHandle, ProcessId}; @@ -1520,24 +1360,13 @@ mod tests { .map(|parent| parent.id()) } - fn staged_duplication( - parent: &Arc, - ) -> ( - super::DuplicationTransaction, - Arc, - ProcessIdentity, - ) { - let (child, initial_thread_id) = parent + fn prepared_duplication(parent: &Arc) -> Arc { + let (child, _) = parent .core .create_process_with_initial_thread(parent.caller_credential(), Some(parent.id())) .unwrap(); - let mut transaction = parent.begin_duplication().unwrap(); - transaction.retain_child(Arc::clone(&child)).unwrap(); - let identity = ProcessIdentity { - process_id: child.id(), - initial_thread_id, - }; - (transaction, child, identity) + parent.prepare_duplication_child(&child).unwrap(); + child } fn process_record_states() -> [ProcessRecordState; 8] { @@ -1600,39 +1429,6 @@ mod tests { } } - #[test] - fn duplication_refusal_does_not_allocate_a_child() { - let broker = TestBrokerCoreBuilder::new( - PolicyEngine::with_unauthenticated_rights(ObjectRights::all()) - .with_process_duplication_enabled(true), - ) - .build() - .unwrap(); - let parent = broker - .create_process(CallerCredential::Unauthenticated, None) - .unwrap(); - parent.complete_start().unwrap(); - let process_count = broker.processes.read().len(); - - let transaction = parent.begin_duplication().unwrap(); - assert_eq!(transaction.owner.id(), parent.id()); - assert!(matches!( - parent.begin_duplication(), - Err(BrokerError::WouldBlock) - )); - assert_eq!(transaction.refuse(), Err(BrokerError::WouldBlock)); - - let transaction = parent.begin_duplication().unwrap(); - drop(transaction); - assert!(parent.begin_duplication().is_ok()); - assert_eq!(broker.processes.read().len(), process_count); - - let next = broker - .create_process(CallerCredential::Unauthenticated, None) - .unwrap(); - assert_eq!(next.id().0, parent.id().0 + 1); - } - #[test] fn process_duplication_policy_is_enforced_at_admission() { let broker = TestBrokerCoreBuilder::new(PolicyEngine::with_unauthenticated_rights( @@ -1644,143 +1440,84 @@ mod tests { .create_process(CallerCredential::Unauthenticated, None) .unwrap(); parent.complete_start().unwrap(); + let child = broker + .create_process(parent.caller_credential(), Some(parent.id())) + .unwrap(); assert!(matches!( - parent.begin_duplication(), + parent.prepare_duplication_child(&child), Err(BrokerError::PolicyDenied) )); + child.complete_start().unwrap(); } #[test] - fn duplication_publication_releases_transaction_slot() { - let broker = TestBrokerCoreBuilder::new( - PolicyEngine::with_unauthenticated_rights(ObjectRights::all()) - .with_process_duplication_enabled(true), - ) - .build() - .unwrap(); - let parent = broker - .create_process(CallerCredential::Unauthenticated, None) - .unwrap(); - parent.complete_start().unwrap(); - let (transaction, child, identity) = staged_duplication(&parent); - - assert_eq!(child.complete_start(), Err(BrokerError::Internal)); - assert_eq!(transaction.publish(&child), Ok(identity)); - assert_eq!(child.state.lock().record, ProcessRecordState::Running); - assert!(parent.begin_duplication().is_ok()); - - let second_parent = broker - .create_process(CallerCredential::Unauthenticated, None) - .unwrap(); - second_parent.complete_start().unwrap(); - let (transaction, second_child, identity) = staged_duplication(&second_parent); - assert_eq!(transaction.publish(&second_child), Ok(identity)); - - second_parent.handle_owner_death(); - - assert_eq!( - second_child.state.lock().record, - ProcessRecordState::Running - ); - assert_eq!(parent_id(&second_child), None); - } - - #[test] - fn duplication_transaction_owns_staged_child() { + fn duplication_preparation_validates_the_created_child() { let broker = TestBrokerCoreBuilder::new( PolicyEngine::with_unauthenticated_rights(ObjectRights::all()) .with_process_duplication_enabled(true), ) .build() .unwrap(); - let owner = broker .create_process(CallerCredential::Unauthenticated, None) .unwrap(); owner.complete_start().unwrap(); - let transaction = owner.begin_duplication().unwrap(); - assert_eq!(transaction.publish(&owner), Err(BrokerError::Internal)); - assert!(owner.begin_duplication().is_ok()); - + let other_owner = broker + .create_process(CallerCredential::Unauthenticated, None) + .unwrap(); + other_owner.complete_start().unwrap(); let (child, _) = broker .create_process_with_initial_thread(owner.caller_credential(), Some(owner.id())) .unwrap(); - let mut transaction = owner.begin_duplication().unwrap(); - transaction.retain_child(Arc::clone(&child)).unwrap(); - assert!(matches!( - transaction.retain_child(Arc::clone(&child)), - Err(BrokerError::Internal) - )); - drop(transaction); + assert_eq!( - child.state.lock().record, - ProcessRecordState::Failed(BrokerError::PeerClosed) + other_owner.prepare_duplication_child(&child), + Err(BrokerError::Internal) ); - assert!(owner.begin_duplication().is_ok()); - - let first_parent = broker - .create_process(CallerCredential::Unauthenticated, None) - .unwrap(); - first_parent.complete_start().unwrap(); - let (first_transaction, first_child, _) = staged_duplication(&first_parent); - let second_parent = broker - .create_process(CallerCredential::Unauthenticated, None) - .unwrap(); - second_parent.complete_start().unwrap(); - let (second_transaction, second_child, second_identity) = - staged_duplication(&second_parent); - + assert_eq!(child.startup_result(), None); assert_eq!( - first_transaction.publish(&second_child), + child.complete_duplication_start(), Err(BrokerError::Internal) ); + owner.prepare_duplication_child(&child).unwrap(); assert_eq!( - first_child.state.lock().record, - ProcessRecordState::Failed(BrokerError::PeerClosed) + owner.prepare_duplication_child(&child), + Err(BrokerError::Internal) ); + assert_eq!(child.complete_start(), Err(BrokerError::Internal)); + child.complete_duplication_start().unwrap(); + assert!(child.is_running()); assert_eq!( - second_transaction.publish(&second_child), - Ok(second_identity) + owner.prepare_duplication_child(&owner), + Err(BrokerError::Internal) ); } #[test] - fn duplication_transaction_rejects_a_child_created_by_another_owner() { + fn duplication_children_publish_independently() { let broker = TestBrokerCoreBuilder::new( PolicyEngine::with_unauthenticated_rights(ObjectRights::all()) .with_process_duplication_enabled(true), ) .build() .unwrap(); - let owner = broker - .create_process(CallerCredential::Unauthenticated, None) - .unwrap(); - owner.complete_start().unwrap(); - let other_owner = broker + let parent = broker .create_process(CallerCredential::Unauthenticated, None) .unwrap(); - other_owner.complete_start().unwrap(); - let (child, _) = broker - .create_process_with_initial_thread(owner.caller_credential(), Some(owner.id())) - .unwrap(); + parent.complete_start().unwrap(); + let first_child = prepared_duplication(&parent); + let second_child = prepared_duplication(&parent); - let mut wrong_transaction = other_owner.begin_duplication().unwrap(); - assert_eq!( - wrong_transaction.retain_child(Arc::clone(&child)), - Err(BrokerError::Internal) - ); - drop(wrong_transaction); - assert_eq!(child.startup_result(), None); + first_child.complete_duplication_start().unwrap(); + second_child.complete_duplication_start().unwrap(); - let mut transaction = owner.begin_duplication().unwrap(); - transaction.retain_child(Arc::clone(&child)).unwrap(); - drop(transaction); - assert_eq!(child.startup_result(), Some(Err(BrokerError::PeerClosed))); + assert!(first_child.is_running()); + assert!(second_child.is_running()); } #[test] - fn duplication_publication_survives_parent_teardown_and_refuses_child_failure() { + fn duplication_publication_survives_parent_teardown_and_rejects_child_failure() { let broker = TestBrokerCoreBuilder::new( PolicyEngine::with_unauthenticated_rights(ObjectRights::all()) .with_process_duplication_enabled(true), @@ -1792,7 +1529,7 @@ mod tests { .create_process(CallerCredential::Unauthenticated, None) .unwrap(); cancelled_parent.complete_start().unwrap(); - let (transaction, cancelled_child, identity) = staged_duplication(&cancelled_parent); + let cancelled_child = prepared_duplication(&cancelled_parent); let shutdowns = Arc::new(AtomicUsize::new(0)); let shutdown_count = Arc::clone(&shutdowns); cancelled_child.install_shutdown(Arc::new(move || { @@ -1800,14 +1537,20 @@ mod tests { })); cancelled_parent.request_cancellation(); - assert_eq!(transaction.publish(&cancelled_child), Ok(identity)); + cancelled_child.complete_duplication_start().unwrap(); assert_eq!( cancelled_child.state.lock().record, ProcessRecordState::Running ); assert_eq!(shutdowns.load(Ordering::Relaxed), 0); + let unprepared_child = broker + .create_process( + cancelled_parent.caller_credential(), + Some(cancelled_parent.id()), + ) + .unwrap(); assert!(matches!( - cancelled_parent.begin_duplication(), + cancelled_parent.prepare_duplication_child(&unprepared_child), Err(BrokerError::PeerClosed) )); @@ -1815,10 +1558,10 @@ mod tests { .create_process(CallerCredential::Unauthenticated, None) .unwrap(); dead_parent.complete_start().unwrap(); - let (transaction, dead_child, identity) = staged_duplication(&dead_parent); + let dead_child = prepared_duplication(&dead_parent); dead_parent.handle_owner_death(); - assert_eq!(transaction.publish(&dead_child), Ok(identity)); + dead_child.complete_duplication_start().unwrap(); assert_eq!(dead_child.state.lock().record, ProcessRecordState::Running); assert_eq!(parent_id(&dead_child), None); @@ -1826,16 +1569,15 @@ mod tests { .create_process(CallerCredential::Unauthenticated, None) .unwrap(); live_parent.complete_start().unwrap(); - let (transaction, failed_child, _) = staged_duplication(&live_parent); + let failed_child = prepared_duplication(&live_parent); assert_eq!( failed_child.fail_start(BrokerError::PeerClosed, false, true), Err(BrokerError::PeerClosed) ); assert_eq!( - transaction.publish(&failed_child), - Err(BrokerError::WouldBlock) + failed_child.complete_duplication_start(), + Err(BrokerError::PeerClosed) ); - assert!(live_parent.begin_duplication().is_ok()); } #[test] diff --git a/litebox_broker_host/src/lib.rs b/litebox_broker_host/src/lib.rs index 64ded4a1a..53c991d77 100644 --- a/litebox_broker_host/src/lib.rs +++ b/litebox_broker_host/src/lib.rs @@ -24,9 +24,7 @@ extern crate std; use alloc::{sync::Arc, vec::Vec}; use litebox_broker_core::readiness::ReadinessSink; -use litebox_broker_core::{ - BrokerCore, BrokerError, BrokerProcess, CallerCredential, DuplicationTransaction, -}; +use litebox_broker_core::{BrokerCore, BrokerError, BrokerProcess, CallerCredential}; use litebox_broker_protocol::error::ErrorCode; use litebox_broker_protocol::event::{AddEventResponse, CreateEventResponse}; use litebox_broker_protocol::fs::{ @@ -102,8 +100,8 @@ struct AssociationState { pub enum ProcessStartupCompletion { /// Completes ordinary process startup. CompleteStart, - /// Publishes the exact staged child owned by a duplication transaction. - PublishDuplication(DuplicationTransaction), + /// Publishes the prepared duplication child associated with the runner. + PublishDuplication, } impl BrokerHostAssociation { @@ -124,17 +122,14 @@ impl BrokerHostAssociation { } /// Commits process startup after deployment-specific installation and validation. - /// - /// A duplication completion must remain paired with the exact process - /// association supplied by its transaction. pub fn complete_startup( &self, completion: ProcessStartupCompletion, ) -> litebox_broker_core::Result<()> { match completion { ProcessStartupCompletion::CompleteStart => self.process.complete_start(), - ProcessStartupCompletion::PublishDuplication(transaction) => { - transaction.publish(&self.process).map(|_| ()) + ProcessStartupCompletion::PublishDuplication => { + self.process.complete_duplication_start() } } } @@ -826,10 +821,9 @@ pub trait ProcessLauncher: Send + Sync { ProcessStartupCompletion::CompleteStart => { self.launch(process, initial_thread_id, startup) } - ProcessStartupCompletion::PublishDuplication(transaction) => { + ProcessStartupCompletion::PublishDuplication => { let error = BrokerError::UnsupportedOperation; let _ = process.fail_start(error, false, true); - drop(transaction); process.retire(true); Err(error) } @@ -1759,8 +1753,7 @@ mod tests { let (child, _) = broker .create_process_with_initial_thread(parent.caller_credential(), Some(parent.id())) .unwrap(); - let mut transaction = parent.begin_duplication().unwrap(); - transaction.retain_child(Arc::clone(&child)).unwrap(); + parent.prepare_duplication_child(&child).unwrap(); let association = BrokerHostAssociation::new( Arc::clone(&child), Arc::new(test_shared_buffers()), @@ -1769,7 +1762,7 @@ mod tests { assert!(!child.is_running()); association - .complete_startup(ProcessStartupCompletion::PublishDuplication(transaction)) + .complete_startup(ProcessStartupCompletion::PublishDuplication) .unwrap(); assert!(child.is_running()); From 841f8c83656009cb06c94e5f8e9de689db476716 Mon Sep 17 00:00:00 2001 From: Weidong Cui Date: Wed, 23 Sep 2026 20:55:34 -0700 Subject: [PATCH 5/8] Simplify broker process state Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ee779b34-31e2-4e38-8068-21fe8fce7674 --- litebox_broker_core/src/lib.rs | 11 +- litebox_broker_core/src/process.rs | 250 +++--------------- litebox_broker_host/src/lib.rs | 58 +--- .../src/process_launcher.rs | 42 +-- litebox_broker_userland/src/runtime.rs | 17 +- 5 files changed, 65 insertions(+), 313 deletions(-) diff --git a/litebox_broker_core/src/lib.rs b/litebox_broker_core/src/lib.rs index b39d6c15c..16d37b94e 100644 --- a/litebox_broker_core/src/lib.rs +++ b/litebox_broker_core/src/lib.rs @@ -50,10 +50,10 @@ pub use policy::{ PolicyProfile, SocketPolicy, SocketPolicyError, }; pub use process::{ - AssociationCancellation, BrokerProcess, BrokerThread, CallerCredential, ObjectRights, - ProcessLifecycleSink, ProcessShutdown, + AssociationCancellation, BrokerProcess, CallerCredential, ObjectRights, ProcessLifecycleSink, + ProcessShutdown, }; -use process::{ObjectReference, ProcessParent, ProcessRoot}; +use process::{ObjectReference, ProcessRoot}; use random::RandomProvider; use socket::{BrokerSocketPorts, SocketProvider}; use stdio::StdioProvider; @@ -336,7 +336,8 @@ impl BrokerCore { caller_credential: CallerCredential, parent_id: Option, ) -> Result> { - let allocate_process = |parent: Option, root: Option>| { + let allocate_process = |parent: Option>, + root: Option>| { let mut processes = self.processes.write(); if processes.len() >= self.limits.max_processes { return Err(BrokerError::ResourceExhausted); @@ -381,7 +382,7 @@ impl BrokerCore { .and_then(Weak::upgrade) .ok_or(BrokerError::UnknownObject)?; return parent.with_live_owner(|root| { - allocate_process(Some(ProcessParent::new(&parent)), Some(root)) + allocate_process(Some(Arc::downgrade(&parent)), Some(root)) })?; } allocate_process(None, None) diff --git a/litebox_broker_core/src/process.rs b/litebox_broker_core/src/process.rs index 215ef8289..7e6ab064b 100644 --- a/litebox_broker_core/src/process.rs +++ b/litebox_broker_core/src/process.rs @@ -12,7 +12,7 @@ use crate::fs::File; use crate::pipe::PipeObject; use crate::socket::SocketObject; use crate::{BrokerCore, BrokerError, Result}; -use hashbrown::HashMap; +use hashbrown::{HashMap, HashSet}; use litebox_broker_protocol::readiness::ReadinessFlags; use litebox_broker_protocol::{ObjectHandle, ProcessId, ThreadId}; use spin::{Mutex, rwlock::RwLock}; @@ -104,39 +104,6 @@ struct ProcessReferences { pending_handles: usize, } -pub(crate) struct ProcessParent { - process: Weak, -} - -impl ProcessParent { - pub(crate) fn new(process: &Arc) -> Self { - Self { - process: Arc::downgrade(process), - } - } -} - -/// Broker-owned state for one guest thread. -/// -/// Execution remains platform-local. This object owns the authoritative -/// broker identity and is the extension point for execution-control state when -/// a broker platform needs to manage thread execution. -pub struct BrokerThread { - id: ThreadId, -} - -impl BrokerThread { - const fn new(id: ThreadId) -> Self { - Self { id } - } - - /// Returns the assigned thread ID. - #[must_use] - pub const fn id(&self) -> ThreadId { - self.id - } -} - /// Broker-owned state for one authenticated guest process. /// /// User mode cannot choose the process ID. The broker entry layer authenticates @@ -147,15 +114,13 @@ pub struct BrokerProcess { /// Assigned process ID and internal authority. pub(crate) id: ProcessId, root: Arc, - /// Parent that created this record; unlike the wait parent, never changes. - creation_parent: Option>, state: Mutex, /// Broker-entry-authenticated caller credential for this process. pub(crate) caller_credential: CallerCredential, /// Handles of the live object references owned by this process. references: Mutex, /// Authoritative broker threads owned by this process. - threads: Mutex>, + threads: Mutex>, /// Pipe capacity charged to this process by live pipe objects. pub(crate) reserved_pipe_capacity: Arc, /// Socket quota held by pending, live, and closing in-flight resources. @@ -167,7 +132,7 @@ pub struct BrokerProcess { struct BrokerProcessState { record: ProcessRecordState, /// Immediate wait parent; `None` on a non-root means future zombies auto-reap. - parent: Option, + parent: Option>, owner_alive: bool, /// Whether a starting child continues after its parent dies. reparent_startup_on_parent_death: bool, @@ -176,34 +141,9 @@ struct BrokerProcessState { shutdown: Option, } -/// Origin of a request concerning one process record. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[cfg_attr( - not(test), - expect( - dead_code, - reason = "later request dispatch PRs consume the origin classification" - ) -)] -pub(crate) enum ProcessRequestOrigin { - /// Transport or host notification that must be handled in every state. - Lifecycle, - /// Operation initiated by guest execution. - Guest, -} - /// Authoritative lifecycle state of one broker process record. #[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[cfg_attr( - not(test), - expect( - dead_code, - reason = "later process lifecycle PRs construct these states" - ) -)] pub(crate) enum ProcessRecordState { - /// Identity reserved, with no host process selected yet. - Reserved, /// Host process setup is in progress. Starting, /// The process is published and may issue guest-originated operations. @@ -212,42 +152,17 @@ pub(crate) enum ProcessRecordState { Failed(BrokerError), /// The process exited and has a waitable status. Zombie, - /// A failed host process has been confirmed dead. - Collected, /// A zombie's waitable status was consumed. Reaped, - /// An unused reservation expired. - Expired, } impl ProcessRecordState { - /// Returns whether requests from this origin can be considered in this state. - /// - /// Guest operations still require operation-specific authorization. - /// Startup negotiation is lifecycle traffic, so guest operations begin - /// only after the process reaches a running state. - #[cfg_attr( - not(test), - expect( - dead_code, - reason = "later request dispatch PRs apply the operation-specific checks" - ) - )] - fn admits_request_origin(self, origin: ProcessRequestOrigin) -> bool { - match origin { - ProcessRequestOrigin::Lifecycle => true, - ProcessRequestOrigin::Guest => matches!(self, Self::Running), - } - } - fn transition(&mut self, next: Self) -> Result<()> { let allowed = matches!( (*self, next), - (Self::Reserved, Self::Starting | Self::Expired) - | (Self::Starting, Self::Running | Self::Failed(_)) + (Self::Starting, Self::Running | Self::Failed(_)) | (Self::Running, Self::Zombie) | (Self::Zombie, Self::Reaped) - | (Self::Failed(_), Self::Collected) ); if !allowed { return Err(BrokerError::Internal); @@ -298,15 +213,13 @@ impl BrokerProcess { core: BrokerCore, id: ProcessId, root: Arc, - parent: Option, + parent: Option>, caller_credential: CallerCredential, ) -> Self { - let creation_parent = parent.as_ref().map(|parent| Weak::clone(&parent.process)); Self { core, id, root, - creation_parent, state: Mutex::new(BrokerProcessState { record: ProcessRecordState::Starting, parent, @@ -321,7 +234,7 @@ impl BrokerProcess { handles: Vec::new(), pending_handles: 0, }), - threads: Mutex::new(HashMap::new()), + threads: Mutex::new(HashSet::new()), reserved_pipe_capacity: Arc::new(AtomicUsize::new(0)), reserved_sockets: Arc::new(AtomicUsize::new(0)), cancellation: AssociationCancellation::default(), @@ -352,14 +265,7 @@ impl BrokerProcess { if self.cancellation.is_cancelled() { return Err(BrokerError::PeerClosed); } - if core::ptr::eq(self, child) - || !Arc::ptr_eq(&self.core.processes, &child.core.processes) - || !child - .creation_parent - .as_ref() - .and_then(Weak::upgrade) - .is_some_and(|parent| core::ptr::eq(parent.as_ref(), self)) - { + if core::ptr::eq(self, child) || !Arc::ptr_eq(&self.core.processes, &child.core.processes) { return Err(BrokerError::Internal); } @@ -373,6 +279,11 @@ impl BrokerProcess { let mut child_state = child.state.lock(); if !child_state.owner_alive || !matches!(child_state.record, ProcessRecordState::Starting) + || !child_state + .parent + .as_ref() + .and_then(Weak::upgrade) + .is_some_and(|parent| core::ptr::eq(parent.as_ref(), self)) || child_state.reparent_startup_on_parent_death || !matches!(child_state.retirement, ProcessRetirement::Active { .. }) { @@ -393,55 +304,28 @@ impl BrokerProcess { /// Returns the completed startup outcome, or `None` while startup is pending. pub fn startup_result(&self) -> Option> { match self.state.lock().record { - ProcessRecordState::Reserved | ProcessRecordState::Starting => None, + ProcessRecordState::Starting => None, ProcessRecordState::Running => Some(Ok(())), ProcessRecordState::Failed(error) => Some(Err(error)), - ProcessRecordState::Zombie - | ProcessRecordState::Collected - | ProcessRecordState::Reaped - | ProcessRecordState::Expired => Some(Err(BrokerError::PeerClosed)), + ProcessRecordState::Zombie | ProcessRecordState::Reaped => { + Some(Err(BrokerError::PeerClosed)) + } } } /// Completes startup after the process association becomes active. pub fn complete_start(&self) -> Result<()> { - { - let mut state = self.state.lock(); - if !matches!(state.retirement, ProcessRetirement::Active { .. }) { - return Err(BrokerError::PeerClosed); - } - match state.record { - ProcessRecordState::Starting if !state.reparent_startup_on_parent_death => {} - ProcessRecordState::Starting | ProcessRecordState::Running => { - return Err(BrokerError::Internal); - } - ProcessRecordState::Failed(error) => return Err(error), - _ => return Err(BrokerError::PeerClosed), - } - state.record.transition(ProcessRecordState::Running)?; - } - self.core.process_lifecycle_sink.changed(); - Ok(()) - } - - /// Publishes a prepared duplication child after its association is active. - pub fn complete_duplication_start(&self) -> Result<()> { { let mut state = self.state.lock(); if !state.owner_alive || !matches!(state.retirement, ProcessRetirement::Active { .. }) { return Err(BrokerError::PeerClosed); } match state.record { - ProcessRecordState::Starting if state.reparent_startup_on_parent_death => {} - ProcessRecordState::Starting | ProcessRecordState::Running => { - return Err(BrokerError::Internal); - } + ProcessRecordState::Starting => {} + ProcessRecordState::Running => return Err(BrokerError::Internal), ProcessRecordState::Failed(error) => return Err(error), _ => return Err(BrokerError::PeerClosed), } - if self.threads.lock().len() != 1 { - return Err(BrokerError::Internal); - } state.record.transition(ProcessRecordState::Running)?; state.reparent_startup_on_parent_death = false; } @@ -503,11 +387,6 @@ impl BrokerProcess { self.state.lock().shutdown_request == ProcessShutdownRequest::Expected } - /// Marks process retirement as abnormal. - pub fn mark_abnormal(&self) { - self.state.lock().retirement.mark_abnormal(); - } - /// Records final retirement disposition without releasing resources early. pub fn retire(&self, release_ids: bool) { { @@ -519,10 +398,9 @@ impl BrokerProcess { /// Applies owner-death handling to every direct child process. /// - /// Reserved children expire, ordinary startup fails, retained duplication - /// startup continues after reparenting, and live or zombie children reparent - /// to the tree root. Zombies are reaped immediately when the root owner is - /// gone. + /// Ordinary startup fails, prepared duplication startup continues after + /// reparenting, and live or zombie children reparent to the tree root. + /// Zombies are reaped immediately when the root owner is gone. pub fn handle_owner_death(self: &Arc) { { let mut state = self.state.lock(); @@ -598,20 +476,13 @@ impl BrokerProcess { if !state .parent .as_ref() - .is_some_and(|parent| Weak::ptr_eq(&parent.process, owner)) + .is_some_and(|parent| Weak::ptr_eq(parent, owner)) { return (false, None); } let mut shutdown = None; let reparent = match state.record { - ProcessRecordState::Reserved => { - state - .record - .transition(ProcessRecordState::Expired) - .expect("reserved child expiration must be a valid transition"); - false - } ProcessRecordState::Starting if state.reparent_startup_on_parent_death => true, ProcessRecordState::Starting => { state @@ -625,14 +496,11 @@ impl BrokerProcess { false } ProcessRecordState::Running | ProcessRecordState::Zombie => true, - ProcessRecordState::Failed(_) - | ProcessRecordState::Collected - | ProcessRecordState::Reaped - | ProcessRecordState::Expired => return (false, None), + ProcessRecordState::Failed(_) | ProcessRecordState::Reaped => return (false, None), }; if reparent { - state.parent = live_root.map(ProcessParent::new); + state.parent = live_root.map(Arc::downgrade); if live_root.is_none() && state.record == ProcessRecordState::Zombie { state .record @@ -706,10 +574,9 @@ impl BrokerProcess { return Err(error); } }; - let thread = BrokerThread::new(ThreadId(raw_id)); - let thread_id = thread.id(); + let thread_id = ThreadId(raw_id); assert!( - threads.insert(thread_id, thread).is_none(), + threads.insert(thread_id), "the ID allocator returned an occupied thread ID" ); Ok(thread_id) @@ -718,14 +585,14 @@ impl BrokerProcess { /// Records broker thread exit after its local task teardown completes. pub fn exit_thread(&self, thread_id: ThreadId) -> Result<()> { let mut threads = self.threads.lock(); - let thread = threads - .remove(&thread_id) - .ok_or(BrokerError::UnknownObject)?; + if !threads.remove(&thread_id) { + return Err(BrokerError::UnknownObject); + } drop(threads); self.core .active_thread_count .fetch_sub(1, Ordering::Relaxed); - self.core.ids.lock().release(thread.id().0); + self.core.ids.lock().release(thread_id.0); Ok(()) } @@ -1209,8 +1076,8 @@ impl BrokerProcess { .active_thread_count .fetch_sub(threads.len(), Ordering::Relaxed); let mut ids = self.core.ids.lock(); - for thread in threads.into_values() { - ids.release(thread.id().0); + for thread_id in threads { + ids.release(thread_id.0); } ids.release(self.id.0); } @@ -1316,7 +1183,7 @@ mod tests { use super::{ BrokerProcess, ProcessLifecycleSink, ProcessRecordState, ProcessReferences, - ProcessRequestOrigin, release_pending_reference, + release_pending_reference, }; use crate::test_platform::TestPlatform; use crate::test_support::{TestBrokerCoreBuilder, TestStdioProvider}; @@ -1356,7 +1223,7 @@ mod tests { .lock() .parent .as_ref() - .and_then(|parent| parent.process.upgrade()) + .and_then(alloc::sync::Weak::upgrade) .map(|parent| parent.id()) } @@ -1369,18 +1236,15 @@ mod tests { child } - fn process_record_states() -> [ProcessRecordState; 8] { + fn process_record_states() -> [ProcessRecordState; 5] { use ProcessRecordState as State; [ - State::Reserved, State::Starting, State::Running, State::Failed(BrokerError::PeerClosed), State::Zombie, - State::Collected, State::Reaped, - State::Expired, ] } @@ -1391,13 +1255,10 @@ mod tests { let failed = State::Failed(BrokerError::PeerClosed); let states = process_record_states(); let allowed = [ - (State::Reserved, State::Starting), - (State::Reserved, State::Expired), (State::Starting, State::Running), (State::Starting, failed), (State::Running, State::Zombie), (State::Zombie, State::Reaped), - (failed, State::Collected), ]; for initial in states { @@ -1414,21 +1275,6 @@ mod tests { } } - #[test] - fn request_origin_classification_preserves_lifecycle_notifications() { - use ProcessRecordState as State; - use ProcessRequestOrigin as Origin; - - for state in process_record_states() { - assert!(state.admits_request_origin(Origin::Lifecycle), "{state:?}"); - assert_eq!( - state.admits_request_origin(Origin::Guest), - matches!(state, State::Running), - "{state:?}" - ); - } - } - #[test] fn process_duplication_policy_is_enforced_at_admission() { let broker = TestBrokerCoreBuilder::new(PolicyEngine::with_unauthenticated_rights( @@ -1476,17 +1322,12 @@ mod tests { Err(BrokerError::Internal) ); assert_eq!(child.startup_result(), None); - assert_eq!( - child.complete_duplication_start(), - Err(BrokerError::Internal) - ); owner.prepare_duplication_child(&child).unwrap(); assert_eq!( owner.prepare_duplication_child(&child), Err(BrokerError::Internal) ); - assert_eq!(child.complete_start(), Err(BrokerError::Internal)); - child.complete_duplication_start().unwrap(); + child.complete_start().unwrap(); assert!(child.is_running()); assert_eq!( owner.prepare_duplication_child(&owner), @@ -1509,8 +1350,8 @@ mod tests { let first_child = prepared_duplication(&parent); let second_child = prepared_duplication(&parent); - first_child.complete_duplication_start().unwrap(); - second_child.complete_duplication_start().unwrap(); + first_child.complete_start().unwrap(); + second_child.complete_start().unwrap(); assert!(first_child.is_running()); assert!(second_child.is_running()); @@ -1537,7 +1378,7 @@ mod tests { })); cancelled_parent.request_cancellation(); - cancelled_child.complete_duplication_start().unwrap(); + cancelled_child.complete_start().unwrap(); assert_eq!( cancelled_child.state.lock().record, ProcessRecordState::Running @@ -1561,7 +1402,7 @@ mod tests { let dead_child = prepared_duplication(&dead_parent); dead_parent.handle_owner_death(); - dead_child.complete_duplication_start().unwrap(); + dead_child.complete_start().unwrap(); assert_eq!(dead_child.state.lock().record, ProcessRecordState::Running); assert_eq!(parent_id(&dead_child), None); @@ -1574,10 +1415,7 @@ mod tests { failed_child.fail_start(BrokerError::PeerClosed, false, true), Err(BrokerError::PeerClosed) ); - assert_eq!( - failed_child.complete_duplication_start(), - Err(BrokerError::PeerClosed) - ); + assert_eq!(failed_child.complete_start(), Err(BrokerError::PeerClosed)); } #[test] @@ -1658,11 +1496,6 @@ mod tests { .record .transition(ProcessRecordState::Zombie) .unwrap(); - let reserved = broker - .create_process(CallerCredential::Unauthenticated, Some(parent.id())) - .unwrap(); - reserved.state.lock().record = ProcessRecordState::Reserved; - parent.handle_owner_death(); assert!(!parent.state.lock().owner_alive); @@ -1670,7 +1503,6 @@ mod tests { assert_eq!(running.state.lock().record, ProcessRecordState::Running); assert_eq!(parent_id(&zombie), Some(root.id())); assert_eq!(zombie.state.lock().record, ProcessRecordState::Zombie); - assert_eq!(reserved.state.lock().record, ProcessRecordState::Expired); assert!(matches!( broker.create_process(CallerCredential::Unauthenticated, Some(parent.id())), Err(BrokerError::PeerClosed) diff --git a/litebox_broker_host/src/lib.rs b/litebox_broker_host/src/lib.rs index 53c991d77..d71a58cd8 100644 --- a/litebox_broker_host/src/lib.rs +++ b/litebox_broker_host/src/lib.rs @@ -96,14 +96,6 @@ struct AssociationState { shared_buffer_usage: SharedBufferUsage, } -/// Broker-core action that commits one validated runner association. -pub enum ProcessStartupCompletion { - /// Completes ordinary process startup. - CompleteStart, - /// Publishes the prepared duplication child associated with the runner. - PublishDuplication, -} - impl BrokerHostAssociation { fn new( process: Arc, @@ -121,22 +113,9 @@ impl BrokerHostAssociation { } } - /// Commits process startup after deployment-specific installation and validation. - pub fn complete_startup( - &self, - completion: ProcessStartupCompletion, - ) -> litebox_broker_core::Result<()> { - match completion { - ProcessStartupCompletion::CompleteStart => self.process.complete_start(), - ProcessStartupCompletion::PublishDuplication => { - self.process.complete_duplication_start() - } - } - } - - /// Commits ordinary process startup after installation and validation. + /// Commits process startup after installation and validation. pub fn activate_process(&self) -> litebox_broker_core::Result<()> { - self.complete_startup(ProcessStartupCompletion::CompleteStart) + self.process.complete_start() } /// Treats association loss as owner death; cleanup waits for confirmed runner teardown. @@ -804,31 +783,6 @@ pub trait ProcessLauncher: Send + Sync { initial_thread_id: ThreadId, startup: ProcessStartupData, ) -> core::result::Result<(), BrokerError>; - - /// Starts one process with a non-default startup completion action. - /// - /// Launchers that support duplication publication transfer `completion` - /// to the runner association and consume it only after deployment-specific - /// installation and validation. - fn launch_with_completion( - self: Arc, - process: Arc, - initial_thread_id: ThreadId, - startup: ProcessStartupData, - completion: ProcessStartupCompletion, - ) -> core::result::Result<(), BrokerError> { - match completion { - ProcessStartupCompletion::CompleteStart => { - self.launch(process, initial_thread_id, startup) - } - ProcessStartupCompletion::PublishDuplication => { - let error = BrokerError::UnsupportedOperation; - let _ = process.fail_start(error, false, true); - process.retire(true); - Err(error) - } - } - } } /// Handles a process operation using the configured platform launcher. @@ -1665,7 +1619,7 @@ mod tests { test_channel_aborts_without_response_on_shared_memory_failure(&broker); setup_failure_transfers_process_to_the_deployment_owner(&broker); precreated_root_negotiates_without_startup_data(&broker); - duplication_startup_completion_publishes_after_activation(&broker); + prepared_duplication_publishes_after_activation(&broker); test_channel_rejects_incompatible_shared_buffer_layout(&broker); active_request_allocates_and_releases_thread_id(&broker); active_request_closes_object_reference(&broker); @@ -1745,7 +1699,7 @@ mod tests { association.finish(); } - fn duplication_startup_completion_publishes_after_activation(broker: &BrokerCore) { + fn prepared_duplication_publishes_after_activation(broker: &BrokerCore) { let parent = broker .create_test_process(CallerCredential::Unauthenticated, None) .unwrap(); @@ -1761,9 +1715,7 @@ mod tests { ); assert!(!child.is_running()); - association - .complete_startup(ProcessStartupCompletion::PublishDuplication) - .unwrap(); + association.activate_process().unwrap(); assert!(child.is_running()); association.finish(); diff --git a/litebox_broker_userland/src/process_launcher.rs b/litebox_broker_userland/src/process_launcher.rs index ddcfaee44..195decca8 100644 --- a/litebox_broker_userland/src/process_launcher.rs +++ b/litebox_broker_userland/src/process_launcher.rs @@ -12,7 +12,7 @@ use std::time::Instant; use litebox_broker_core::{ BrokerCore, BrokerError, BrokerProcess, CallerCredential, ProcessLifecycleSink, }; -use litebox_broker_host::{ProcessLauncher, ProcessStartupCompletion}; +use litebox_broker_host::ProcessLauncher; use litebox_broker_protocol::ThreadId; use litebox_broker_protocol::process::ProcessStartupData; @@ -30,7 +30,6 @@ pub(crate) struct PendingRunnerAssociation { pub(super) process: Arc, initial_thread_id: ThreadId, data: Option, - completion: ProcessStartupCompletion, } impl PendingRunnerAssociation { @@ -38,28 +37,18 @@ impl PendingRunnerAssociation { process: Arc, initial_thread_id: ThreadId, data: Option, - completion: ProcessStartupCompletion, ) -> Self { Self { process, initial_thread_id, data, - completion, } } pub(crate) fn into_process_and_startup( self, - ) -> ( - (Arc, ThreadId), - Option, - ProcessStartupCompletion, - ) { - ( - (self.process, self.initial_thread_id), - self.data, - self.completion, - ) + ) -> ((Arc, ThreadId), Option) { + ((self.process, self.initial_thread_id), self.data) } } @@ -140,12 +129,8 @@ impl UserlandProcessLauncher { .broker .create_process_with_initial_thread(CallerCredential::HostGuaranteed, None) .map_err(broker_io_error)?; - let association = PendingRunnerAssociation::new( - Arc::clone(&process), - initial_thread_id, - None, - ProcessStartupCompletion::CompleteStart, - ); + let association = + PendingRunnerAssociation::new(Arc::clone(&process), initial_thread_id, None); let (completion_sender, completion_receiver) = sync_channel(1); let startup = Arc::clone(&launcher).launch_runner(association, config, Some(completion_sender)); @@ -221,25 +206,10 @@ impl ProcessLauncher for UserlandProcessLauncher { process: Arc, initial_thread_id: ThreadId, data: ProcessStartupData, - ) -> Result<(), BrokerError> { - self.launch_with_completion( - process, - initial_thread_id, - data, - ProcessStartupCompletion::CompleteStart, - ) - } - - fn launch_with_completion( - self: Arc, - process: Arc, - initial_thread_id: ThreadId, - data: ProcessStartupData, - completion: ProcessStartupCompletion, ) -> Result<(), BrokerError> { let config = self.started_runner_config.clone(); self.launch_runner( - PendingRunnerAssociation::new(process, initial_thread_id, Some(data), completion), + PendingRunnerAssociation::new(process, initial_thread_id, Some(data)), config, None, ) diff --git a/litebox_broker_userland/src/runtime.rs b/litebox_broker_userland/src/runtime.rs index b0dda9f3a..502ae0e27 100644 --- a/litebox_broker_userland/src/runtime.rs +++ b/litebox_broker_userland/src/runtime.rs @@ -27,8 +27,8 @@ use std::time::{Duration, Instant}; use litebox_broker_core::BrokerCore; use litebox_broker_host::{ - BrokerHostAssociation, BrokerHostError, ConnectionTermination, ProcessStartupCompletion, - handle_process_operation, setup_connection, + BrokerHostAssociation, BrokerHostError, ConnectionTermination, handle_process_operation, + setup_connection, }; use litebox_broker_protocol::error::ErrorCode; use litebox_broker_protocol::message::BrokerRequest; @@ -201,12 +201,12 @@ where NotificationChannel: HostNotificationChannel + Send, Shutdown: HostAssociationShutdown + Send + Sync + 'static, { - let (process, startup, completion) = match startup { + let (process, startup) = match startup { Some(startup) => { - let (process, data, completion) = startup.into_process_and_startup(); - (Some(process), data, completion) + let (process, data) = startup.into_process_and_startup(); + (Some(process), data) } - None => (None, None, ProcessStartupCompletion::CompleteStart), + None => (None, None), }; let finish_process = process.is_none(); let shared_memory = create_shared_memory()?; @@ -270,7 +270,6 @@ where shutdown, launcher, finish_process, - completion, )) } @@ -455,7 +454,6 @@ fn dispatch_requests>, finish_process: bool, - completion: ProcessStartupCompletion, ) -> AssociationOutcome where Memory: SharedMemory, @@ -466,7 +464,7 @@ where { let association = Arc::new(association); let failure_coordinator = Arc::new(HostAssociationFailureCoordinator::new(shutdown)); - if let Err(error) = association.complete_startup(completion) { + if let Err(error) = association.activate_process() { return AssociationOutcome { result: Err(IoError::other(format!( "failed to complete broker process startup: {error}" @@ -943,7 +941,6 @@ mod tests { shutdown, None, true, - ProcessStartupCompletion::CompleteStart, ) .result, ) From d4ce69449b288fc6b35570a6957da7d2a0c500f4 Mon Sep 17 00:00:00 2001 From: Weidong Cui Date: Wed, 23 Sep 2026 21:15:10 -0700 Subject: [PATCH 6/8] Simplify broker process status and test setup Rename the broker lifecycle dimension to ProcessStatus and remove the cross-crate threadless test process backdoor. External tests now use the production process-and-initial-thread creation path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ee779b34-31e2-4e38-8068-21fe8fce7674 --- litebox_broker_core/src/process.rs | 115 +++++---- litebox_broker_core/src/test_support.rs | 24 +- litebox_broker_host/src/lib.rs | 65 +++--- .../src/socket/tests/mod.rs | 7 +- .../src/socket/tests/tcp.rs | 220 +++++++++++------- .../src/socket/tests/udp.rs | 165 +++++++------ 6 files changed, 326 insertions(+), 270 deletions(-) diff --git a/litebox_broker_core/src/process.rs b/litebox_broker_core/src/process.rs index 7e6ab064b..910253068 100644 --- a/litebox_broker_core/src/process.rs +++ b/litebox_broker_core/src/process.rs @@ -130,7 +130,7 @@ pub struct BrokerProcess { } struct BrokerProcessState { - record: ProcessRecordState, + status: ProcessStatus, /// Immediate wait parent; `None` on a non-root means future zombies auto-reap. parent: Option>, owner_alive: bool, @@ -141,9 +141,9 @@ struct BrokerProcessState { shutdown: Option, } -/// Authoritative lifecycle state of one broker process record. +/// Broker-visible status of one process. #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) enum ProcessRecordState { +pub(crate) enum ProcessStatus { /// Host process setup is in progress. Starting, /// The process is published and may issue guest-originated operations. @@ -156,7 +156,7 @@ pub(crate) enum ProcessRecordState { Reaped, } -impl ProcessRecordState { +impl ProcessStatus { fn transition(&mut self, next: Self) -> Result<()> { let allowed = matches!( (*self, next), @@ -221,7 +221,7 @@ impl BrokerProcess { id, root, state: Mutex::new(BrokerProcessState { - record: ProcessRecordState::Starting, + status: ProcessStatus::Starting, parent, owner_alive: true, reparent_startup_on_parent_death: false, @@ -271,14 +271,14 @@ impl BrokerProcess { let state = self.state.lock(); if !state.owner_alive - || !matches!(state.record, ProcessRecordState::Running) + || !matches!(state.status, ProcessStatus::Running) || !matches!(state.retirement, ProcessRetirement::Active { .. }) { return Err(BrokerError::PeerClosed); } let mut child_state = child.state.lock(); if !child_state.owner_alive - || !matches!(child_state.record, ProcessRecordState::Starting) + || !matches!(child_state.status, ProcessStatus::Starting) || !child_state .parent .as_ref() @@ -297,19 +297,17 @@ impl BrokerProcess { #[must_use] pub fn is_running(&self) -> bool { let state = self.state.lock(); - matches!(state.record, ProcessRecordState::Running) + matches!(state.status, ProcessStatus::Running) && matches!(state.retirement, ProcessRetirement::Active { .. }) } /// Returns the completed startup outcome, or `None` while startup is pending. pub fn startup_result(&self) -> Option> { - match self.state.lock().record { - ProcessRecordState::Starting => None, - ProcessRecordState::Running => Some(Ok(())), - ProcessRecordState::Failed(error) => Some(Err(error)), - ProcessRecordState::Zombie | ProcessRecordState::Reaped => { - Some(Err(BrokerError::PeerClosed)) - } + match self.state.lock().status { + ProcessStatus::Starting => None, + ProcessStatus::Running => Some(Ok(())), + ProcessStatus::Failed(error) => Some(Err(error)), + ProcessStatus::Zombie | ProcessStatus::Reaped => Some(Err(BrokerError::PeerClosed)), } } @@ -320,13 +318,13 @@ impl BrokerProcess { if !state.owner_alive || !matches!(state.retirement, ProcessRetirement::Active { .. }) { return Err(BrokerError::PeerClosed); } - match state.record { - ProcessRecordState::Starting => {} - ProcessRecordState::Running => return Err(BrokerError::Internal), - ProcessRecordState::Failed(error) => return Err(error), + match state.status { + ProcessStatus::Starting => {} + ProcessStatus::Running => return Err(BrokerError::Internal), + ProcessStatus::Failed(error) => return Err(error), _ => return Err(BrokerError::PeerClosed), } - state.record.transition(ProcessRecordState::Running)?; + state.status.transition(ProcessStatus::Running)?; state.reparent_startup_on_parent_death = false; } self.core.process_lifecycle_sink.changed(); @@ -354,16 +352,16 @@ impl BrokerProcess { ) -> Result<()> { let shutdown = { let mut state = self.state.lock(); - match state.record { - ProcessRecordState::Starting => {} - ProcessRecordState::Running => return Ok(()), - ProcessRecordState::Failed(error) => return Err(error), + match state.status { + ProcessStatus::Starting => {} + ProcessStatus::Running => return Ok(()), + ProcessStatus::Failed(error) => return Err(error), _ => return Err(BrokerError::PeerClosed), } if abnormal { state.retirement.mark_abnormal(); } - state.record.transition(ProcessRecordState::Failed(error))?; + state.status.transition(ProcessStatus::Failed(error))?; state.reparent_startup_on_parent_death = false; if state.shutdown_request == ProcessShutdownRequest::None { state.shutdown_request = if expected_shutdown { @@ -482,12 +480,12 @@ impl BrokerProcess { } let mut shutdown = None; - let reparent = match state.record { - ProcessRecordState::Starting if state.reparent_startup_on_parent_death => true, - ProcessRecordState::Starting => { + let reparent = match state.status { + ProcessStatus::Starting if state.reparent_startup_on_parent_death => true, + ProcessStatus::Starting => { state - .record - .transition(ProcessRecordState::Failed(BrokerError::PeerClosed)) + .status + .transition(ProcessStatus::Failed(BrokerError::PeerClosed)) .expect("starting child rejection must be a valid transition"); if state.shutdown_request == ProcessShutdownRequest::None { state.shutdown_request = ProcessShutdownRequest::Expected; @@ -495,16 +493,16 @@ impl BrokerProcess { shutdown.clone_from(&state.shutdown); false } - ProcessRecordState::Running | ProcessRecordState::Zombie => true, - ProcessRecordState::Failed(_) | ProcessRecordState::Reaped => return (false, None), + ProcessStatus::Running | ProcessStatus::Zombie => true, + ProcessStatus::Failed(_) | ProcessStatus::Reaped => return (false, None), }; if reparent { state.parent = live_root.map(Arc::downgrade); - if live_root.is_none() && state.record == ProcessRecordState::Zombie { + if live_root.is_none() && state.status == ProcessStatus::Zombie { state - .record - .transition(ProcessRecordState::Reaped) + .status + .transition(ProcessStatus::Reaped) .expect("orphaned zombie reaping must be a valid transition"); } } @@ -1182,7 +1180,7 @@ mod tests { use core::sync::atomic::{AtomicUsize, Ordering}; use super::{ - BrokerProcess, ProcessLifecycleSink, ProcessRecordState, ProcessReferences, + BrokerProcess, ProcessLifecycleSink, ProcessReferences, ProcessStatus, release_pending_reference, }; use crate::test_platform::TestPlatform; @@ -1236,8 +1234,8 @@ mod tests { child } - fn process_record_states() -> [ProcessRecordState; 5] { - use ProcessRecordState as State; + fn process_statuses() -> [ProcessStatus; 5] { + use ProcessStatus as State; [ State::Starting, @@ -1249,11 +1247,11 @@ mod tests { } #[test] - fn process_record_state_transition_matrix() { - use ProcessRecordState as State; + fn process_status_transition_matrix() { + use ProcessStatus as State; let failed = State::Failed(BrokerError::PeerClosed); - let states = process_record_states(); + let states = process_statuses(); let allowed = [ (State::Starting, State::Running), (State::Starting, failed), @@ -1379,10 +1377,7 @@ mod tests { cancelled_parent.request_cancellation(); cancelled_child.complete_start().unwrap(); - assert_eq!( - cancelled_child.state.lock().record, - ProcessRecordState::Running - ); + assert_eq!(cancelled_child.state.lock().status, ProcessStatus::Running); assert_eq!(shutdowns.load(Ordering::Relaxed), 0); let unprepared_child = broker .create_process( @@ -1403,7 +1398,7 @@ mod tests { dead_parent.handle_owner_death(); dead_child.complete_start().unwrap(); - assert_eq!(dead_child.state.lock().record, ProcessRecordState::Running); + assert_eq!(dead_child.state.lock().status, ProcessStatus::Running); assert_eq!(parent_id(&dead_child), None); let live_parent = broker @@ -1493,16 +1488,16 @@ mod tests { zombie .state .lock() - .record - .transition(ProcessRecordState::Zombie) + .status + .transition(ProcessStatus::Zombie) .unwrap(); parent.handle_owner_death(); assert!(!parent.state.lock().owner_alive); assert_eq!(parent_id(&running), Some(root.id())); - assert_eq!(running.state.lock().record, ProcessRecordState::Running); + assert_eq!(running.state.lock().status, ProcessStatus::Running); assert_eq!(parent_id(&zombie), Some(root.id())); - assert_eq!(zombie.state.lock().record, ProcessRecordState::Zombie); + assert_eq!(zombie.state.lock().status, ProcessStatus::Zombie); assert!(matches!( broker.create_process(CallerCredential::Unauthenticated, Some(parent.id())), Err(BrokerError::PeerClosed) @@ -1532,15 +1527,15 @@ mod tests { zombie .state .lock() - .record - .transition(ProcessRecordState::Zombie) + .status + .transition(ProcessStatus::Zombie) .unwrap(); root.handle_owner_death(); assert_eq!(parent_id(&running), None); - assert_eq!(running.state.lock().record, ProcessRecordState::Running); + assert_eq!(running.state.lock().status, ProcessStatus::Running); assert_eq!(parent_id(&zombie), None); - assert_eq!(zombie.state.lock().record, ProcessRecordState::Reaped); + assert_eq!(zombie.state.lock().status, ProcessStatus::Reaped); } #[test] @@ -1565,8 +1560,8 @@ mod tests { child .state .lock() - .record - .transition(ProcessRecordState::Zombie) + .status + .transition(ProcessStatus::Zombie) .unwrap(); root.handle_owner_death(); @@ -1574,7 +1569,7 @@ mod tests { assert_eq!(parent_id(&parent), None); assert_eq!(parent_id(&child), None); - assert_eq!(child.state.lock().record, ProcessRecordState::Reaped); + assert_eq!(child.state.lock().status, ProcessStatus::Reaped); } #[test] @@ -1601,8 +1596,8 @@ mod tests { zombie .state .lock() - .record - .transition(ProcessRecordState::Zombie) + .status + .transition(ProcessStatus::Zombie) .unwrap(); root.handle_owner_death(); @@ -1625,7 +1620,7 @@ mod tests { ); assert_eq!(shutdowns.load(Ordering::Relaxed), 1); assert_eq!(parent_id(&zombie), None); - assert_eq!(zombie.state.lock().record, ProcessRecordState::Reaped); + assert_eq!(zombie.state.lock().status, ProcessStatus::Reaped); } #[test] diff --git a/litebox_broker_core/src/test_support.rs b/litebox_broker_core/src/test_support.rs index de93ccea9..9e7ee8a6a 100644 --- a/litebox_broker_core/src/test_support.rs +++ b/litebox_broker_core/src/test_support.rs @@ -7,13 +7,11 @@ use alloc::collections::VecDeque; use alloc::sync::Arc; use alloc::vec::Vec; -use litebox_broker_protocol::ProcessId; use litebox_broker_protocol::stdio::{StdioOutputStream, StdioStream}; use spin::Mutex; use crate::{ - AssociationCancellation, BrokerCore, BrokerCoreLimits, BrokerProcess, CallerCredential, - PolicyEngine, Result, + AssociationCancellation, BrokerCore, BrokerCoreLimits, PolicyEngine, Result, fs::{FileService, UnsupportedFileService}, random::{RandomProvider, RandomProviderError}, socket::{SocketProvider, UnsupportedSocketProvider}, @@ -96,26 +94,6 @@ impl TestBrokerCoreBuilder { } } -/// Test-only access to low-level broker process construction. -pub trait BrokerCoreTestExt { - /// Creates a process without allocating its initial thread. - fn create_test_process( - &self, - caller_credential: CallerCredential, - parent_id: Option, - ) -> Result>; -} - -impl BrokerCoreTestExt for BrokerCore { - fn create_test_process( - &self, - caller_credential: CallerCredential, - parent_id: Option, - ) -> Result> { - self.create_process(caller_credential, parent_id) - } -} - struct FailingRandomProvider; impl RandomProvider for FailingRandomProvider { diff --git a/litebox_broker_host/src/lib.rs b/litebox_broker_host/src/lib.rs index d71a58cd8..b9f288044 100644 --- a/litebox_broker_host/src/lib.rs +++ b/litebox_broker_host/src/lib.rs @@ -1268,9 +1268,7 @@ mod tests { AcceptedPlatformSocket, PlatformConnectError, PlatformDatagramReceive, PlatformSocket, PlatformSocketStatus, PlatformStreamReceive, SocketProvider, }; - use litebox_broker_core::test_support::{ - BrokerCoreTestExt, TestBrokerCoreBuilder, TestStdioProvider, - }; + use litebox_broker_core::test_support::{TestBrokerCoreBuilder, TestStdioProvider}; use litebox_broker_core::{ObjectRights, PolicyEngine, SocketPolicy}; use litebox_broker_protocol::event::{ AddEventRequest, ConsumeEventRequest, CreateEventRequest, EventConsumeMode, @@ -1701,8 +1699,9 @@ mod tests { fn prepared_duplication_publishes_after_activation(broker: &BrokerCore) { let parent = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; parent.complete_start().unwrap(); let (child, _) = broker .create_process_with_initial_thread(parent.caller_credential(), Some(parent.id())) @@ -1725,8 +1724,9 @@ mod tests { fn association_shared_buffer_sequences_stage_file_data(broker: &BrokerCore) { let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let shared_buffers = test_shared_buffers(); shared_buffers .write(SharedBufferSlotIndex(0), b"/file") @@ -1837,8 +1837,9 @@ mod tests { fn association_shared_buffer_sequence_stages_random_data(broker: &BrokerCore) { let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let shared_buffers = test_shared_buffers(); shared_buffers .write(SharedBufferSlotIndex(3), &[0xa5; 4]) @@ -1892,8 +1893,9 @@ mod tests { provider: &TestStdioProvider, ) { let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let shared_buffers = test_shared_buffers(); shared_buffers .write(SharedBufferSlotIndex(7), b"error") @@ -2103,13 +2105,11 @@ mod tests { }] ); assert!(!setup_called.get()); - assert_eq!( - broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap() - .id(), - root_process_id(5) - ); + let (process, initial_thread_id) = broker + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap(); + assert_eq!(process.id(), root_process_id(5)); + assert_eq!(initial_thread_id, ThreadId(6)); } fn test_channel_rejects_active_request_before_negotiation(broker: &BrokerCore) { @@ -2143,8 +2143,8 @@ mod tests { channel.handshake_responses, [BrokerHandshakeResponse::Negotiated { broker_protocol_version: BROKER_PROTOCOL_VERSION, - process_id: root_process_id(6), - initial_thread_id: ThreadId(7), + process_id: root_process_id(7), + initial_thread_id: ThreadId(8), startup: None, }] ); @@ -2320,8 +2320,9 @@ mod tests { fn active_request_closes_object_reference(broker: &BrokerCore) { let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let response = handle_test_request( &process, BrokerOperation::Event(EventRequest::Create(CreateEventRequest { @@ -2352,8 +2353,9 @@ mod tests { fn active_request_allocates_and_releases_thread_id(broker: &BrokerCore) { let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let response = handle_test_request(&process, BrokerOperation::CreateThread); let BrokerResult::ThreadCreated(thread_id) = response else { panic!("unexpected thread-ID allocation response: {response:?}"); @@ -2371,8 +2373,9 @@ mod tests { fn association_shared_buffer_sequences_stage_pipe_data(broker: &BrokerCore) { let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let memory = TestSharedMemory::new(SHARED_BUFFER_POOL_SIZE); let shared_buffers = SharedBufferPool::new(memory.clone(), SHARED_BUFFER_LAYOUT).unwrap(); shared_buffers @@ -2432,8 +2435,9 @@ mod tests { fn association_shared_buffer_sequences_stage_socket_data(broker: &BrokerCore) { let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let shared_buffers = test_shared_buffers(); let created = handle_test_request_with_buffers( &process, @@ -2854,8 +2858,9 @@ mod tests { ) -> BrokerHostAssociation { BrokerHostAssociation { process: broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(), + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0, shared_buffers, readiness_sink: test_readiness_sink(), state: SpinMutex::new(AssociationState { diff --git a/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs b/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs index 5715ad76a..947038f1d 100644 --- a/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs +++ b/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs @@ -10,7 +10,7 @@ use std::time::{Duration, Instant}; use super::*; use litebox_broker_core::readiness::ReadinessSink; use litebox_broker_core::socket::{GUEST_IPV4_ADDRESS, HOST_GATEWAY_IPV4_ADDRESS}; -use litebox_broker_core::test_support::{BrokerCoreTestExt, TestBrokerCoreBuilder}; +use litebox_broker_core::test_support::TestBrokerCoreBuilder; use litebox_broker_core::{ BrokerCore, BrokerCoreLimits, BrokerProcess, CallerCredential, DestinationPortRange, DestinationRule, Ipv4Cidr, ObjectRights, PolicyEngine, SocketPolicy, @@ -378,8 +378,9 @@ fn directional_shutdown_survives_readiness_publication_failure() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { diff --git a/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs b/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs index e53e7171f..d6f8e7972 100644 --- a/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs +++ b/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs @@ -24,11 +24,13 @@ fn connected_guest_tcp_pair(port: u16) -> GuestTcpPair { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -154,8 +156,9 @@ fn reactor_drives_a_loopback_tcp_socket() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -483,8 +486,9 @@ fn external_tcp_deferred_abortive_close_resets_peer() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -528,8 +532,9 @@ fn external_tcp_gateway_uses_host_loopback_and_keeps_guest_identity() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -604,8 +609,9 @@ fn external_tcp_route_keeps_guest_private_identity() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -645,8 +651,9 @@ fn tcp_connect_to_zero_port_returns_an_ordinary_socket_outcome() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, _publications) = channel(); let (retired, _retirements) = channel(); let socket = create_socket(&process, Arc::new(TestReadinessSink { published, retired })); @@ -683,8 +690,9 @@ fn tcp_receive_survives_readiness_publication_failure() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -745,8 +753,9 @@ fn tcp_status_publication_failure_preserves_consumed_error() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -819,8 +828,9 @@ fn external_tcp_readiness_failure_does_not_fail_shared_reactor() { .unwrap(); let process_a = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published_a, publications_a) = channel(); let (retired_a, _retirements_a) = channel(); let readiness_a = Arc::new(FailingReadinessSink { @@ -846,8 +856,9 @@ fn external_tcp_readiness_failure_does_not_fail_shared_reactor() { // Process B gets its own readiness sink, mirroring production's // per-association sinks. let process_b = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published_b, publications_b) = channel(); let (retired_b, _retirements_b) = channel(); let readiness_b = Arc::new(FailingReadinessSink { @@ -942,8 +953,9 @@ fn external_tcp_connect_completion_readiness_failure_does_not_fail_shared_reacto ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -1029,8 +1041,9 @@ fn exhausted_tcp_peek_cache_refreshes_before_terminal_eof() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1112,11 +1125,13 @@ fn accepted_guest_tcp_close_with_unread_data_preserves_reset() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1470,11 +1485,13 @@ fn guest_tcp_namespace_routes_across_processs_and_hides_private_backend() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let client_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1612,11 +1629,13 @@ fn tcp_exact_bindings_coexist_and_wildcard_accepts_concrete_destinations() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1764,11 +1783,13 @@ fn connector_and_process_teardown_clean_bounded_pending_state() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1826,8 +1847,9 @@ fn connector_and_process_teardown_clean_bounded_pending_state() { assert_ne!(retirements.recv_timeout(TEST_TIMEOUT).unwrap(), listener); let final_connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let final_connector = create_socket(&final_connector_process, readiness); assert!(matches!( litebox_broker_core::socket::connect( @@ -1870,11 +1892,13 @@ fn graceful_connector_close_preserves_late_accept_and_eof() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1964,11 +1988,13 @@ fn guest_tcp_zero_backlog_accepts_one_unspecified_destination() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, _publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2052,11 +2078,13 @@ fn guest_tcp_backlog_relisten_and_fifo_are_bounded() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2171,11 +2199,13 @@ fn guest_tcp_stream_preserves_options_peek_waitall_and_half_close() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2631,11 +2661,13 @@ fn guest_tcp_connect_publication_failure_purges_committed_queue() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, _publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -2686,11 +2718,13 @@ fn guest_tcp_accept_publication_failure_purges_registered_endpoint() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -2751,11 +2785,13 @@ fn queued_guest_accept_transfers_capacity_without_global_growth() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, _publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2777,8 +2813,9 @@ fn queued_guest_accept_transfers_capacity_without_global_growth() { ); assert_eq!(provider.reactor.queued_guest_connection_count(), 1); let capacity_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let _global_capacity = create_socket(&capacity_process, readiness.clone()); assert_eq!( litebox_broker_core::socket::create( @@ -2811,11 +2848,13 @@ fn queued_guest_accept_rejects_exhausted_listener_process_capacity() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, _publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2868,11 +2907,13 @@ fn abortive_connector_close_releases_descriptor_capacity() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2949,11 +2990,13 @@ fn stop_listening_cleanup_survives_readiness_failure() { ) .unwrap(); let listener_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let connector_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -3033,8 +3076,9 @@ fn reactor_drives_a_loopback_tcp_listener() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); diff --git a/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs b/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs index 19638e40a..e95779fc2 100644 --- a/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs +++ b/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs @@ -48,8 +48,9 @@ fn udp_gateway_translates_sources_filters_spoofing_and_reuses_endpoint() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let socket = create_udp_socket(&process, Arc::new(TestReadinessSink { published, retired })); @@ -133,8 +134,9 @@ fn connected_udp_gateway_preserves_guest_visible_mapping() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let socket = create_udp_socket(&process, Arc::new(TestReadinessSink { published, retired })); @@ -188,8 +190,9 @@ fn unmatched_guest_udp_destinations_fail_closed() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, _publications) = channel(); let (retired, _retirements) = channel(); let socket = create_udp_socket(&process, Arc::new(TestReadinessSink { published, retired })); @@ -232,8 +235,9 @@ fn failed_initial_udp_readiness_does_not_retain_process_state() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, _publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -268,11 +272,13 @@ fn guest_udp_readiness_failure_rolls_back_enqueue() { ) .unwrap(); let receiver_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let sender_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, _publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -365,8 +371,9 @@ fn external_udp_readiness_failure_does_not_fail_shared_reactor() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -477,8 +484,9 @@ fn udp_status_publication_failure_still_rearms_native_endpoint() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -550,8 +558,9 @@ fn udp_status_republishes_when_another_error_remains_pending() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -602,11 +611,13 @@ fn guest_udp_queue_pressure_drops_new_datagrams_successfully() { ) .unwrap(); let receiver_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let sender_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, _publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -693,8 +704,9 @@ fn udp_external_peer_authorization_is_bounded_without_eviction() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -785,8 +797,9 @@ fn reactor_preserves_udp_datagram_semantics() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1139,11 +1152,13 @@ fn guest_udp_namespace_routes_across_processes_and_filters_private_endpoints() { ) .unwrap(); let receiver_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let sender_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1403,11 +1418,13 @@ fn udp_exact_bindings_coexist_and_wildcard_covers_guest_addresses() { ) .unwrap(); let receiver_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let sender_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1591,8 +1608,9 @@ fn udp_native_endpoint_is_reused_and_retired() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, _publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1656,8 +1674,9 @@ fn udp_endpoint_staging_error_rolls_back_external_peer_reservation() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, _publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1694,11 +1713,13 @@ fn stale_udp_datagrams_are_not_relabelled_after_guest_port_reuse() { ) .unwrap(); let receiver_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let source_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1801,17 +1822,21 @@ fn udp_queued_datagrams_survive_source_process_teardown() { ) .unwrap(); let source_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let first_receiver_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let second_receiver_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let replacement_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1946,11 +1971,13 @@ fn connected_guest_udp_enforces_barriers_peek_and_peer_generations() { ) .unwrap(); let first_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let second_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2078,8 +2105,9 @@ fn connected_guest_udp_filters_other_wildcard_peer_aliases() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2157,8 +2185,9 @@ fn wildcard_udp_reconnect_updates_guest_source_identity() { ) .unwrap(); let process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, _publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2244,11 +2273,13 @@ fn externally_connected_udp_preserves_guest_routing_identity() { ) .unwrap(); let source_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let receiver_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2354,11 +2385,13 @@ fn internally_connected_udp_drains_external_datagrams_without_delivering_them() ) .unwrap(); let receiver_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let sender_process = broker - .create_test_process(CallerCredential::Unauthenticated, None) - .unwrap(); + .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .unwrap() + .0; let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); From fd9402187cdcabe55f0613ba614996a6eb92a388 Mon Sep 17 00:00:00 2001 From: Weidong Cui Date: Wed, 23 Sep 2026 21:44:40 -0700 Subject: [PATCH 7/8] Make process creation include the initial thread Use create_process for the complete production operation and reserve allocate_process for core-internal tests that intentionally need threadless state. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ee779b34-31e2-4e38-8068-21fe8fce7674 --- litebox_broker_core/src/lib.rs | 10 +- litebox_broker_core/src/process.rs | 154 +++++++++--------- litebox_broker_core/src/socket/tests.rs | 78 ++++----- litebox_broker_host/src/lib.rs | 28 ++-- .../src/socket/tests/mod.rs | 2 +- .../src/socket/tests/tcp.rs | 88 +++++----- .../src/socket/tests/udp.rs | 66 ++++---- .../src/process_launcher.rs | 2 +- 8 files changed, 214 insertions(+), 214 deletions(-) diff --git a/litebox_broker_core/src/lib.rs b/litebox_broker_core/src/lib.rs index 16d37b94e..052bd5e7a 100644 --- a/litebox_broker_core/src/lib.rs +++ b/litebox_broker_core/src/lib.rs @@ -325,13 +325,13 @@ impl BrokerCore { Ok((first, second)) } - /// Allocates one authenticated process awaiting association activation. + /// Allocates one authenticated process without an initial thread. /// /// # Panics /// /// Panics if the shared ID allocator violates its range or uniqueness /// invariants. - pub(crate) fn create_process( + pub(crate) fn allocate_process( &self, caller_credential: CallerCredential, parent_id: Option, @@ -388,7 +388,7 @@ impl BrokerCore { allocate_process(None, None) } - /// Allocates one process and its initial thread. + /// Creates one process and its initial thread. /// /// If initial-thread creation fails, the process is retired before the /// error is returned. @@ -397,12 +397,12 @@ impl BrokerCore { /// /// Panics if the shared ID allocator violates its range or uniqueness /// invariants. - pub fn create_process_with_initial_thread( + pub fn create_process( &self, caller_credential: CallerCredential, parent_id: Option, ) -> Result<(Arc, ThreadId)> { - let process = self.create_process(caller_credential, parent_id)?; + let process = self.allocate_process(caller_credential, parent_id)?; match process.create_thread() { Ok(initial_thread_id) => Ok((process, initial_thread_id)), Err(error) => { diff --git a/litebox_broker_core/src/process.rs b/litebox_broker_core/src/process.rs index 910253068..640c1b7f3 100644 --- a/litebox_broker_core/src/process.rs +++ b/litebox_broker_core/src/process.rs @@ -1228,7 +1228,7 @@ mod tests { fn prepared_duplication(parent: &Arc) -> Arc { let (child, _) = parent .core - .create_process_with_initial_thread(parent.caller_credential(), Some(parent.id())) + .create_process(parent.caller_credential(), Some(parent.id())) .unwrap(); parent.prepare_duplication_child(&child).unwrap(); child @@ -1281,11 +1281,11 @@ mod tests { .build() .unwrap(); let parent = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); parent.complete_start().unwrap(); let child = broker - .create_process(parent.caller_credential(), Some(parent.id())) + .allocate_process(parent.caller_credential(), Some(parent.id())) .unwrap(); assert!(matches!( @@ -1304,15 +1304,15 @@ mod tests { .build() .unwrap(); let owner = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); owner.complete_start().unwrap(); let other_owner = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); other_owner.complete_start().unwrap(); let (child, _) = broker - .create_process_with_initial_thread(owner.caller_credential(), Some(owner.id())) + .create_process(owner.caller_credential(), Some(owner.id())) .unwrap(); assert_eq!( @@ -1342,7 +1342,7 @@ mod tests { .build() .unwrap(); let parent = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); parent.complete_start().unwrap(); let first_child = prepared_duplication(&parent); @@ -1365,7 +1365,7 @@ mod tests { .unwrap(); let cancelled_parent = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); cancelled_parent.complete_start().unwrap(); let cancelled_child = prepared_duplication(&cancelled_parent); @@ -1380,7 +1380,7 @@ mod tests { assert_eq!(cancelled_child.state.lock().status, ProcessStatus::Running); assert_eq!(shutdowns.load(Ordering::Relaxed), 0); let unprepared_child = broker - .create_process( + .allocate_process( cancelled_parent.caller_credential(), Some(cancelled_parent.id()), ) @@ -1391,7 +1391,7 @@ mod tests { )); let dead_parent = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); dead_parent.complete_start().unwrap(); let dead_child = prepared_duplication(&dead_parent); @@ -1402,7 +1402,7 @@ mod tests { assert_eq!(parent_id(&dead_child), None); let live_parent = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); live_parent.complete_start().unwrap(); let failed_child = prepared_duplication(&live_parent); @@ -1421,11 +1421,11 @@ mod tests { .build() .unwrap(); let first = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let thread = first.create_thread().unwrap(); let second = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); assert_eq!(first.id().0, 1); @@ -1441,11 +1441,11 @@ mod tests { .build() .unwrap(); let parent = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); parent.complete_start().unwrap(); let child = broker - .create_process(parent.caller_credential(), Some(parent.id())) + .allocate_process(parent.caller_credential(), Some(parent.id())) .unwrap(); let shutdowns = Arc::new(AtomicUsize::new(0)); let shutdown_count = Arc::clone(&shutdowns); @@ -1469,20 +1469,20 @@ mod tests { .build() .unwrap(); let root = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); root.complete_start().unwrap(); let parent = broker - .create_process(CallerCredential::Unauthenticated, Some(root.id())) + .allocate_process(CallerCredential::Unauthenticated, Some(root.id())) .unwrap(); parent.complete_start().unwrap(); let running = broker - .create_process(CallerCredential::Unauthenticated, Some(parent.id())) + .allocate_process(CallerCredential::Unauthenticated, Some(parent.id())) .unwrap(); running.complete_start().unwrap(); let zombie = broker - .create_process(CallerCredential::Unauthenticated, Some(parent.id())) + .allocate_process(CallerCredential::Unauthenticated, Some(parent.id())) .unwrap(); zombie.complete_start().unwrap(); zombie @@ -1499,7 +1499,7 @@ mod tests { assert_eq!(parent_id(&zombie), Some(root.id())); assert_eq!(zombie.state.lock().status, ProcessStatus::Zombie); assert!(matches!( - broker.create_process(CallerCredential::Unauthenticated, Some(parent.id())), + broker.allocate_process(CallerCredential::Unauthenticated, Some(parent.id())), Err(BrokerError::PeerClosed) )); } @@ -1512,16 +1512,16 @@ mod tests { .build() .unwrap(); let root = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); root.complete_start().unwrap(); let running = broker - .create_process(CallerCredential::Unauthenticated, Some(root.id())) + .allocate_process(CallerCredential::Unauthenticated, Some(root.id())) .unwrap(); running.complete_start().unwrap(); let zombie = broker - .create_process(CallerCredential::Unauthenticated, Some(root.id())) + .allocate_process(CallerCredential::Unauthenticated, Some(root.id())) .unwrap(); zombie.complete_start().unwrap(); zombie @@ -1546,15 +1546,15 @@ mod tests { .build() .unwrap(); let root = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); root.complete_start().unwrap(); let parent = broker - .create_process(CallerCredential::Unauthenticated, Some(root.id())) + .allocate_process(CallerCredential::Unauthenticated, Some(root.id())) .unwrap(); parent.complete_start().unwrap(); let child = broker - .create_process(CallerCredential::Unauthenticated, Some(parent.id())) + .allocate_process(CallerCredential::Unauthenticated, Some(parent.id())) .unwrap(); child.complete_start().unwrap(); child @@ -1582,15 +1582,15 @@ mod tests { broker.ids = alloc::sync::Arc::new(spin::Mutex::new(crate::id::IdAllocator::new(3).unwrap())); let root = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); root.complete_start().unwrap(); let parent = broker - .create_process(CallerCredential::Unauthenticated, Some(root.id())) + .allocate_process(CallerCredential::Unauthenticated, Some(root.id())) .unwrap(); parent.complete_start().unwrap(); let zombie = broker - .create_process(CallerCredential::Unauthenticated, Some(parent.id())) + .allocate_process(CallerCredential::Unauthenticated, Some(parent.id())) .unwrap(); zombie.complete_start().unwrap(); zombie @@ -1603,7 +1603,7 @@ mod tests { root.handle_owner_death(); root.cleanup(true); let replacement = broker - .create_process(CallerCredential::Unauthenticated, Some(parent.id())) + .allocate_process(CallerCredential::Unauthenticated, Some(parent.id())) .unwrap(); assert_eq!(replacement.id(), root.id()); let shutdowns = Arc::new(AtomicUsize::new(0)); @@ -1631,15 +1631,15 @@ mod tests { .build() .unwrap(); let root = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); root.complete_start().unwrap(); let parent = broker - .create_process(CallerCredential::Unauthenticated, Some(root.id())) + .allocate_process(CallerCredential::Unauthenticated, Some(root.id())) .unwrap(); parent.complete_start().unwrap(); let other_root = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); other_root.complete_start().unwrap(); @@ -1680,7 +1680,7 @@ mod tests { .unwrap() .with_process_lifecycle_sink(sink.clone()); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let retained = Arc::clone(&process); process.complete_start().unwrap(); @@ -1694,7 +1694,7 @@ mod tests { drop(process); assert!(matches!( - broker.create_process(CallerCredential::Unauthenticated, None), + broker.allocate_process(CallerCredential::Unauthenticated, None), Err(BrokerError::ResourceExhausted) )); assert_eq!(sink.changes.load(Ordering::Relaxed), 1); @@ -1704,7 +1704,7 @@ mod tests { assert_eq!(sink.changes.load(Ordering::Relaxed), 2); assert!( broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .is_ok() ); } @@ -1717,10 +1717,10 @@ mod tests { .build() .unwrap(); let source = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let target = broker - .create_process(source.caller_credential(), None) + .allocate_process(source.caller_credential(), None) .unwrap(); let source_handle = crate::event::create(&source, 1).unwrap(); @@ -1746,7 +1746,7 @@ mod tests { broker.ids = alloc::sync::Arc::new(spin::Mutex::new(crate::id::IdAllocator::new(2).unwrap())); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let first = process.create_thread().unwrap(); @@ -1763,10 +1763,10 @@ mod tests { .build() .unwrap(); let first = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let second = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let thread = first.create_thread().unwrap(); @@ -1783,13 +1783,13 @@ mod tests { .build() .unwrap(); let first = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let second = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let third = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let first_thread = first.create_thread().unwrap(); let second_thread = second.create_thread().unwrap(); @@ -1811,18 +1811,18 @@ mod tests { .build() .unwrap(); let first = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); assert!(matches!( - broker.create_process(CallerCredential::Unauthenticated, None), + broker.allocate_process(CallerCredential::Unauthenticated, None), Err(BrokerError::ResourceExhausted) )); first.cleanup(true); assert!( broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .is_ok() ); } @@ -1837,7 +1837,7 @@ mod tests { broker.ids = alloc::sync::Arc::new(spin::Mutex::new(crate::id::IdAllocator::new(2).unwrap())); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let process_id = process.id(); let thread_id = process.create_thread().unwrap(); @@ -1856,7 +1856,7 @@ mod tests { assert_eq!(broker.active_thread_count.load(Ordering::Relaxed), 0); let replacement = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); assert_eq!(replacement.id(), process_id); assert_eq!(replacement.create_thread().unwrap(), thread_id); @@ -1873,7 +1873,7 @@ mod tests { broker.ids = alloc::sync::Arc::new(spin::Mutex::new(crate::id::IdAllocator::new(4).unwrap())); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let process_id = process.id(); let thread_id = process.create_thread().unwrap(); @@ -1882,10 +1882,10 @@ mod tests { assert_eq!(broker.active_thread_count.load(Ordering::Relaxed), 1); let first_replacement = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let second_replacement = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); assert_ne!(first_replacement.id(), process_id); assert_ne!(first_replacement.id().0, thread_id.0); @@ -1896,7 +1896,7 @@ mod tests { Err(BrokerError::ResourceExhausted) ); assert!(matches!( - broker.create_process(CallerCredential::Unauthenticated, None), + broker.allocate_process(CallerCredential::Unauthenticated, None), Err(BrokerError::ResourceExhausted) )); } @@ -1909,7 +1909,7 @@ mod tests { .build() .unwrap(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let process_id = process.id(); crate::event::create(&process, 1).unwrap(); @@ -1919,7 +1919,7 @@ mod tests { assert!(broker.references.read().is_empty()); let replacement = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); assert_ne!(replacement.id(), process_id); } @@ -1948,13 +1948,13 @@ mod tests { fn check_supported_references_duplicate_between_processes(broker: &BrokerCore) { let source = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let target = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let denied_target = broker - .create_process(CallerCredential::HostGuaranteed, None) + .allocate_process(CallerCredential::HostGuaranteed, None) .unwrap(); let event = crate::event::create(&source, 1).unwrap(); @@ -2011,10 +2011,10 @@ mod tests { fn check_file_reference_lifecycle(broker: &BrokerCore, stdio_provider: &TestStdioProvider) { let source = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let target = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let mode = FileMode::from_bits(0o600).unwrap(); let file = crate::fs::open( @@ -2289,10 +2289,10 @@ mod tests { fn check_event_reference_lifecycle(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let other = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let handle = crate::event::create(&process, 0).unwrap(); let unknown_handle = ObjectHandle(handle.0.checked_add(1).unwrap()); @@ -2343,7 +2343,7 @@ mod tests { fn check_process_drop_releases_references(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let first = crate::event::create(&process, 0).unwrap(); let second = crate::event::create(&process, 0).unwrap(); @@ -2363,7 +2363,7 @@ mod tests { fn check_pipe_lifecycle(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); assert_eq!( crate::pipe::create(&process, 5, 2), @@ -2411,7 +2411,7 @@ mod tests { fn check_pipe_reader_closure(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let (reader, writer) = crate::pipe::create(&process, 4, 2).unwrap(); assert_eq!(broker.reserved_pipe_capacity.load(Ordering::Relaxed), 4); @@ -2431,7 +2431,7 @@ mod tests { fn check_corrupt_index_fails_without_mutation(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let older = crate::event::create(&process, 0).unwrap(); let newer = crate::event::create(&process, 0).unwrap(); @@ -2454,7 +2454,7 @@ mod tests { fn check_corrupt_index_does_not_break_teardown(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let _older = crate::event::create(&process, 0).unwrap(); let newer = crate::event::create(&process, 0).unwrap(); @@ -2472,10 +2472,10 @@ mod tests { fn check_reference_quota_is_per_process(broker: &BrokerCore) { let greedy = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let neighbor = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let greedy_first = crate::event::create(&greedy, 0).unwrap(); @@ -2490,7 +2490,7 @@ mod tests { assert_eq!(broker.references.read().len(), TEST_MAX_REFERENCES); let latecomer = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); assert_eq!( crate::event::create(&latecomer, 0), @@ -2509,10 +2509,10 @@ mod tests { fn check_pending_references_count_toward_process_quota(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let neighbor = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let first = process @@ -2536,10 +2536,10 @@ mod tests { fn check_pipe_capacity_quota_is_per_process(broker: &BrokerCore) { let greedy = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let neighbor = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let (greedy_reader, greedy_writer) = @@ -2561,7 +2561,7 @@ mod tests { ); let latecomer = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); assert_eq!( crate::pipe::create(&latecomer, 1, 1), @@ -2581,7 +2581,7 @@ mod tests { fn check_pipe_capacity_outlives_process_for_in_flight_object(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let (reader, _writer) = crate::pipe::create(&process, TEST_MAX_PIPE_CAPACITY_PER_PROCESS as u64, 2).unwrap(); @@ -2610,7 +2610,7 @@ mod tests { fn check_pair_handle_exhaustion(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); { let mut next_reference_handle = broker.next_reference_handle.write(); diff --git a/litebox_broker_core/src/socket/tests.rs b/litebox_broker_core/src/socket/tests.rs index b45de414d..65a7db6a5 100644 --- a/litebox_broker_core/src/socket/tests.rs +++ b/litebox_broker_core/src/socket/tests.rs @@ -72,7 +72,7 @@ fn gateway_destinations_require_external_policy() { let provider = Arc::new(TestSocketProvider::default()); let broker = test_broker(Arc::clone(&provider) as Arc); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let tcp = create( &process, @@ -113,7 +113,7 @@ fn gateway_destinations_reach_the_platform_untranslated() { .unwrap(); let broker = test_broker_with_policy(Arc::clone(&provider) as Arc, &policy); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let tcp = create( &process, @@ -303,7 +303,7 @@ fn rejected_external_route_preserves_an_exact_loopback_socket() { .unwrap(); let broker = test_broker_with_policy(Arc::clone(&provider) as Arc, &policy); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let socket = create( &process, @@ -351,7 +351,7 @@ fn rejected_udp_external_routes_preserve_an_exact_loopback_socket() { .unwrap(); let broker = test_broker_with_policy(Arc::clone(&provider) as Arc, &policy); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let socket = create( &process, @@ -1086,7 +1086,7 @@ fn zero_port_connect_fails_before_platform_dispatch() { let provider = Arc::new(TestSocketProvider::default()); let broker = test_broker(Arc::clone(&provider) as Arc); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let socket = create( &process, @@ -1116,10 +1116,10 @@ fn accepted_guest_source_lease_is_retained() { let provider = Arc::new(TestSocketProvider::default()); let broker = test_broker(Arc::clone(&provider) as Arc); let listener_session = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_session = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let listener = create( &listener_session, @@ -1212,10 +1212,10 @@ fn check_queued_guest_source_lease_release(stop_listener: bool) { let provider = Arc::new(TestSocketProvider::default()); let broker = test_broker(Arc::clone(&provider) as Arc); let listener_session = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_session = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let listener_address = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 44010); let listener = create( @@ -1373,7 +1373,7 @@ fn check_platform_socket_retires_before_last_arc_drop( provider: &TestSocketProvider, ) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let retired_before = provider.state.retired_sockets.load(Ordering::Relaxed); let dropped_before = provider.state.dropped_sockets.load(Ordering::Relaxed); @@ -1414,7 +1414,7 @@ fn check_platform_socket_retires_before_last_arc_drop( fn check_failed_create_rolls_back(broker: &BrokerCore, provider: &TestSocketProvider) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); provider.fail_next_create(); let readiness = Arc::new(TestReadinessSink::default()); @@ -1443,7 +1443,7 @@ fn failed_accept_rolls_back_readiness_and_quota() { let provider = Arc::new(TestSocketProvider::default()); let broker = test_broker(Arc::clone(&provider) as Arc); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let listener = create( &process, @@ -1519,10 +1519,10 @@ fn invalid_accepted_metadata_retires_socket_readiness_and_quota() { ), ] { let listener_session = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let connector_session = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let listener = create( &listener_session, @@ -1601,7 +1601,7 @@ fn invalid_accepted_metadata_retires_socket_readiness_and_quota() { fn check_in_flight_connect_preserves_local_address(broker: &BrokerCore) { let process = Arc::new( broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(), ); let (started_tx, started_rx) = mpsc::channel(); @@ -1640,10 +1640,10 @@ fn check_in_flight_connect_preserves_local_address(broker: &BrokerCore) { fn check_invalid_bind_response_retires_socket(broker: &BrokerCore, provider: &TestSocketProvider) { let first_session = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let second_session = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let readiness = Arc::new(TestReadinessSink::default()); let retired_before = provider.state.retired_sockets.load(Ordering::Relaxed); @@ -1712,7 +1712,7 @@ fn check_invalid_bind_response_retires_socket(broker: &BrokerCore, provider: &Te let blocking_session = Arc::new( broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(), ); let invalid = create( @@ -1792,7 +1792,7 @@ fn check_automatic_bind_retains_reservation_during_retirement( }; let process = Arc::new( broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(), ); let handle = create(&process, request, Arc::new(TestReadinessSink::default())).unwrap(); @@ -1841,7 +1841,7 @@ fn check_automatic_bind_retains_reservation_during_retirement( fn check_duplicate_port_binding_retires_socket(broker: &BrokerCore, provider: &TestSocketProvider) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let handle = create( &process, @@ -1903,10 +1903,10 @@ fn check_duplicate_port_binding_retires_socket(broker: &BrokerCore, provider: &T fn check_socket_operations_and_policy(broker: &BrokerCore, provider: &TestSocketProvider) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let other = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let readiness = Arc::new(TestReadinessSink::default()); let handle = create(&process, create_request(), readiness.clone()).unwrap(); @@ -2113,7 +2113,7 @@ fn check_socket_operations_and_policy(broker: &BrokerCore, provider: &TestSocket fn check_tcp_option_state_is_per_socket(broker: &BrokerCore) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let first = create( &process, @@ -2155,7 +2155,7 @@ fn check_private_tcp_connect_uses_private_source_for_wildcard_binding( provider: &TestSocketProvider, ) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let handle = create( &process, @@ -2202,7 +2202,7 @@ fn check_udp_socket_operations(broker: &BrokerCore, provider: &TestSocketProvide .unwrap() .len(); let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let readiness = Arc::new(TestReadinessSink::default()); let request = CreateSocketRequest { @@ -2480,7 +2480,7 @@ fn check_udp_socket_operations(broker: &BrokerCore, provider: &TestSocketProvide fn check_udp_status_validates_local_address(broker: &BrokerCore, provider: &TestSocketProvider) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let unbound = create( &process, @@ -2739,7 +2739,7 @@ fn check_udp_status_validates_local_address(broker: &BrokerCore, provider: &Test fn check_server_socket_operations(broker: &BrokerCore, provider: &TestSocketProvider) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let readiness = Arc::new(TestReadinessSink::default()); let listener = create(&process, create_request(), readiness.clone()).unwrap(); @@ -2813,7 +2813,7 @@ fn check_server_socket_operations(broker: &BrokerCore, provider: &TestSocketProv ); let competing_session = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let competitor = create( &competing_session, @@ -2855,7 +2855,7 @@ fn check_concurrent_udp_status_does_not_regress_connection( ) { let process = Arc::new( broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(), ); let handle = create( @@ -2975,7 +2975,7 @@ fn check_failed_listener_shutdown_preserves_state( provider: &TestSocketProvider, ) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let handle = create( &process, @@ -3005,7 +3005,7 @@ fn check_listener_shutdown_does_not_race_listen( ) { let process = Arc::new( broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(), ); let handle = create( @@ -3044,13 +3044,13 @@ fn check_listener_shutdown_does_not_race_listen( fn check_socket_quotas(broker: &BrokerCore) { let first = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let second = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let third = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let first_handle = create( &first, @@ -3119,7 +3119,7 @@ impl ReadinessSink for BlockingReadinessSink { fn check_quota_waits_for_deferred_retirement(broker: &BrokerCore, provider: &TestSocketProvider) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let (started_tx, started_rx) = mpsc::channel(); let (release_tx, release_rx) = mpsc::channel(); @@ -3155,7 +3155,7 @@ fn check_quota_waits_for_deferred_retirement(broker: &BrokerCore, provider: &Tes fn check_connect_errors_classify_peer_state(broker: &BrokerCore, provider: &TestSocketProvider) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let retryable = create( &process, @@ -3325,7 +3325,7 @@ fn check_concurrent_status_preserves_terminal_state( ) { let process = Arc::new( broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(), ); let handle = create( @@ -3504,7 +3504,7 @@ fn check_concurrent_status_preserves_terminal_state( fn check_stream_status_validates_local_address(broker: &BrokerCore, provider: &TestSocketProvider) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let valid = create( &process, @@ -3761,7 +3761,7 @@ fn check_terminal_stream_status_preserves_refined_address( provider: &TestSocketProvider, ) { let process = broker - .create_process(CallerCredential::Unauthenticated, None) + .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); let handle = create( &process, diff --git a/litebox_broker_host/src/lib.rs b/litebox_broker_host/src/lib.rs index b9f288044..86448b866 100644 --- a/litebox_broker_host/src/lib.rs +++ b/litebox_broker_host/src/lib.rs @@ -332,7 +332,7 @@ where .map_err(BrokerHostError::Channel)?; return Ok(Err(ConnectionTermination::Rejected(error))); } - None => match core.create_process_with_initial_thread(caller_credential, None) { + None => match core.create_process(caller_credential, None) { Ok(process) => process, Err( error @ (litebox_broker_core::BrokerError::ResourceExhausted @@ -830,7 +830,7 @@ fn start_child_process( return Err(RequestFailure::Abort(ErrorCode::ProtocolState)); } let (process, initial_thread_id) = broker - .create_process_with_initial_thread(parent.caller_credential(), Some(parent.id())) + .create_process(parent.caller_credential(), Some(parent.id())) .map_err(RequestFailure::from)?; let inherited_objects = match parent .duplicate_object_references_to(requested_inherited_objects.as_slice(), &process) @@ -1670,7 +1670,7 @@ mod tests { fn precreated_root_negotiates_without_startup_data(broker: &BrokerCore) { let (process, initial_thread_id) = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap(); let mut channel = FakeHostControlChannel::new( std::vec::Vec::from([Ok(HostReceive::Message(BrokerHandshakeRequest { @@ -1699,12 +1699,12 @@ mod tests { fn prepared_duplication_publishes_after_activation(broker: &BrokerCore) { let parent = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; parent.complete_start().unwrap(); let (child, _) = broker - .create_process_with_initial_thread(parent.caller_credential(), Some(parent.id())) + .create_process(parent.caller_credential(), Some(parent.id())) .unwrap(); parent.prepare_duplication_child(&child).unwrap(); let association = BrokerHostAssociation::new( @@ -1724,7 +1724,7 @@ mod tests { fn association_shared_buffer_sequences_stage_file_data(broker: &BrokerCore) { let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let shared_buffers = test_shared_buffers(); @@ -1837,7 +1837,7 @@ mod tests { fn association_shared_buffer_sequence_stages_random_data(broker: &BrokerCore) { let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let shared_buffers = test_shared_buffers(); @@ -1893,7 +1893,7 @@ mod tests { provider: &TestStdioProvider, ) { let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let shared_buffers = test_shared_buffers(); @@ -2106,7 +2106,7 @@ mod tests { ); assert!(!setup_called.get()); let (process, initial_thread_id) = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap(); assert_eq!(process.id(), root_process_id(5)); assert_eq!(initial_thread_id, ThreadId(6)); @@ -2320,7 +2320,7 @@ mod tests { fn active_request_closes_object_reference(broker: &BrokerCore) { let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let response = handle_test_request( @@ -2353,7 +2353,7 @@ mod tests { fn active_request_allocates_and_releases_thread_id(broker: &BrokerCore) { let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let response = handle_test_request(&process, BrokerOperation::CreateThread); @@ -2373,7 +2373,7 @@ mod tests { fn association_shared_buffer_sequences_stage_pipe_data(broker: &BrokerCore) { let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let memory = TestSharedMemory::new(SHARED_BUFFER_POOL_SIZE); @@ -2435,7 +2435,7 @@ mod tests { fn association_shared_buffer_sequences_stage_socket_data(broker: &BrokerCore) { let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let shared_buffers = test_shared_buffers(); @@ -2858,7 +2858,7 @@ mod tests { ) -> BrokerHostAssociation { BrokerHostAssociation { process: broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0, shared_buffers, diff --git a/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs b/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs index 947038f1d..a1bda8760 100644 --- a/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs +++ b/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs @@ -378,7 +378,7 @@ fn directional_shutdown_survives_readiness_publication_failure() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); diff --git a/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs b/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs index d6f8e7972..303c4f2db 100644 --- a/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs +++ b/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs @@ -24,11 +24,11 @@ fn connected_guest_tcp_pair(port: u16) -> GuestTcpPair { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -156,7 +156,7 @@ fn reactor_drives_a_loopback_tcp_socket() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -486,7 +486,7 @@ fn external_tcp_deferred_abortive_close_resets_peer() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -532,7 +532,7 @@ fn external_tcp_gateway_uses_host_loopback_and_keeps_guest_identity() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -609,7 +609,7 @@ fn external_tcp_route_keeps_guest_private_identity() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -651,7 +651,7 @@ fn tcp_connect_to_zero_port_returns_an_ordinary_socket_outcome() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, _publications) = channel(); @@ -690,7 +690,7 @@ fn tcp_receive_survives_readiness_publication_failure() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -753,7 +753,7 @@ fn tcp_status_publication_failure_preserves_consumed_error() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -828,7 +828,7 @@ fn external_tcp_readiness_failure_does_not_fail_shared_reactor() { .unwrap(); let process_a = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published_a, publications_a) = channel(); @@ -856,7 +856,7 @@ fn external_tcp_readiness_failure_does_not_fail_shared_reactor() { // Process B gets its own readiness sink, mirroring production's // per-association sinks. let process_b = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published_b, publications_b) = channel(); @@ -953,7 +953,7 @@ fn external_tcp_connect_completion_readiness_failure_does_not_fail_shared_reacto ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -1041,7 +1041,7 @@ fn exhausted_tcp_peek_cache_refreshes_before_terminal_eof() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -1125,11 +1125,11 @@ fn accepted_guest_tcp_close_with_unread_data_preserves_reset() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -1485,11 +1485,11 @@ fn guest_tcp_namespace_routes_across_processs_and_hides_private_backend() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let client_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -1629,11 +1629,11 @@ fn tcp_exact_bindings_coexist_and_wildcard_accepts_concrete_destinations() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -1783,11 +1783,11 @@ fn connector_and_process_teardown_clean_bounded_pending_state() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -1847,7 +1847,7 @@ fn connector_and_process_teardown_clean_bounded_pending_state() { assert_ne!(retirements.recv_timeout(TEST_TIMEOUT).unwrap(), listener); let final_connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let final_connector = create_socket(&final_connector_process, readiness); @@ -1892,11 +1892,11 @@ fn graceful_connector_close_preserves_late_accept_and_eof() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -1988,11 +1988,11 @@ fn guest_tcp_zero_backlog_accepts_one_unspecified_destination() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, _publications) = channel(); @@ -2078,11 +2078,11 @@ fn guest_tcp_backlog_relisten_and_fifo_are_bounded() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -2199,11 +2199,11 @@ fn guest_tcp_stream_preserves_options_peek_waitall_and_half_close() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -2661,11 +2661,11 @@ fn guest_tcp_connect_publication_failure_purges_committed_queue() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, _publications) = channel(); @@ -2718,11 +2718,11 @@ fn guest_tcp_accept_publication_failure_purges_registered_endpoint() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -2785,11 +2785,11 @@ fn queued_guest_accept_transfers_capacity_without_global_growth() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, _publications) = channel(); @@ -2813,7 +2813,7 @@ fn queued_guest_accept_transfers_capacity_without_global_growth() { ); assert_eq!(provider.reactor.queued_guest_connection_count(), 1); let capacity_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let _global_capacity = create_socket(&capacity_process, readiness.clone()); @@ -2848,11 +2848,11 @@ fn queued_guest_accept_rejects_exhausted_listener_process_capacity() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, _publications) = channel(); @@ -2907,11 +2907,11 @@ fn abortive_connector_close_releases_descriptor_capacity() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -2990,11 +2990,11 @@ fn stop_listening_cleanup_survives_readiness_failure() { ) .unwrap(); let listener_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let connector_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -3076,7 +3076,7 @@ fn reactor_drives_a_loopback_tcp_listener() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); diff --git a/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs b/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs index e95779fc2..f18466413 100644 --- a/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs +++ b/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs @@ -48,7 +48,7 @@ fn udp_gateway_translates_sources_filters_spoofing_and_reuses_endpoint() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -134,7 +134,7 @@ fn connected_udp_gateway_preserves_guest_visible_mapping() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -190,7 +190,7 @@ fn unmatched_guest_udp_destinations_fail_closed() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, _publications) = channel(); @@ -235,7 +235,7 @@ fn failed_initial_udp_readiness_does_not_retain_process_state() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, _publications) = channel(); @@ -272,11 +272,11 @@ fn guest_udp_readiness_failure_rolls_back_enqueue() { ) .unwrap(); let receiver_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let sender_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, _publications) = channel(); @@ -371,7 +371,7 @@ fn external_udp_readiness_failure_does_not_fail_shared_reactor() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -484,7 +484,7 @@ fn udp_status_publication_failure_still_rearms_native_endpoint() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -558,7 +558,7 @@ fn udp_status_republishes_when_another_error_remains_pending() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -611,11 +611,11 @@ fn guest_udp_queue_pressure_drops_new_datagrams_successfully() { ) .unwrap(); let receiver_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let sender_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, _publications) = channel(); @@ -704,7 +704,7 @@ fn udp_external_peer_authorization_is_bounded_without_eviction() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -797,7 +797,7 @@ fn reactor_preserves_udp_datagram_semantics() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -1152,11 +1152,11 @@ fn guest_udp_namespace_routes_across_processes_and_filters_private_endpoints() { ) .unwrap(); let receiver_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let sender_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -1418,11 +1418,11 @@ fn udp_exact_bindings_coexist_and_wildcard_covers_guest_addresses() { ) .unwrap(); let receiver_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let sender_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -1608,7 +1608,7 @@ fn udp_native_endpoint_is_reused_and_retired() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, _publications) = channel(); @@ -1674,7 +1674,7 @@ fn udp_endpoint_staging_error_rolls_back_external_peer_reservation() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, _publications) = channel(); @@ -1713,11 +1713,11 @@ fn stale_udp_datagrams_are_not_relabelled_after_guest_port_reuse() { ) .unwrap(); let receiver_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let source_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -1822,19 +1822,19 @@ fn udp_queued_datagrams_survive_source_process_teardown() { ) .unwrap(); let source_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let first_receiver_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let second_receiver_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let replacement_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -1971,11 +1971,11 @@ fn connected_guest_udp_enforces_barriers_peek_and_peer_generations() { ) .unwrap(); let first_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let second_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -2105,7 +2105,7 @@ fn connected_guest_udp_filters_other_wildcard_peer_aliases() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -2185,7 +2185,7 @@ fn wildcard_udp_reconnect_updates_guest_source_identity() { ) .unwrap(); let process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, _publications) = channel(); @@ -2273,11 +2273,11 @@ fn externally_connected_udp_preserves_guest_routing_identity() { ) .unwrap(); let source_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let receiver_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); @@ -2385,11 +2385,11 @@ fn internally_connected_udp_drains_external_datagrams_without_delivering_them() ) .unwrap(); let receiver_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let sender_process = broker - .create_process_with_initial_thread(CallerCredential::Unauthenticated, None) + .create_process(CallerCredential::Unauthenticated, None) .unwrap() .0; let (published, publications) = channel(); diff --git a/litebox_broker_userland/src/process_launcher.rs b/litebox_broker_userland/src/process_launcher.rs index 195decca8..4e61ac564 100644 --- a/litebox_broker_userland/src/process_launcher.rs +++ b/litebox_broker_userland/src/process_launcher.rs @@ -127,7 +127,7 @@ impl UserlandProcessLauncher { let launcher = Self::new(config.without_initial_arguments(), broker.clone()); let (process, initial_thread_id) = launcher .broker - .create_process_with_initial_thread(CallerCredential::HostGuaranteed, None) + .create_process(CallerCredential::HostGuaranteed, None) .map_err(broker_io_error)?; let association = PendingRunnerAssociation::new(Arc::clone(&process), initial_thread_id, None); From c59bb54c1c82addc48a8a9b32c3a9871a35bab54 Mon Sep 17 00:00:00 2001 From: Weidong Cui Date: Wed, 23 Sep 2026 22:04:00 -0700 Subject: [PATCH 8/8] Store initial thread identity in BrokerProcess Keep the initial thread ID as immutable process creation metadata, return only the process from create_process, and remove duplicated ID plumbing from setup and launcher paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ee779b34-31e2-4e38-8068-21fe8fce7674 --- litebox_broker_core/src/lib.rs | 9 +- litebox_broker_core/src/process.rs | 34 ++++- litebox_broker_host/src/lib.rs | 58 +++----- .../src/socket/tests/mod.rs | 3 +- .../src/socket/tests/tcp.rs | 132 ++++++------------ .../src/socket/tests/udp.rs | 99 +++++-------- .../src/process_launcher.rs | 26 +--- 7 files changed, 144 insertions(+), 217 deletions(-) diff --git a/litebox_broker_core/src/lib.rs b/litebox_broker_core/src/lib.rs index 052bd5e7a..8d404460f 100644 --- a/litebox_broker_core/src/lib.rs +++ b/litebox_broker_core/src/lib.rs @@ -39,7 +39,7 @@ use alloc::sync::{Arc, Weak}; use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use hashbrown::HashMap; -use litebox_broker_protocol::{ObjectHandle, ProcessId, ThreadId}; +use litebox_broker_protocol::{ObjectHandle, ProcessId}; use spin::{Mutex, rwlock::RwLock}; pub use error::BrokerError; @@ -401,10 +401,13 @@ impl BrokerCore { &self, caller_credential: CallerCredential, parent_id: Option, - ) -> Result<(Arc, ThreadId)> { + ) -> Result> { let process = self.allocate_process(caller_credential, parent_id)?; match process.create_thread() { - Ok(initial_thread_id) => Ok((process, initial_thread_id)), + Ok(initial_thread_id) => { + process.set_initial_thread_id(initial_thread_id); + Ok(process) + } Err(error) => { process.retire(true); Err(error) diff --git a/litebox_broker_core/src/process.rs b/litebox_broker_core/src/process.rs index 640c1b7f3..f22a2e6fa 100644 --- a/litebox_broker_core/src/process.rs +++ b/litebox_broker_core/src/process.rs @@ -15,7 +15,7 @@ use crate::{BrokerCore, BrokerError, Result}; use hashbrown::{HashMap, HashSet}; use litebox_broker_protocol::readiness::ReadinessFlags; use litebox_broker_protocol::{ObjectHandle, ProcessId, ThreadId}; -use spin::{Mutex, rwlock::RwLock}; +use spin::{Mutex, Once, rwlock::RwLock}; /// Platform-provided notification destination for broker-process lifecycle changes. pub trait ProcessLifecycleSink: Send + Sync { @@ -113,6 +113,8 @@ pub struct BrokerProcess { pub(crate) core: BrokerCore, /// Assigned process ID and internal authority. pub(crate) id: ProcessId, + /// ID assigned to the initial thread when process creation completes. + initial_thread_id: Once, root: Arc, state: Mutex, /// Broker-entry-authenticated caller credential for this process. @@ -219,6 +221,7 @@ impl BrokerProcess { Self { core, id, + initial_thread_id: Once::new(), root, state: Mutex::new(BrokerProcessState { status: ProcessStatus::Starting, @@ -247,6 +250,31 @@ impl BrokerProcess { self.id } + /// Returns the ID assigned to this process's initial thread. + /// + /// This is immutable creation metadata. Live thread ownership remains + /// authoritative in the process thread set. + /// + /// # Panics + /// + /// Panics if called on crate-internal process state before process creation + /// initializes the initial thread. + #[must_use] + pub fn initial_thread_id(&self) -> ThreadId { + *self + .initial_thread_id + .get() + .expect("broker process creation did not initialize its initial thread ID") + } + + pub(crate) fn set_initial_thread_id(&self, initial_thread_id: ThreadId) { + assert!( + self.initial_thread_id.get().is_none(), + "broker process initial thread ID was initialized twice" + ); + self.initial_thread_id.call_once(|| initial_thread_id); + } + /// Returns the credential authenticated for this process association. #[must_use] pub const fn caller_credential(&self) -> CallerCredential { @@ -1226,7 +1254,7 @@ mod tests { } fn prepared_duplication(parent: &Arc) -> Arc { - let (child, _) = parent + let child = parent .core .create_process(parent.caller_credential(), Some(parent.id())) .unwrap(); @@ -1311,7 +1339,7 @@ mod tests { .allocate_process(CallerCredential::Unauthenticated, None) .unwrap(); other_owner.complete_start().unwrap(); - let (child, _) = broker + let child = broker .create_process(owner.caller_credential(), Some(owner.id())) .unwrap(); diff --git a/litebox_broker_host/src/lib.rs b/litebox_broker_host/src/lib.rs index 86448b866..0d5195b73 100644 --- a/litebox_broker_host/src/lib.rs +++ b/litebox_broker_host/src/lib.rs @@ -63,7 +63,7 @@ use litebox_broker_protocol::stdio::{ IsTerminalStdioRequest, IsTerminalStdioResponse, MAX_STDIO_TRANSFER_SIZE, ReadStdioRequest, ReadStdioResponse, WriteStdioRequest, WriteStdioResponse, }; -use litebox_broker_protocol::{BROKER_PROTOCOL_VERSION, RequestId, ThreadId}; +use litebox_broker_protocol::{BROKER_PROTOCOL_VERSION, RequestId}; use litebox_broker_transport::channel::{HostReceive, HostSetupChannel, PeerCredential}; use litebox_broker_transport::shared_memory::{SharedBufferError, SharedBufferPool, SharedMemory}; use spin::mutex::SpinMutex; @@ -223,7 +223,7 @@ impl BrokerHostAssociation { #[allow(clippy::too_many_arguments)] pub fn setup_connection( core: &BrokerCore, - process: Option<(Arc, ThreadId)>, + process: Option>, startup: Option, setup_channel: &mut SetupChannel, shared_buffers: Arc>, @@ -319,12 +319,8 @@ where } let finish_on_setup_error = process.is_none(); - let (process, initial_thread_id) = match process.take() { - Some((process, initial_thread_id)) - if process.caller_credential() == caller_credential => - { - (process, initial_thread_id) - } + let process = match process.take() { + Some(process) if process.caller_credential() == caller_credential => process, Some(_) => { let error = ErrorCode::PolicyDenied; setup_channel @@ -350,7 +346,7 @@ where let response = BrokerHandshakeResponse::Negotiated { broker_protocol_version: BROKER_PROTOCOL_VERSION, process_id: process.id(), - initial_thread_id, + initial_thread_id: process.initial_thread_id(), startup, }; let process_retained = retain_process(&process); @@ -780,7 +776,6 @@ pub trait ProcessLauncher: Send + Sync { fn launch( self: Arc, process: Arc, - initial_thread_id: ThreadId, startup: ProcessStartupData, ) -> core::result::Result<(), BrokerError>; } @@ -829,7 +824,7 @@ fn start_child_process( if !parent.is_running() { return Err(RequestFailure::Abort(ErrorCode::ProtocolState)); } - let (process, initial_thread_id) = broker + let process = broker .create_process(parent.caller_credential(), Some(parent.id())) .map_err(RequestFailure::from)?; let inherited_objects = match parent @@ -844,6 +839,7 @@ fn start_child_process( let inherited_objects = InheritedProcessObjects::new(&inherited_objects) .expect("child handle count must match the bounded inheritance request"); let process_id = process.id(); + let initial_thread_id = process.initial_thread_id(); if parent.is_cancellation_requested() { process.retire(true); return Err(RequestFailure::Respond(ErrorCode::PeerClosed)); @@ -851,7 +847,6 @@ fn start_child_process( launcher .launch( process, - initial_thread_id, ProcessStartupData { format, version, @@ -1294,7 +1289,7 @@ mod tests { TcpOptionValue, }; use litebox_broker_protocol::stdio::{StdioOutputStream, StdioStream}; - use litebox_broker_protocol::{ObjectHandle, ProcessId, ProtocolVersion, RequestId}; + use litebox_broker_protocol::{ObjectHandle, ProcessId, ProtocolVersion, RequestId, ThreadId}; use litebox_broker_transport::shared_memory::{SharedBufferPool, SharedMemoryError}; use litebox_platform::sync::{ ImmediatelyWokenUp, RawMutex, RawMutexProvider, UnblockedOrTimedOut, @@ -1669,7 +1664,7 @@ mod tests { } fn precreated_root_negotiates_without_startup_data(broker: &BrokerCore) { - let (process, initial_thread_id) = broker + let process = broker .create_process(CallerCredential::Unauthenticated, None) .unwrap(); let mut channel = FakeHostControlChannel::new( @@ -1681,7 +1676,7 @@ mod tests { let association = setup_connection( broker, - Some((Arc::clone(&process), initial_thread_id)), + Some(Arc::clone(&process)), None, &mut channel, Arc::new(test_shared_buffers()), @@ -1700,10 +1695,9 @@ mod tests { fn prepared_duplication_publishes_after_activation(broker: &BrokerCore) { let parent = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); parent.complete_start().unwrap(); - let (child, _) = broker + let child = broker .create_process(parent.caller_credential(), Some(parent.id())) .unwrap(); parent.prepare_duplication_child(&child).unwrap(); @@ -1725,8 +1719,7 @@ mod tests { fn association_shared_buffer_sequences_stage_file_data(broker: &BrokerCore) { let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let shared_buffers = test_shared_buffers(); shared_buffers .write(SharedBufferSlotIndex(0), b"/file") @@ -1838,8 +1831,7 @@ mod tests { fn association_shared_buffer_sequence_stages_random_data(broker: &BrokerCore) { let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let shared_buffers = test_shared_buffers(); shared_buffers .write(SharedBufferSlotIndex(3), &[0xa5; 4]) @@ -1894,8 +1886,7 @@ mod tests { ) { let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let shared_buffers = test_shared_buffers(); shared_buffers .write(SharedBufferSlotIndex(7), b"error") @@ -2105,11 +2096,11 @@ mod tests { }] ); assert!(!setup_called.get()); - let (process, initial_thread_id) = broker + let process = broker .create_process(CallerCredential::Unauthenticated, None) .unwrap(); assert_eq!(process.id(), root_process_id(5)); - assert_eq!(initial_thread_id, ThreadId(6)); + assert_eq!(process.initial_thread_id(), ThreadId(6)); } fn test_channel_rejects_active_request_before_negotiation(broker: &BrokerCore) { @@ -2321,8 +2312,7 @@ mod tests { fn active_request_closes_object_reference(broker: &BrokerCore) { let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let response = handle_test_request( &process, BrokerOperation::Event(EventRequest::Create(CreateEventRequest { @@ -2354,8 +2344,7 @@ mod tests { fn active_request_allocates_and_releases_thread_id(broker: &BrokerCore) { let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let response = handle_test_request(&process, BrokerOperation::CreateThread); let BrokerResult::ThreadCreated(thread_id) = response else { panic!("unexpected thread-ID allocation response: {response:?}"); @@ -2374,8 +2363,7 @@ mod tests { fn association_shared_buffer_sequences_stage_pipe_data(broker: &BrokerCore) { let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let memory = TestSharedMemory::new(SHARED_BUFFER_POOL_SIZE); let shared_buffers = SharedBufferPool::new(memory.clone(), SHARED_BUFFER_LAYOUT).unwrap(); shared_buffers @@ -2436,8 +2424,7 @@ mod tests { fn association_shared_buffer_sequences_stage_socket_data(broker: &BrokerCore) { let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let shared_buffers = test_shared_buffers(); let created = handle_test_request_with_buffers( &process, @@ -2859,8 +2846,7 @@ mod tests { BrokerHostAssociation { process: broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0, + .unwrap(), shared_buffers, readiness_sink: test_readiness_sink(), state: SpinMutex::new(AssociationState { diff --git a/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs b/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs index a1bda8760..4ce729a0c 100644 --- a/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs +++ b/litebox_broker_platform_linux_userland/src/socket/tests/mod.rs @@ -379,8 +379,7 @@ fn directional_shutdown_survives_readiness_publication_failure() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { diff --git a/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs b/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs index 303c4f2db..03c901ae6 100644 --- a/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs +++ b/litebox_broker_platform_linux_userland/src/socket/tests/tcp.rs @@ -25,12 +25,10 @@ fn connected_guest_tcp_pair(port: u16) -> GuestTcpPair { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -157,8 +155,7 @@ fn reactor_drives_a_loopback_tcp_socket() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -487,8 +484,7 @@ fn external_tcp_deferred_abortive_close_resets_peer() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -533,8 +529,7 @@ fn external_tcp_gateway_uses_host_loopback_and_keeps_guest_identity() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -610,8 +605,7 @@ fn external_tcp_route_keeps_guest_private_identity() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -652,8 +646,7 @@ fn tcp_connect_to_zero_port_returns_an_ordinary_socket_outcome() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); let socket = create_socket(&process, Arc::new(TestReadinessSink { published, retired })); @@ -691,8 +684,7 @@ fn tcp_receive_survives_readiness_publication_failure() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -754,8 +746,7 @@ fn tcp_status_publication_failure_preserves_consumed_error() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -829,8 +820,7 @@ fn external_tcp_readiness_failure_does_not_fail_shared_reactor() { let process_a = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published_a, publications_a) = channel(); let (retired_a, _retirements_a) = channel(); let readiness_a = Arc::new(FailingReadinessSink { @@ -857,8 +847,7 @@ fn external_tcp_readiness_failure_does_not_fail_shared_reactor() { // per-association sinks. let process_b = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published_b, publications_b) = channel(); let (retired_b, _retirements_b) = channel(); let readiness_b = Arc::new(FailingReadinessSink { @@ -954,8 +943,7 @@ fn external_tcp_connect_completion_readiness_failure_does_not_fail_shared_reacto .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -1042,8 +1030,7 @@ fn exhausted_tcp_peek_cache_refreshes_before_terminal_eof() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1126,12 +1113,10 @@ fn accepted_guest_tcp_close_with_unread_data_preserves_reset() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1486,12 +1471,10 @@ fn guest_tcp_namespace_routes_across_processs_and_hides_private_backend() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let client_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1630,12 +1613,10 @@ fn tcp_exact_bindings_coexist_and_wildcard_accepts_concrete_destinations() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1784,12 +1765,10 @@ fn connector_and_process_teardown_clean_bounded_pending_state() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1848,8 +1827,7 @@ fn connector_and_process_teardown_clean_bounded_pending_state() { let final_connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let final_connector = create_socket(&final_connector_process, readiness); assert!(matches!( litebox_broker_core::socket::connect( @@ -1893,12 +1871,10 @@ fn graceful_connector_close_preserves_late_accept_and_eof() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1989,12 +1965,10 @@ fn guest_tcp_zero_backlog_accepts_one_unspecified_destination() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, _publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2079,12 +2053,10 @@ fn guest_tcp_backlog_relisten_and_fifo_are_bounded() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2200,12 +2172,10 @@ fn guest_tcp_stream_preserves_options_peek_waitall_and_half_close() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2662,12 +2632,10 @@ fn guest_tcp_connect_publication_failure_purges_committed_queue() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, _publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -2719,12 +2687,10 @@ fn guest_tcp_accept_publication_failure_purges_registered_endpoint() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -2786,12 +2752,10 @@ fn queued_guest_accept_transfers_capacity_without_global_growth() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, _publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2814,8 +2778,7 @@ fn queued_guest_accept_transfers_capacity_without_global_growth() { assert_eq!(provider.reactor.queued_guest_connection_count(), 1); let capacity_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let _global_capacity = create_socket(&capacity_process, readiness.clone()); assert_eq!( litebox_broker_core::socket::create( @@ -2849,12 +2812,10 @@ fn queued_guest_accept_rejects_exhausted_listener_process_capacity() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, _publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2908,12 +2869,10 @@ fn abortive_connector_close_releases_descriptor_capacity() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2991,12 +2950,10 @@ fn stop_listening_cleanup_survives_readiness_failure() { .unwrap(); let listener_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let connector_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -3077,8 +3034,7 @@ fn reactor_drives_a_loopback_tcp_listener() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); diff --git a/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs b/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs index f18466413..3421e967a 100644 --- a/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs +++ b/litebox_broker_platform_linux_userland/src/socket/tests/udp.rs @@ -49,8 +49,7 @@ fn udp_gateway_translates_sources_filters_spoofing_and_reuses_endpoint() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let socket = create_udp_socket(&process, Arc::new(TestReadinessSink { published, retired })); @@ -135,8 +134,7 @@ fn connected_udp_gateway_preserves_guest_visible_mapping() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let socket = create_udp_socket(&process, Arc::new(TestReadinessSink { published, retired })); @@ -191,8 +189,7 @@ fn unmatched_guest_udp_destinations_fail_closed() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); let socket = create_udp_socket(&process, Arc::new(TestReadinessSink { published, retired })); @@ -236,8 +233,7 @@ fn failed_initial_udp_readiness_does_not_retain_process_state() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -273,12 +269,10 @@ fn guest_udp_readiness_failure_rolls_back_enqueue() { .unwrap(); let receiver_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let sender_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -372,8 +366,7 @@ fn external_udp_readiness_failure_does_not_fail_shared_reactor() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -485,8 +478,7 @@ fn udp_status_publication_failure_still_rearms_native_endpoint() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(FailingReadinessSink { @@ -559,8 +551,7 @@ fn udp_status_republishes_when_another_error_remains_pending() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -612,12 +603,10 @@ fn guest_udp_queue_pressure_drops_new_datagrams_successfully() { .unwrap(); let receiver_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let sender_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -705,8 +694,7 @@ fn udp_external_peer_authorization_is_bounded_without_eviction() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -798,8 +786,7 @@ fn reactor_preserves_udp_datagram_semantics() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1153,12 +1140,10 @@ fn guest_udp_namespace_routes_across_processes_and_filters_private_endpoints() { .unwrap(); let receiver_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let sender_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1419,12 +1404,10 @@ fn udp_exact_bindings_coexist_and_wildcard_covers_guest_addresses() { .unwrap(); let receiver_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let sender_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1609,8 +1592,7 @@ fn udp_native_endpoint_is_reused_and_retired() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, _publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1675,8 +1657,7 @@ fn udp_endpoint_staging_error_rolls_back_external_peer_reservation() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1714,12 +1695,10 @@ fn stale_udp_datagrams_are_not_relabelled_after_guest_port_reuse() { .unwrap(); let receiver_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let source_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1823,20 +1802,16 @@ fn udp_queued_datagrams_survive_source_process_teardown() { .unwrap(); let source_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let first_receiver_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let second_receiver_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let replacement_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -1972,12 +1947,10 @@ fn connected_guest_udp_enforces_barriers_peek_and_peer_generations() { .unwrap(); let first_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let second_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2106,8 +2079,7 @@ fn connected_guest_udp_filters_other_wildcard_peer_aliases() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2186,8 +2158,7 @@ fn wildcard_udp_reconnect_updates_guest_source_identity() { .unwrap(); let process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, _publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2274,12 +2245,10 @@ fn externally_connected_udp_preserves_guest_routing_identity() { .unwrap(); let source_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let receiver_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); @@ -2386,12 +2355,10 @@ fn internally_connected_udp_drains_external_datagrams_without_delivering_them() .unwrap(); let receiver_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let sender_process = broker .create_process(CallerCredential::Unauthenticated, None) - .unwrap() - .0; + .unwrap(); let (published, publications) = channel(); let (retired, _retirements) = channel(); let readiness = Arc::new(TestReadinessSink { published, retired }); diff --git a/litebox_broker_userland/src/process_launcher.rs b/litebox_broker_userland/src/process_launcher.rs index 4e61ac564..f355e9cb4 100644 --- a/litebox_broker_userland/src/process_launcher.rs +++ b/litebox_broker_userland/src/process_launcher.rs @@ -13,7 +13,6 @@ use litebox_broker_core::{ BrokerCore, BrokerError, BrokerProcess, CallerCredential, ProcessLifecycleSink, }; use litebox_broker_host::ProcessLauncher; -use litebox_broker_protocol::ThreadId; use litebox_broker_protocol::process::ProcessStartupData; use crate::runner::{RunnerCompletion, RunnerConfig, RunnerInstance}; @@ -28,27 +27,18 @@ pub(crate) struct UserlandProcessLauncher { /// Pending association for a broker-created runner process. pub(crate) struct PendingRunnerAssociation { pub(super) process: Arc, - initial_thread_id: ThreadId, data: Option, } impl PendingRunnerAssociation { - fn new( - process: Arc, - initial_thread_id: ThreadId, - data: Option, - ) -> Self { - Self { - process, - initial_thread_id, - data, - } + fn new(process: Arc, data: Option) -> Self { + Self { process, data } } pub(crate) fn into_process_and_startup( self, - ) -> ((Arc, ThreadId), Option) { - ((self.process, self.initial_thread_id), self.data) + ) -> (Arc, Option) { + (self.process, self.data) } } @@ -125,12 +115,11 @@ impl UserlandProcessLauncher { pub(crate) fn run_root(config: RunnerConfig, broker: &BrokerCore) -> IoResult { let launcher = Self::new(config.without_initial_arguments(), broker.clone()); - let (process, initial_thread_id) = launcher + let process = launcher .broker .create_process(CallerCredential::HostGuaranteed, None) .map_err(broker_io_error)?; - let association = - PendingRunnerAssociation::new(Arc::clone(&process), initial_thread_id, None); + let association = PendingRunnerAssociation::new(Arc::clone(&process), None); let (completion_sender, completion_receiver) = sync_channel(1); let startup = Arc::clone(&launcher).launch_runner(association, config, Some(completion_sender)); @@ -204,12 +193,11 @@ impl ProcessLauncher for UserlandProcessLauncher { fn launch( self: Arc, process: Arc, - initial_thread_id: ThreadId, data: ProcessStartupData, ) -> Result<(), BrokerError> { let config = self.started_runner_config.clone(); self.launch_runner( - PendingRunnerAssociation::new(process, initial_thread_id, Some(data)), + PendingRunnerAssociation::new(process, Some(data)), config, None, )