Skip to main content

liminal_server/server/connection/
supervisor.rs

1#[path = "supervisor/force_close.rs"]
2mod force_close;
3#[cfg(test)]
4#[path = "process/force_close_tests.rs"]
5mod force_close_tests;
6#[path = "supervisor/retirement.rs"]
7mod retirement;
8
9use retirement::NativeRetirements;
10
11#[path = "supervisor/routed_push.rs"]
12mod routed_push;
13#[path = "supervisor/tap_placements.rs"]
14mod tap_placements;
15use std::collections::HashMap;
16#[cfg(test)]
17use std::collections::VecDeque;
18use std::collections::hash_map::Entry;
19use std::net::{SocketAddr, TcpStream};
20use std::os::fd::RawFd;
21#[cfg(test)]
22use std::sync::Barrier;
23use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
24use std::sync::mpsc::{Receiver, RecvTimeoutError, Sender, TryRecvError, channel};
25use std::sync::{Arc, Condvar, Mutex, MutexGuard, OnceLock, PoisonError, Weak};
26use std::time::{Duration, Instant};
27
28use beamr::atom::{Atom, AtomTable};
29use beamr::module::ModuleRegistry;
30use beamr::native::native_process::NativeHandlerFactory;
31use beamr::process::ExitReason;
32use beamr::scheduler::{NativeBifs, ReadinessToken, Scheduler, SchedulerConfig, SchedulerServices};
33use beamr::timer::TimerRef;
34
35use liminal::protocol::{Frame, WorkerRefusal, WorkerRegistration};
36use liminal_protocol::wire::ConnectionIncarnation;
37
38use super::incarnation::ConnectionIncarnationAuthority;
39use super::loopback::{LoopbackConnectionProcess, LoopbackServerEnd};
40use super::notifier::ConnectionNotifier;
41use super::outbound::OutboundError;
42use super::process::ConnectionProcess;
43use super::refusal::AdmissionRefusal;
44#[cfg(any(test, feature = "test-support"))]
45use super::services::LiminalConnectionServices;
46use super::services::{ConnectionServices, build_connection_services};
47#[cfg(test)]
48use super::services::{SubsystemFactory, build_connection_services_via};
49use crate::ServerError;
50use crate::auth_pass::{PassPrincipal, PassVerifier};
51use crate::config::types::{AuthConfig, LimitsConfig, ServerConfig};
52use crate::health::AdmissionReadiness;
53use crate::server::mount::MountKind;
54use crate::server::participant::{
55    CandidateLaneListener, ConnectionFateClass, InstalledParticipantService,
56    ParticipantSemanticHandler, ParticipantServiceFatal,
57};
58use crate::server::shutdown::ShutdownHandle;
59use crate::server::signals::ServerSignals;
60
61const CONNECTION_SCHEDULER_THREADS: usize = 4;
62const CONNECTION_SHUTDOWN_CONTROL_ATOM: &str = "liminal_server_connection_shutdown_control";
63/// R6 (ยง1.2(4)): the single `READY` wake vocabulary for a connection. One atom;
64/// any marker (or N coalesced) triggers one full slice servicing all sources.
65const CONNECTION_READY_ATOM: &str = "liminal_server_connection_ready";
66
67#[path = "supervisor_fate.rs"]
68mod fate;
69use fate::ParkedConnectionFates;
70#[cfg(test)]
71#[path = "supervisor_fate_tests.rs"]
72mod fate_tests;
73#[path = "supervisor_lifecycle.rs"]
74mod lifecycle;
75#[path = "supervisor_reclaim.rs"]
76mod reclaim;
77#[cfg(test)]
78use reclaim::run_for_test as run_reclaim_reactor;
79#[path = "relay_pump.rs"]
80pub(super) mod relay_pump;
81#[cfg(test)]
82#[path = "../shutdown_store_tests.rs"]
83mod shutdown_store_tests;
84#[cfg(test)]
85#[path = "supervisor_shutdown_wake_tests.rs"]
86mod shutdown_wake_tests;
87#[cfg(test)]
88#[path = "supervisor_tests.rs"]
89mod tests;
90
91#[cfg(test)]
92#[path = "worker_refusal_tests.rs"]
93mod worker_refusal_tests;
94
95/// Supervisor that owns the beamr scheduler for per-connection processes.
96#[derive(Clone, Debug)]
97pub struct ConnectionSupervisor {
98    inner: Arc<SupervisorInner>,
99}
100
101use super::{service_directory, services, state, wake};
102use builder::{
103    ConnectionSupervisorBuilder, LysInstall, configured_authentication, configured_lys, install_lys,
104};
105#[cfg(test)]
106use handle::PushReplyFailure;
107use handle::{ConnectionHandle, PushReplyAwaiter};
108use inner::SupervisorInner;
109use push_types::{
110    PendingPush, PushBinding, PushReplyDisposition, PushSlotDisposition, PushSlotResolution,
111};
112use registry::{
113    ConnectionRecord, QueuedConnectionControl, ReadinessRegistration, Registry, lock, recover_lock,
114};
115use runtime::{
116    ActiveConnection, AdmissionReservation, ConnectionControl, ConnectionRuntime,
117    ConnectionRuntimeInstallation, ConnectionServiceInstallation,
118};
119#[cfg(test)]
120use runtime::{CloseEventFdProbe, PreWaitBarrier, ReclaimBarrier};
121
122#[path = "supervisor/builder.rs"]
123pub(super) mod builder;
124#[path = "supervisor/context_watch.rs"]
125pub(super) mod context_watch;
126#[path = "supervisor/handle.rs"]
127pub(super) mod handle;
128#[path = "supervisor/inner.rs"]
129mod inner;
130#[path = "supervisor/push_types.rs"]
131pub(super) mod push_types;
132#[path = "supervisor/registry.rs"]
133mod registry;
134#[path = "supervisor/runtime.rs"]
135pub(super) mod runtime;
136#[path = "supervisor/runtime_admission.rs"]
137mod runtime_admission;
138#[path = "supervisor/runtime_authority.rs"]
139mod runtime_authority;
140#[path = "supervisor/runtime_close.rs"]
141mod runtime_close;
142#[path = "supervisor/runtime_control.rs"]
143mod runtime_control;
144#[path = "supervisor/runtime_fate.rs"]
145mod runtime_fate;
146#[path = "supervisor/runtime_notifier.rs"]
147mod runtime_notifier;
148#[path = "supervisor/runtime_push_admission.rs"]
149mod runtime_push_admission;
150#[path = "supervisor/runtime_push_resolution.rs"]
151mod runtime_push_resolution;
152#[path = "supervisor/runtime_readiness.rs"]
153mod runtime_readiness;
154#[path = "supervisor/runtime_registry.rs"]
155mod runtime_registry;
156#[path = "supervisor/runtime_settlement.rs"]
157mod runtime_settlement;
158#[path = "supervisor/runtime_shutdown.rs"]
159mod runtime_shutdown;
160#[cfg(test)]
161#[path = "supervisor/runtime_test_barriers.rs"]
162mod runtime_test_barriers;
163#[cfg(test)]
164#[path = "supervisor/runtime_test_construction.rs"]
165mod runtime_test_construction;
166#[cfg(test)]
167#[path = "supervisor/runtime_test_observation.rs"]
168mod runtime_test_observation;
169#[cfg(test)]
170#[path = "supervisor/shutdown_notifier_tests.rs"]
171mod shutdown_notifier_tests;
172#[path = "supervisor/supervisor_authority.rs"]
173mod supervisor_authority;
174#[path = "supervisor/supervisor_config.rs"]
175mod supervisor_config;
176#[path = "supervisor/supervisor_connections.rs"]
177mod supervisor_connections;
178#[path = "supervisor/supervisor_push.rs"]
179mod supervisor_push;
180#[path = "supervisor/supervisor_shutdown.rs"]
181mod supervisor_shutdown;
182#[cfg(test)]
183#[path = "supervisor/supervisor_test_support.rs"]
184mod supervisor_test_support;
185#[cfg(test)]
186#[path = "supervisor/worker_refusal_ticket_fixture.rs"]
187mod worker_refusal_ticket_fixture;
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}