Skip to main content

melin_server_runtime/
process.rs

1//! Process-level setup for latency-sensitive servers: signal handling
2//! and memory locking. Generic OS plumbing — no application coupling.
3
4use std::sync::Arc;
5use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
6
7/// Pointer to the shared shutdown flag, set once before signals can fire.
8/// `AtomicUsize` stores the raw pointer as an integer — signal-safe.
9static SHUTDOWN_PTR: AtomicUsize = AtomicUsize::new(0);
10
11/// Signal handler for SIGINT/SIGTERM. Sets the shutdown flag.
12/// Second signal force-exits (user is impatient).
13extern "C" fn signal_handler(_sig: libc::c_int) {
14    let ptr = SHUTDOWN_PTR.load(Ordering::Relaxed);
15    if ptr != 0 {
16        let flag = unsafe { &*(ptr as *const AtomicBool) };
17        if flag.swap(true, Ordering::Relaxed) {
18            unsafe { libc::_exit(1) };
19        }
20    }
21}
22
23/// Install SIGINT/SIGTERM handlers that flip `shutdown` on first signal
24/// and force-exit on the second. The caller must keep the `Arc` alive
25/// for the program's lifetime — we publish its pointer to a signal-safe
26/// static so the handler can reach the flag.
27pub fn install_shutdown_handler(shutdown: &Arc<AtomicBool>) {
28    SHUTDOWN_PTR.store(Arc::as_ptr(shutdown) as usize, Ordering::Relaxed);
29    unsafe {
30        libc::signal(
31            libc::SIGINT,
32            signal_handler as *const () as libc::sighandler_t,
33        );
34        libc::signal(
35            libc::SIGTERM,
36            signal_handler as *const () as libc::sighandler_t,
37        );
38    }
39}
40
41/// Pin the entire process address space into RAM with `mlockall`.
42///
43/// Prevents the kernel from faulting out engine pages under memory
44/// pressure, which otherwise surfaces as 100µs–10ms tail spikes.
45/// Best-effort: requires `CAP_IPC_LOCK` (or root) and a sufficient
46/// `RLIMIT_MEMLOCK`. Logs a warning and continues on failure.
47pub fn try_lock_memory() {
48    let unlim = libc::rlimit {
49        rlim_cur: libc::RLIM_INFINITY,
50        rlim_max: libc::RLIM_INFINITY,
51    };
52    let setrlimit_rc = unsafe { libc::setrlimit(libc::RLIMIT_MEMLOCK, &unlim) };
53    if setrlimit_rc != 0 {
54        let err = std::io::Error::last_os_error();
55        tracing::warn!(
56            error = %err,
57            "could not raise RLIMIT_MEMLOCK; mlockall may fail or be capped"
58        );
59    }
60
61    let rc = unsafe { libc::mlockall(libc::MCL_CURRENT | libc::MCL_FUTURE) };
62    if rc == 0 {
63        tracing::info!("mlockall(MCL_CURRENT | MCL_FUTURE) succeeded");
64    } else {
65        let err = std::io::Error::last_os_error();
66        tracing::warn!(
67            error = %err,
68            "mlockall failed; running without memory lock — tail latency may be affected"
69        );
70    }
71}