mz_environmentd/environmentd/
sys.rs
1use anyhow::Context;
13use nix::errno;
14use nix::sys::signal;
15use tracing::trace;
16
17#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "ios")))]
18pub fn adjust_rlimits() {
19 trace!("rlimit crate does not support this OS; not adjusting nofile limit");
20}
21
22#[cfg(any(target_os = "macos", target_os = "linux", target_os = "ios"))]
24pub fn adjust_rlimits() {
25 use rlimit::Resource;
26 use tracing::warn;
27
28 let (soft, hard) = match Resource::NOFILE.get() {
34 Ok(limits) => limits,
35 Err(e) => {
36 trace!("unable to read initial nofile rlimit: {}", e);
37 return;
38 }
39 };
40 trace!("initial nofile rlimit: ({}, {})", soft, hard);
41
42 #[cfg(target_os = "macos")]
43 let hard = {
44 use std::cmp;
45
46 use mz_ore::result::ResultExt;
47 use sysctl::Sysctl;
48
49 let res = sysctl::Ctl::new("kern.maxfilesperproc")
54 .and_then(|ctl| ctl.value())
55 .map_err_to_string_with_causes()
56 .and_then(|v| match v {
57 sysctl::CtlValue::Int(v) => u64::try_from(v)
58 .map_err(|_| format!("kern.maxfilesperproc unexpectedly negative: {}", v)),
59 o => Err(format!("unexpected sysctl value type: {:?}", o)),
60 });
61 match res {
62 Ok(v) => {
63 trace!("sysctl kern.maxfilesperproc hard limit: {}", v);
64 cmp::min(v, hard)
65 }
66 Err(e) => {
67 trace!("error while reading sysctl: {}", e);
68 hard
69 }
70 }
71 };
72
73 trace!("attempting to adjust nofile rlimit to ({0}, {0})", hard);
74 if let Err(e) = Resource::NOFILE.set(hard, hard) {
75 trace!("error adjusting nofile rlimit: {}", e);
76 return;
77 }
78
79 let (soft, hard) = match Resource::NOFILE.get() {
82 Ok(limits) => limits,
83 Err(e) => {
84 trace!("unable to read adjusted nofile rlimit: {}", e);
85 return;
86 }
87 };
88 trace!("adjusted nofile rlimit: ({}, {})", soft, hard);
89
90 const RECOMMENDED_SOFT: u64 = 1024;
91 if soft < RECOMMENDED_SOFT {
92 warn!(
93 "soft nofile rlimit ({}) is dangerously low; at least {} is recommended",
94 soft, RECOMMENDED_SOFT
95 )
96 }
97}
98
99pub fn enable_sigusr2_coverage_dump() -> Result<(), anyhow::Error> {
100 let action = signal::SigAction::new(
101 signal::SigHandler::Handler(handle_sigusr2_signal),
102 signal::SaFlags::SA_NODEFER | signal::SaFlags::SA_ONSTACK,
103 signal::SigSet::empty(),
104 );
105
106 unsafe { signal::sigaction(signal::SIGUSR2, &action) }
107 .context("failed to install SIGUSR2 handler")?;
108
109 Ok(())
110}
111
112pub fn enable_termination_signal_cleanup() -> Result<(), anyhow::Error> {
113 let action = signal::SigAction::new(
114 signal::SigHandler::Handler(handle_termination_signal),
115 signal::SaFlags::SA_NODEFER | signal::SaFlags::SA_ONSTACK,
116 signal::SigSet::empty(),
117 );
118
119 for signum in &[
120 signal::SIGHUP,
121 signal::SIGINT,
122 signal::SIGALRM,
123 signal::SIGTERM,
124 signal::SIGUSR1,
125 ] {
126 unsafe { signal::sigaction(*signum, &action) }
127 .with_context(|| format!("failed to install handler for {}", signum))?;
128 }
129
130 Ok(())
131}
132
133unsafe extern "C" {
134 fn __llvm_profile_write_file() -> libc::c_int;
135}
136
137extern "C" fn handle_sigusr2_signal(_: i32) {
138 let _ = unsafe { __llvm_profile_write_file() };
139}
140
141extern "C" fn handle_termination_signal(signum: i32) {
142 let _ = unsafe { __llvm_profile_write_file() };
143
144 let action = signal::SigAction::new(
145 signal::SigHandler::SigDfl,
146 signal::SaFlags::SA_NODEFER | signal::SaFlags::SA_ONSTACK,
147 signal::SigSet::empty(),
148 );
149 unsafe { signal::sigaction(signum.try_into().unwrap(), &action) }
150 .unwrap_or_else(|_| panic!("failed to uninstall handler for {}", signum));
151
152 let ret = unsafe { libc::raise(signum) };
153 if ret == -1 {
154 let errno = errno::from_i32(errno::errno());
155 panic!("failed to re-raise signal {}: {}", signum, errno);
156 }
157}