Skip to main content

liminal_server/server/connection/
supervisor.rs

1#[cfg(feature = "test-support")]
2#[path = "supervisor/console_for_tests.rs"]
3pub(super) mod console_for_tests;
4#[path = "supervisor/force_close.rs"]
5mod force_close;
6#[cfg(test)]
7#[path = "process/force_close_tests.rs"]
8mod force_close_tests;
9#[path = "supervisor/retirement.rs"]
10mod retirement;
11
12use retirement::NativeRetirements;
13
14#[path = "supervisor/routed_push.rs"]
15mod routed_push;
16#[path = "supervisor/tap_placements.rs"]
17mod tap_placements;
18use std::collections::HashMap;
19#[cfg(test)]
20use std::collections::VecDeque;
21use std::collections::hash_map::Entry;
22use std::net::{SocketAddr, TcpStream};
23use std::os::fd::RawFd;
24#[cfg(test)]
25use std::sync::Barrier;
26use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
27use std::sync::mpsc::{Receiver, RecvTimeoutError, Sender, TryRecvError, channel};
28use std::sync::{Arc, Condvar, Mutex, MutexGuard, OnceLock, PoisonError, Weak};
29use std::time::{Duration, Instant};
30
31use beamr::atom::{Atom, AtomTable};
32use beamr::module::ModuleRegistry;
33use beamr::native::native_process::NativeHandlerFactory;
34use beamr::process::ExitReason;
35use beamr::scheduler::{NativeBifs, ReadinessToken, Scheduler, SchedulerConfig, SchedulerServices};
36use beamr::timer::TimerRef;
37
38use liminal::protocol::{Frame, WorkerRefusal, WorkerRegistration};
39use liminal_protocol::wire::ConnectionIncarnation;
40
41use super::incarnation::ConnectionIncarnationAuthority;
42use super::loopback::{LoopbackConnectionProcess, LoopbackServerEnd};
43use super::notifier::ConnectionNotifier;
44use super::outbound::OutboundError;
45use super::process::ConnectionProcess;
46use super::refusal::AdmissionRefusal;
47#[cfg(any(test, feature = "test-support"))]
48use super::services::LiminalConnectionServices;
49use super::services::{ConnectionServices, build_connection_services};
50#[cfg(test)]
51use super::services::{SubsystemFactory, build_connection_services_via};
52use crate::ServerError;
53use crate::auth_pass::{PassPrincipal, PassVerifier};
54use crate::config::types::{AuthConfig, LimitsConfig, ServerConfig};
55use crate::health::AdmissionReadiness;
56use crate::server::mount::MountKind;
57use crate::server::participant::{
58    CandidateLaneListener, ConnectionFateClass, InstalledParticipantService,
59    ParticipantSemanticHandler, ParticipantServiceFatal,
60};
61use crate::server::shutdown::ShutdownHandle;
62use crate::server::signals::ServerSignals;
63
64const CONNECTION_SCHEDULER_THREADS: usize = 4;
65const CONNECTION_SHUTDOWN_CONTROL_ATOM: &str = "liminal_server_connection_shutdown_control";
66/// R6 (ยง1.2(4)): the single `READY` wake vocabulary for a connection. One atom;
67/// any marker (or N coalesced) triggers one full slice servicing all sources.
68const CONNECTION_READY_ATOM: &str = "liminal_server_connection_ready";
69
70#[path = "supervisor_fate.rs"]
71mod fate;
72use fate::ParkedConnectionFates;
73#[cfg(test)]
74#[path = "supervisor_fate_tests.rs"]
75mod fate_tests;
76#[path = "supervisor_lifecycle.rs"]
77mod lifecycle;
78#[path = "supervisor_reclaim.rs"]
79mod reclaim;
80#[cfg(test)]
81use reclaim::run_for_test as run_reclaim_reactor;
82#[path = "relay_pump.rs"]
83pub(super) mod relay_pump;
84#[cfg(test)]
85#[path = "../shutdown_store_tests.rs"]
86mod shutdown_store_tests;
87#[cfg(test)]
88#[path = "supervisor_shutdown_wake_tests.rs"]
89mod shutdown_wake_tests;
90#[cfg(test)]
91#[path = "supervisor_tests.rs"]
92mod tests;
93
94#[cfg(test)]
95#[path = "worker_refusal_tests.rs"]
96mod worker_refusal_tests;
97
98/// Supervisor that owns the beamr scheduler for per-connection processes.
99#[derive(Clone, Debug)]
100pub struct ConnectionSupervisor {
101    inner: Arc<SupervisorInner>,
102}
103
104use super::{service_directory, services, state, wake};
105use builder::{
106    ConnectionSupervisorBuilder, LysInstall, configured_authentication, configured_lys, install_lys,
107};
108#[cfg(test)]
109use handle::PushReplyFailure;
110use handle::{ConnectionHandle, PushReplyAwaiter};
111use inner::SupervisorInner;
112use push_types::{
113    PendingPush, PushBinding, PushReplyDisposition, PushSlotDisposition, PushSlotResolution,
114};
115use registry::{
116    ConnectionRecord, QueuedConnectionControl, ReadinessRegistration, Registry, lock, recover_lock,
117};
118use runtime::{
119    ActiveConnection, AdmissionReservation, ConnectionControl, ConnectionRuntime,
120    ConnectionRuntimeInstallation, ConnectionServiceInstallation,
121};
122#[cfg(test)]
123use runtime::{CloseEventFdProbe, PreWaitBarrier, ReclaimBarrier};
124
125#[path = "supervisor/builder.rs"]
126pub(super) mod builder;
127#[path = "supervisor/context_watch.rs"]
128pub(super) mod context_watch;
129#[path = "supervisor/handle.rs"]
130pub(super) mod handle;
131#[path = "supervisor/inner.rs"]
132mod inner;
133#[path = "supervisor/push_types.rs"]
134pub(super) mod push_types;
135#[path = "supervisor/registry.rs"]
136mod registry;
137#[path = "supervisor/runtime.rs"]
138pub(super) mod runtime;
139#[path = "supervisor/runtime_admission.rs"]
140mod runtime_admission;
141#[path = "supervisor/runtime_authority.rs"]
142mod runtime_authority;
143#[path = "supervisor/runtime_close.rs"]
144mod runtime_close;
145#[path = "supervisor/runtime_control.rs"]
146mod runtime_control;
147#[path = "supervisor/runtime_fate.rs"]
148mod runtime_fate;
149#[path = "supervisor/runtime_notifier.rs"]
150mod runtime_notifier;
151#[path = "supervisor/runtime_push_admission.rs"]
152mod runtime_push_admission;
153#[path = "supervisor/runtime_push_resolution.rs"]
154mod runtime_push_resolution;
155#[path = "supervisor/runtime_readiness.rs"]
156mod runtime_readiness;
157#[path = "supervisor/runtime_registry.rs"]
158mod runtime_registry;
159#[path = "supervisor/runtime_settlement.rs"]
160mod runtime_settlement;
161#[path = "supervisor/runtime_shutdown.rs"]
162mod runtime_shutdown;
163#[cfg(test)]
164#[path = "supervisor/runtime_test_barriers.rs"]
165mod runtime_test_barriers;
166#[cfg(test)]
167#[path = "supervisor/runtime_test_construction.rs"]
168mod runtime_test_construction;
169#[cfg(test)]
170#[path = "supervisor/runtime_test_observation.rs"]
171mod runtime_test_observation;
172#[cfg(test)]
173#[path = "supervisor/shutdown_notifier_tests.rs"]
174mod shutdown_notifier_tests;
175#[path = "supervisor/supervisor_authority.rs"]
176mod supervisor_authority;
177#[path = "supervisor/supervisor_config.rs"]
178mod supervisor_config;
179#[path = "supervisor/supervisor_connections.rs"]
180mod supervisor_connections;
181#[path = "supervisor/supervisor_push.rs"]
182mod supervisor_push;
183#[path = "supervisor/supervisor_shutdown.rs"]
184mod supervisor_shutdown;
185#[cfg(test)]
186#[path = "supervisor/supervisor_test_support.rs"]
187mod supervisor_test_support;
188
189#[test]
190fn host_fd_is_closed_before_connection_close_event_handoff()
191-> Result<(), Box<dyn std::error::Error>> {
192    use std::os::fd::AsRawFd;
193    let fixture = crate::server::self_streams::tests::R3Fixture::new()?;
194    let services: Arc<dyn ConnectionServices> = fixture.services;
195    let runtime = ConnectionRuntime::for_tests(services);
196    runtime
197        .signals
198        .set(ServerSignals::default())
199        .map_err(|_| "close-event signals already installed")?;
200    let listener = std::net::TcpListener::bind("127.0.0.1:0")?;
201    let client = TcpStream::connect(listener.local_addr()?)?;
202    let (server, address) = listener.accept()?;
203    let host_fd = server.as_raw_fd();
204    let positive_control = std::fs::File::open(format!("/dev/fd/{host_fd}"))?;
205    drop(positive_control);
206    runtime.register_record(1, Some(address), None, MountKind::Tcp, Some(server))?;
207    *runtime
208        .close_event_fd_probe
209        .lock()
210        .map_err(|error| error.to_string())? = CloseEventFdProbe::Armed;
211    let removed = runtime
212        .remove(1)
213        .ok_or("fd-owning connection was not removed")?;
214    let mut probe = runtime
215        .close_event_fd_probe
216        .lock()
217        .map_err(|error| error.to_string())?;
218    let CloseEventFdProbe::Observed(observed) =
219        std::mem::replace(&mut *probe, CloseEventFdProbe::Off)
220    else {
221        return Err("close-event handoff was not observed".into());
222    };
223    drop(probe);
224    assert!(
225        observed?,
226        "connection-close event was handed off while its host fd remained open"
227    );
228    assert!(removed.fd_guard.is_none());
229    drop(removed);
230    drop(client);
231    drop(listener);
232    Ok(())
233}