use std::env;
use std::fmt::Display;
use std::fmt::Write;
use std::os::unix::prelude::CommandExt;
use std::process::Command;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize, Default)]
pub struct Jemalloc {
#[serde(default)]
pub background_thread: bool,
pub max_background_threads: Option<u32>,
pub number_of_arenas: Option<u32>,
}
const POSSIBLE_MALLOC_CONF_ENVIRONMENT_VARIABLES: &[&str] = &["MALLOC_CONF", "_RJEM_MALLOC_CONF"];
pub const fn is_background_thread_supported() -> bool {
if cfg!(target_env = "musl") {
return false;
}
if cfg!(target_os = "macos") {
return false;
}
true
}
pub fn apply_config(config: &Jemalloc, f: impl FnOnce(&str)) -> ! {
let malloc_conf = config.to_config();
let mut args = env::args_os();
let program = args.next().expect("Process name");
let mut cmd = Command::new(program);
cmd.args(args);
for name in POSSIBLE_MALLOC_CONF_ENVIRONMENT_VARIABLES {
cmd.env(name, &malloc_conf);
}
f(&malloc_conf);
let err = cmd.exec();
panic!("jemalloc: exec error: {:?}", err);
}
pub fn is_configured() -> bool {
POSSIBLE_MALLOC_CONF_ENVIRONMENT_VARIABLES
.iter()
.any(|name| env::var_os(name).is_some())
}
impl Jemalloc {
pub fn to_config(&self) -> String {
let mut config = String::with_capacity(64);
config.push_str("abort_conf:true");
let mut write_config = |key: &str, value: &dyn Display| {
write!(&mut config, ",{}:{}", key, value)
.expect("a Display implementation returned an error unexpectedly");
};
if self.background_thread {
}
if let Some(v) = self.max_background_threads {
write_config("max_background_threads", &v);
}
if let Some(v) = self.number_of_arenas {
write_config("narenas", &v);
}
config
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn jemalloc_to_config() {
let val = Jemalloc {
background_thread: false,
max_background_threads: None,
number_of_arenas: None,
};
assert_eq!(val.to_config(), "abort_conf:true");
let val = Jemalloc {
background_thread: false,
max_background_threads: None,
number_of_arenas: Some(16),
};
assert_eq!(val.to_config(), "abort_conf:true,narenas:16");
let val = Jemalloc {
background_thread: true,
max_background_threads: None,
number_of_arenas: None,
};
assert_eq!(val.to_config(), "abort_conf:true");
let val = Jemalloc {
background_thread: false,
max_background_threads: Some(4),
number_of_arenas: None,
};
assert_eq!(val.to_config(), "abort_conf:true,max_background_threads:4");
let val = Jemalloc {
background_thread: true,
max_background_threads: Some(8),
number_of_arenas: Some(64),
};
assert_eq!(
val.to_config(),
"abort_conf:true,max_background_threads:8,narenas:64"
);
}
}