#![doc(html_root_url = "https://docs.rs/jemalloc-ctl/0.1")]
#![warn(missing_docs)]
extern crate jemalloc_sys;
extern crate libc;
#[cfg(test)]
extern crate jemallocator;
#[cfg(test)]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
use libc::{c_char, c_int};
use std::ffi::CStr;
use std::io;
use std::mem;
use std::ptr;
pub mod arenas;
pub mod config;
pub mod opt;
pub mod stats;
pub mod stats_print;
pub mod thread;
unsafe fn name_to_mib(name: *const c_char, mib: &mut [usize]) -> io::Result<()> {
let mut len = mib.len();
cvt(jemalloc_sys::mallctlnametomib(
name,
mib.as_mut_ptr(),
&mut len,
))?;
debug_assert_eq!(mib.len(), len);
Ok(())
}
unsafe fn get_mib<T>(mib: &[usize]) -> io::Result<T> {
let mut value = mem::uninitialized::<T>();
let mut len = mem::size_of::<T>();
cvt(jemalloc_sys::mallctlbymib(
mib.as_ptr(),
mib.len(),
&mut value as *mut _ as *mut _,
&mut len,
ptr::null_mut(),
0,
))?;
debug_assert_eq!(len, mem::size_of::<T>());
Ok(value)
}
unsafe fn get<T>(name: *const c_char) -> io::Result<T> {
let mut value = mem::uninitialized::<T>();
let mut len = mem::size_of::<T>();
cvt(jemalloc_sys::mallctl(
name,
&mut value as *mut _ as *mut _,
&mut len,
ptr::null_mut(),
0,
))?;
debug_assert_eq!(len, mem::size_of::<T>());
Ok(value)
}
unsafe fn get_str_mib(mib: &[usize]) -> io::Result<&'static str> {
let ptr: *const c_char = get_mib(mib)?;
let cstr = CStr::from_ptr(ptr);
cstr.to_str()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
}
unsafe fn get_str(name: *const c_char) -> io::Result<&'static str> {
let ptr: *const c_char = get(name)?;
let cstr = CStr::from_ptr(ptr);
cstr.to_str()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
}
unsafe fn set_mib<T>(mib: &[usize], mut value: T) -> io::Result<()> {
cvt(jemalloc_sys::mallctlbymib(
mib.as_ptr(),
mib.len(),
ptr::null_mut(),
ptr::null_mut(),
&mut value as *mut _ as *mut _,
mem::size_of::<T>(),
))
}
unsafe fn set<T>(name: *const c_char, mut value: T) -> io::Result<()> {
cvt(jemalloc_sys::mallctl(
name,
ptr::null_mut(),
ptr::null_mut(),
&mut value as *mut _ as *mut _,
mem::size_of::<T>(),
))
}
unsafe fn get_set_mib<T>(mib: &[usize], mut value: T) -> io::Result<T> {
let mut len = mem::size_of::<T>();
cvt(jemalloc_sys::mallctlbymib(
mib.as_ptr(),
mib.len(),
&mut value as *mut _ as *mut _,
&mut len,
&mut value as *mut _ as *mut _,
len,
))?;
debug_assert_eq!(len, mem::size_of::<T>());
Ok(value)
}
unsafe fn get_set<T>(name: *const c_char, mut value: T) -> io::Result<T> {
let mut len = mem::size_of::<T>();
cvt(jemalloc_sys::mallctl(
name,
&mut value as *mut _ as *mut _,
&mut len,
&mut value as *mut _ as *mut _,
len,
))?;
debug_assert_eq!(len, mem::size_of::<T>());
Ok(value)
}
fn cvt(ret: c_int) -> io::Result<()> {
if ret == 0 {
Ok(())
} else {
Err(io::Error::from_raw_os_error(ret as i32))
}
}
const VERSION: *const c_char = b"version\0" as *const _ as *const _;
pub fn version() -> io::Result<&'static str> {
unsafe { get_str(VERSION) }
}
#[derive(Copy, Clone)]
pub struct Version([usize; 1]);
impl Version {
pub fn new() -> io::Result<Version> {
let mut mib = [0; 1];
unsafe {
name_to_mib(VERSION, &mut mib)?;
}
Ok(Version(mib))
}
pub fn get(&self) -> io::Result<&'static str> {
unsafe { get_str_mib(&self.0) }
}
}
const EPOCH: *const c_char = b"epoch\0" as *const _ as *const _;
pub fn epoch() -> io::Result<u64> {
unsafe { get_set(EPOCH, 1) }
}
#[derive(Copy, Clone)]
pub struct Epoch([usize; 1]);
impl Epoch {
pub fn new() -> io::Result<Epoch> {
let mut mib = [0; 1];
unsafe {
name_to_mib(EPOCH, &mut mib)?;
}
Ok(Epoch(mib))
}
pub fn advance(&self) -> io::Result<u64> {
unsafe { get_set_mib(&self.0, 1) }
}
}
const BACKGROUND_THREAD: *const c_char = b"background_thread\0" as *const _ as *const _;
pub fn background_thread() -> io::Result<bool> {
unsafe { get(BACKGROUND_THREAD) }
}
pub fn set_background_thread(background_thread: bool) -> io::Result<()> {
unsafe { set(BACKGROUND_THREAD, background_thread) }
}
#[derive(Copy, Clone)]
pub struct BackgroundThread([usize; 1]);
impl BackgroundThread {
pub fn new() -> io::Result<BackgroundThread> {
let mut mib = [0; 1];
unsafe {
name_to_mib(BACKGROUND_THREAD, &mut mib)?;
}
Ok(BackgroundThread(mib))
}
pub fn get(&self) -> io::Result<bool> {
unsafe { get_mib(&self.0) }
}
pub fn set(&self, background_thread: bool) -> io::Result<()> {
unsafe { set_mib(&self.0, background_thread) }
}
}
const MAX_BACKGROUND_THREADS: *const c_char = b"max_background_threads\0" as *const _ as *const _;
pub fn max_background_threads() -> io::Result<usize> {
unsafe { get(MAX_BACKGROUND_THREADS) }
}
pub fn set_max_background_threads(max_background_threads: usize) -> io::Result<()> {
unsafe { set(MAX_BACKGROUND_THREADS, max_background_threads) }
}
#[derive(Copy, Clone)]
pub struct MaxBackgroundThreads([usize; 1]);
impl MaxBackgroundThreads {
pub fn new() -> io::Result<MaxBackgroundThreads> {
let mut mib = [0; 1];
unsafe {
name_to_mib(MAX_BACKGROUND_THREADS, &mut mib)?;
}
Ok(MaxBackgroundThreads(mib))
}
pub fn get(&self) -> io::Result<usize> {
unsafe { get_mib(&self.0) }
}
pub fn set(&self, max_background_threads: usize) -> io::Result<()> {
unsafe { set_mib(&self.0, max_background_threads) }
}
}