make the API of jemalloc_ctl sound

This commit is contained in:
gnzlbg 2018-11-08 16:44:12 +01:00 committed by gnzlbg
parent 034067f951
commit 3b40f07216
11 changed files with 784 additions and 218 deletions

View File

@ -1,8 +1,8 @@
//! Arena operations.
use error::Result;
use keys::{Access, IntoName, Mib};
use libc::c_uint;
use raw::{get, get_mib, name_to_mib};
const NARENAS: &[u8] = b"arenas.narenas\0";
@ -25,7 +25,7 @@ const NARENAS: &[u8] = b"arenas.narenas\0";
/// }
/// ```
pub fn narenas() -> Result<c_uint> {
get(NARENAS)
NARENAS.name().read()
}
/// A type providing access to the current limit on the number of arenas.
@ -48,18 +48,17 @@ pub fn narenas() -> Result<c_uint> {
/// }
/// ```
#[derive(Copy, Clone)]
pub struct NArenas([usize; 2]);
pub struct NArenas(Mib<[usize; 2]>);
impl NArenas {
/// Returns a new `NArenas`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(NARENAS, &mut mib)?;
let mib = NARENAS.name().mib()?;
Ok(NArenas(mib))
}
/// Returns the maximum number of arenas.
pub fn get(self) -> Result<c_uint> {
get_mib(&self.0)
self.0.read()
}
}

View File

@ -1,7 +1,7 @@
//! Background thread operations.
use error::Result;
use raw::{get, get_mib, name_to_mib, set, set_mib};
use keys::{Access, IntoName, Mib};
const BACKGROUND_THREAD: &[u8] = b"background_thread\0";
@ -27,7 +27,7 @@ const BACKGROUND_THREAD: &[u8] = b"background_thread\0";
/// }
/// ```
pub fn background_thread() -> Result<bool> {
get(BACKGROUND_THREAD)
BACKGROUND_THREAD.name().read()
}
/// Enables or disables internal background worker threads.
@ -51,7 +51,7 @@ pub fn background_thread() -> Result<bool> {
/// }
/// ```
pub fn set_background_thread(background_thread: bool) -> Result<()> {
set(BACKGROUND_THREAD, background_thread)
BACKGROUND_THREAD.name().write(background_thread)
}
/// A type providing access to the state of internal background worker threads.
@ -77,24 +77,23 @@ pub fn set_background_thread(background_thread: bool) -> Result<()> {
/// }
/// ```
#[derive(Copy, Clone)]
pub struct BackgroundThread([usize; 1]);
pub struct BackgroundThread(Mib<[usize; 1]>);
impl BackgroundThread {
/// Returns a new `BackgroundThread`.
pub fn new() -> Result<Self> {
let mut mib = [0; 1];
name_to_mib(BACKGROUND_THREAD, &mut mib)?;
let mib = BACKGROUND_THREAD.name().mib()?;
Ok(BackgroundThread(mib))
}
/// Returns the current background thread state.
pub fn get(self) -> Result<bool> {
get_mib(&self.0)
self.0.read()
}
/// Sets the background thread state.
pub fn set(self, background_thread: bool) -> Result<()> {
set_mib(&self.0, background_thread)
self.0.write(background_thread)
}
}
@ -118,7 +117,7 @@ const MAX_BACKGROUND_THREADS: &[u8] = b"max_background_threads\0";
/// }
/// ```
pub fn max_background_threads() -> Result<usize> {
get(MAX_BACKGROUND_THREADS)
MAX_BACKGROUND_THREADS.name().read()
}
/// Sets the maximum number of background threads that will be created.
@ -138,7 +137,7 @@ pub fn max_background_threads() -> Result<usize> {
/// }
/// ```
pub fn set_max_background_threads(max_background_threads: usize) -> Result<()> {
set(MAX_BACKGROUND_THREADS, max_background_threads)
MAX_BACKGROUND_THREADS.name().write(max_background_threads)
}
/// A type providing access to the maximum number of background threads that
@ -161,23 +160,22 @@ pub fn set_max_background_threads(max_background_threads: usize) -> Result<()> {
/// }
/// ```
#[derive(Copy, Clone)]
pub struct MaxBackgroundThreads([usize; 1]);
pub struct MaxBackgroundThreads(Mib<[usize; 1]>);
impl MaxBackgroundThreads {
/// Returns a new `MaxBackgroundThreads`.
pub fn new() -> Result<Self> {
let mut mib = [0; 1];
name_to_mib(MAX_BACKGROUND_THREADS, &mut mib)?;
let mib = MAX_BACKGROUND_THREADS.name().mib()?;
Ok(MaxBackgroundThreads(mib))
}
/// Returns the current background thread limit.
pub fn get(self) -> Result<usize> {
get_mib(&self.0)
self.0.read()
}
/// Sets the background thread limit.
pub fn set(self, max_background_threads: usize) -> Result<()> {
set_mib(&self.0, max_background_threads)
self.0.write(max_background_threads)
}
}

View File

@ -1,6 +1,6 @@
//! Information about the jemalloc compile-time configuration
use error::Result;
use raw::{get_str, get_str_mib, name_to_mib};
use keys::{Access, IntoName, MibStr};
const MALLOC_CONF: &[u8] = b"config.malloc_conf\0";
@ -26,7 +26,7 @@ const MALLOC_CONF: &[u8] = b"config.malloc_conf\0";
/// }
/// ```
pub fn malloc_conf() -> Result<&'static str> {
get_str(MALLOC_CONF)
MALLOC_CONF.name().read()
}
/// A type providing access to the embedded configure-time-specified run-time
@ -53,18 +53,17 @@ pub fn malloc_conf() -> Result<&'static str> {
/// }
/// ```
#[derive(Copy, Clone)]
pub struct MallocConf([usize; 2]);
pub struct MallocConf(MibStr<[usize; 2]>);
impl MallocConf {
/// Returns a new `MallocConf`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(MALLOC_CONF, &mut mib)?;
let mib = MALLOC_CONF.name().mib_str()?;
Ok(MallocConf(mib))
}
/// Returns the embedded configure-time-specified run-time options config.
pub fn get(self) -> Result<&'static str> {
get_str_mib(&self.0)
self.0.read()
}
}

View File

@ -1,7 +1,7 @@
//! Epoch access.
use error::Result;
use raw::{get_set, get_set_mib, name_to_mib};
use keys::{Access, IntoName, Mib};
const EPOCH: &[u8] = b"epoch\0";
@ -28,7 +28,7 @@ const EPOCH: &[u8] = b"epoch\0";
/// }
/// ```
pub fn epoch() -> Result<u64> {
get_set(EPOCH, 1)
EPOCH.name().read_write(1)
}
/// A type providing access to the jemalloc epoch.
@ -57,13 +57,12 @@ pub fn epoch() -> Result<u64> {
/// assert_eq!(a + 1, b);
/// }
#[derive(Copy, Clone)]
pub struct Epoch([usize; 1]);
pub struct Epoch(Mib<[usize; 1]>);
impl Epoch {
/// Returns a new `Epoch`.
pub fn new() -> Result<Self> {
let mut mib = [0; 1];
name_to_mib(EPOCH, &mut mib)?;
let mib = EPOCH.name().mib()?;
Ok(Epoch(mib))
}
@ -72,6 +71,6 @@ impl Epoch {
/// The epoch advances by 1 every time it is advanced, so the value can be
/// used to determine if another thread triggered a referesh.
pub fn advance(self) -> Result<u64> {
get_set_mib(&self.0, 1)
self.0.read_write(1)
}
}

417
jemalloc-ctl/src/keys.rs Normal file
View File

@ -0,0 +1,417 @@
//! Key types to index the _MALLCTL NAMESPACE_.
//!
//! The [`Name`] and [`Mib`] types are provided as safe indices into the
//! _MALLCTL NAMESPACE_. These are constructed from slices via the [`IntoName`]
//! and [`IntoMib`] traits. The [`Access`] trait provides provides safe access
//! into the `_MALLCTL NAMESPACE_`.
//!
//! # Example
//!
//! ```
//! extern crate libc;
//! extern crate jemallocator;
//! extern crate jemalloc_ctl;
//!
//! #[global_allocator]
//! static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
//!
//! fn main() {
//! use jemalloc_ctl::{Access, IntoName, Name, Mib};
//! use libc::{c_uint, c_char};
//! let name = b"arenas.nbins\0".name();
//! let nbins: c_uint = name.read().unwrap();
//! let mut mib: Mib<[usize; 4]> = b"arenas.bin.0.size\0".name().mib().unwrap();
//! for i in 0..4 {
//! mib[2] = i;
//! let bin_size: usize = mib.read().unwrap();
//! println!("arena bin {} has size {}", i, bin_size);
//! }
//! }
//! ```
use error::Result;
use std::str;
use {fmt, ops, raw};
/// A `Name` in the _MALLCTL NAMESPACE_.
#[repr(transparent)]
#[derive(PartialEq)]
pub struct Name([u8]);
/// Converts a null-terminated byte-string into a [`Name`].
pub trait IntoName {
/// Converts a null-terminated byte-string into a [`Name`].
fn name(&self) -> &Name;
}
impl IntoName for [u8] {
fn name(&self) -> &Name {
use str;
assert!(
!self.is_empty(),
"cannot create Name from empty byte-string"
);
assert_eq!(
*self.last().unwrap(),
b'\0',
"cannot create Name from non-null-terminated byte-string \"{}\"",
str::from_utf8(self).unwrap()
);
unsafe { &*(self as *const [u8] as *const Name) }
}
}
impl Name {
/// Returns the [`Mib`] of `self`.
pub fn mib<T: MibArg>(&self) -> Result<Mib<T>> {
let mut mib: Mib<T> = Mib::default();
raw::name_to_mib(&self.0, mib.0.as_mut())?;
Ok(mib)
}
/// Returns the [`MibStr`] of `self` which is a key whose value is a string.
pub fn mib_str<T: MibArg>(&self) -> Result<MibStr<T>> {
assert!(
self.value_type_str(),
"key \"{}\" does not refer to a string",
self
);
let mut mib: MibStr<T> = MibStr::default();
raw::name_to_mib(&self.0, mib.0.as_mut())?;
Ok(mib)
}
/// Returns `true` if `self` is a key in the _MALLCTL NAMESPCE_ referring to
/// a null-terminated string.
pub fn value_type_str(&self) -> bool {
// remove the null-terminator:
let name = self.0.split_at(self.0.len() - 1).0;
if name.is_empty() {
return false;
}
debug_assert_ne!(*name.last().unwrap(), b'\0');
match name {
b"version"
| b"config.malloc_conf"
| b"opt.metadata_thp"
| b"opt.dss"
| b"opt.percpu_arena"
| b"opt.stats_print_opts"
| b"opt.junk"
| b"opt.thp"
| b"opt.prof_prefix"
| b"thread.prof.name"
| b"prof.dump" => true,
v if v.starts_with(b"arena.") && v.ends_with(b".dss") => true,
v if v.starts_with(b"stats.arenas.") && v.ends_with(b".dss") => true,
_ => false,
}
}
}
impl fmt::Debug for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use str;
write!(f, "{}", str::from_utf8(&self.0).unwrap())
}
}
impl fmt::Display for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use str;
write!(f, "{}", str::from_utf8(&self.0).unwrap())
}
}
/// Management Information Base.
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Debug, Default)]
pub struct Mib<T: MibArg>(T);
/// Management Information Base refering to a string value.
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Debug, Default)]
pub struct MibStr<T: MibArg>(T);
impl<T: MibArg> ops::Index<usize> for Mib<T> {
type Output = usize;
fn index(&self, idx: usize) -> &Self::Output {
&self.0.as_ref()[idx]
}
}
impl<T: MibArg> ops::IndexMut<usize> for Mib<T> {
fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
&mut self.0.as_mut()[idx]
}
}
impl<T: MibArg> ops::Index<usize> for MibStr<T> {
type Output = usize;
fn index(&self, idx: usize) -> &Self::Output {
&self.0.as_ref()[idx]
}
}
impl<T: MibArg> ops::IndexMut<usize> for MibStr<T> {
fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
&mut self.0.as_mut()[idx]
}
}
/// Safe read access to the _MALLCTL NAMESPACE_.
pub trait Access<T> {
/// Read the key at `self`.
fn read(&self) -> Result<T>;
/// Write `value` at the key `self`.
fn write(&self, value: T) -> Result<()>;
/// Write `value` at the key `self` returning its previous value.
fn read_write(&self, value: T) -> Result<T>;
}
macro_rules! impl_access {
($id:ty) => {
impl<T: MibArg> Access<$id> for Mib<T> {
fn read(&self) -> Result<$id> {
unsafe { raw::get_mib(self.0.as_ref()) }
}
fn write(&self, value: $id) -> Result<()> {
unsafe { raw::set_mib(self.0.as_ref(), value) }
}
fn read_write(&self, value: $id) -> Result<$id> {
unsafe { raw::get_set_mib(self.0.as_ref(), value) }
}
}
impl Access<$id> for Name {
fn read(&self) -> Result<$id> {
unsafe { raw::get(&self.0) }
}
fn write(&self, value: $id) -> Result<()> {
unsafe { raw::set(&self.0, value) }
}
fn read_write(&self, value: $id) -> Result<$id> {
unsafe { raw::get_set(&self.0, value) }
}
}
};
}
impl_access!(u32);
impl_access!(u64);
impl_access!(isize);
impl_access!(usize);
impl<T: MibArg> Access<bool> for Mib<T> {
fn read(&self) -> Result<bool> {
unsafe {
let v: u8 = raw::get_mib(self.0.as_ref())?;
assert!(v == 0 || v == 1);
Ok(v == 1)
}
}
fn write(&self, value: bool) -> Result<()> {
unsafe { raw::set_mib(self.0.as_ref(), value) }
}
fn read_write(&self, value: bool) -> Result<bool> {
unsafe {
let v: u8 = raw::get_set_mib(self.0.as_ref(), value as u8)?;
Ok(v == 1)
}
}
}
impl Access<bool> for Name {
fn read(&self) -> Result<bool> {
unsafe {
let v: u8 = raw::get(&self.0)?;
assert!(v == 0 || v == 1);
Ok(v == 1)
}
}
fn write(&self, value: bool) -> Result<()> {
unsafe { raw::set(&self.0, value) }
}
fn read_write(&self, value: bool) -> Result<bool> {
unsafe {
let v: u8 = raw::get_set(&self.0, value as u8)?;
Ok(v == 1)
}
}
}
impl<T: MibArg> Access<&'static [u8]> for MibStr<T> {
fn read(&self) -> Result<&'static [u8]> {
// this is safe because the only safe way to construct a `MibStr` is by
// validating that the key refers to a byte-string value
unsafe { raw::get_str_mib(self.0.as_ref()) }
}
fn write(&self, value: &'static [u8]) -> Result<()> {
raw::set_str_mib(self.0.as_ref(), value)
}
fn read_write(&self, value: &'static [u8]) -> Result<&'static [u8]> {
// this is safe because the only safe way to construct a `MibStr` is by
// validating that the key refers to a byte-string value
unsafe { raw::get_set_str_mib(self.0.as_ref(), value) }
}
}
impl Access<&'static [u8]> for Name {
fn read(&self) -> Result<&'static [u8]> {
assert!(
self.value_type_str(),
"the name \"{:?}\" does not refer to a byte string",
self
);
// this is safe because the key refers to a byte string:
unsafe { raw::get_str(&self.0) }
}
fn write(&self, value: &'static [u8]) -> Result<()> {
assert!(
self.value_type_str(),
"the name \"{:?}\" does not refer to a byte string",
self
);
raw::set_str(&self.0, value)
}
fn read_write(&self, value: &'static [u8]) -> Result<&'static [u8]> {
assert!(
self.value_type_str(),
"the name \"{:?}\" does not refer to a byte string",
self
);
// this is safe because the key refers to a byte string:
unsafe { raw::get_set_str(&self.0, value) }
}
}
impl<T: MibArg> Access<&'static str> for MibStr<T> {
fn read(&self) -> Result<&'static str> {
// this is safe because the only safe way to construct a `MibStr` is by
// validating that the key refers to a byte-string value
let s = unsafe { raw::get_str_mib(self.0.as_ref())? };
Ok(str::from_utf8(s).unwrap())
}
fn write(&self, value: &'static str) -> Result<()> {
raw::set_str_mib(self.0.as_ref(), value.as_bytes())
}
fn read_write(&self, value: &'static str) -> Result<&'static str> {
// this is safe because the only safe way to construct a `MibStr` is by
// validating that the key refers to a byte-string value
let s = unsafe { raw::get_set_str_mib(self.0.as_ref(), value.as_bytes())? };
Ok(str::from_utf8(s).unwrap())
}
}
impl Access<&'static str> for Name {
fn read(&self) -> Result<&'static str> {
assert!(
self.value_type_str(),
"the name \"{:?}\" does not refer to a byte string",
self
);
// this is safe because the key refers to a byte string:
let s = unsafe { raw::get_str(&self.0)? };
Ok(str::from_utf8(s).unwrap())
}
fn write(&self, value: &'static str) -> Result<()> {
assert!(
self.value_type_str(),
"the name \"{:?}\" does not refer to a byte string",
self
);
raw::set_str(&self.0, value.as_bytes())
}
fn read_write(&self, value: &'static str) -> Result<&'static str> {
assert!(
self.value_type_str(),
"the name \"{:?}\" does not refer to a byte string",
self
);
// this is safe because the key refers to a byte string:
let s = unsafe { raw::get_set_str(&self.0, value.as_bytes())? };
Ok(str::from_utf8(s).unwrap())
}
}
#[cfg(test)]
mod tests {
use super::{Access, IntoName, Mib, MibStr};
#[test]
fn bool_rw() {
let name = b"thread.tcache.enabled\0".name();
let tcache: bool = name.read().unwrap();
let new_tcache = !tcache;
name.write(new_tcache).unwrap();
let mib: Mib<[usize; 3]> = name.mib().unwrap();
let r: bool = mib.read().unwrap();
assert_eq!(r, new_tcache);
}
#[test]
fn u32_r() {
let name = b"arenas.bin.0.nregs\0".name();
let v: u32 = name.read().unwrap();
let mib: Mib<[usize; 4]> = name.mib().unwrap();
let r: u32 = mib.read().unwrap();
assert_eq!(r, v);
}
#[test]
fn size_t_r() {
let name = b"arenas.lextent.0.size\0".name();
let v: libc::size_t = name.read().unwrap();
let mib: Mib<[usize; 4]> = name.mib().unwrap();
let r: libc::size_t = mib.read().unwrap();
assert_eq!(r, v);
}
#[test]
fn ssize_t_rw() {
let name = b"arenas.dirty_decay_ms\0".name();
let v: libc::ssize_t = name.read().unwrap();
name.write(v).unwrap();
let mib: Mib<[usize; 2]> = name.mib().unwrap();
let r: libc::ssize_t = mib.read().unwrap();
assert_eq!(r, v);
}
#[test]
fn u64_rw() {
let name = b"epoch\0".name();
let epoch: u64 = name.read().unwrap();
name.write(epoch).unwrap();
let mib: Mib<[usize; 1]> = name.mib().unwrap();
let epoch: u64 = mib.read().unwrap();
mib.write(epoch).unwrap();
}
#[test]
fn str_rw() {
let name = b"arena.0.dss\0".name();
let dss: &'static [u8] = name.read().unwrap();
name.write(dss).unwrap();
let mib: MibStr<[usize; 3]> = name.mib_str().unwrap();
let dss2: &'static [u8] = mib.read().unwrap();
mib.write(dss2).unwrap();
assert_eq!(dss, dss2);
}
}
pub trait MibArg:
Copy + Clone + PartialEq + Default + fmt::Debug + AsRef<[usize]> + AsMut<[usize]>
{
}
impl<T> MibArg for T where
T: Copy + Clone + PartialEq + Default + fmt::Debug + AsRef<[usize]> + AsMut<[usize]>
{
}

View File

@ -71,6 +71,7 @@
#![deny(missing_docs)]
#![cfg_attr(not(feature = "use_std"), no_std)]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::stutter))]
#![feature(coerce_unsized)]
extern crate jemalloc_sys;
extern crate libc;
@ -84,13 +85,14 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
#[cfg(not(feature = "use_std"))]
use core as std;
use std::{fmt, mem, ptr, result, slice};
use std::{fmt, mem, ops, ptr, result, slice, str};
pub mod arenas;
mod background_threads;
pub mod config;
mod epoch;
mod error;
mod keys;
pub mod opt;
pub mod raw;
pub mod stats;
@ -102,4 +104,5 @@ mod version;
pub use background_threads::*;
pub use epoch::*;
pub use error::{Error, Result};
pub use keys::{Access, IntoName, Mib, MibStr, Name};
pub use version::*;

View File

@ -2,8 +2,8 @@
//!
//! These settings are controlled by the `MALLOC_CONF` environment variable.
use error::Result;
use keys::{Access, IntoName, Mib, MibStr};
use libc::c_uint;
use raw::{get, get_mib, get_str, get_str_mib, name_to_mib};
const ABORT: &[u8] = b"opt.abort\0";
@ -25,7 +25,7 @@ const ABORT: &[u8] = b"opt.abort\0";
/// }
/// ```
pub fn abort() -> Result<bool> {
get(ABORT)
ABORT.name().read()
}
/// A type determining if `jemalloc` will call `abort(3)` on most warnings.
@ -50,19 +50,18 @@ pub fn abort() -> Result<bool> {
/// }
/// ```
#[derive(Copy, Clone)]
pub struct Abort([usize; 2]);
pub struct Abort(Mib<[usize; 2]>);
impl Abort {
/// Returns a new `Abort`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(ABORT, &mut mib)?;
let mib = ABORT.name().mib()?;
Ok(Abort(mib))
}
/// Returns the abort-on-warning behavior.
pub fn get(self) -> Result<bool> {
get_mib(&self.0)
self.0.read()
}
}
@ -88,7 +87,7 @@ const DSS: &[u8] = b"opt.dss\0";
/// }
/// ```
pub fn dss() -> Result<&'static str> {
get_str(DSS)
DSS.name().read()
}
/// A type providing access to the dss (`sbrk(2)`) allocation precedence as related to `mmap(2)`
@ -116,19 +115,18 @@ pub fn dss() -> Result<&'static str> {
/// }
/// ```
#[derive(Copy, Clone)]
pub struct Dss([usize; 2]);
pub struct Dss(MibStr<[usize; 2]>);
impl Dss {
/// Returns a new `Dss`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(DSS, &mut mib)?;
let mib = DSS.name().mib_str()?;
Ok(Dss(mib))
}
/// Returns the dss allocation precedence.
pub fn get(self) -> Result<&'static str> {
get_str_mib(&self.0)
self.0.read()
}
}
@ -152,7 +150,7 @@ const NARENAS: &[u8] = b"opt.narenas\0";
/// }
/// ```
pub fn narenas() -> Result<c_uint> {
get(NARENAS)
NARENAS.name().read()
}
/// A type providing access to the maximum number of arenas to use for automatic multiplexing of
@ -178,19 +176,18 @@ pub fn narenas() -> Result<c_uint> {
/// }
/// ```
#[derive(Copy, Clone)]
pub struct NArenas([usize; 2]);
pub struct NArenas(Mib<[usize; 2]>);
impl NArenas {
/// Returns a new `NArenas`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(NARENAS, &mut mib)?;
let mib = NARENAS.name().mib()?;
Ok(NArenas(mib))
}
/// Returns the maximum number of arenas.
pub fn get(self) -> Result<c_uint> {
get_mib(&self.0)
self.0.read()
}
}
@ -222,7 +219,7 @@ const JUNK: &[u8] = b"opt.junk\0";
/// }
/// ```
pub fn junk() -> Result<&'static str> {
get_str(JUNK)
JUNK.name().read()
}
/// A type providing access to `jemalloc`'s junk filling mode.
@ -255,19 +252,18 @@ pub fn junk() -> Result<&'static str> {
/// }
/// ```
#[derive(Copy, Clone)]
pub struct Junk([usize; 2]);
pub struct Junk(MibStr<[usize; 2]>);
impl Junk {
/// Returns a new `Junk`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(JUNK, &mut mib)?;
let mib = JUNK.name().mib_str()?;
Ok(Junk(mib))
}
/// Returns jemalloc's junk filling mode.
pub fn get(self) -> Result<&'static str> {
get_str_mib(&self.0)
self.0.read()
}
}
@ -294,7 +290,7 @@ const ZERO: &[u8] = b"opt.zero\0";
/// }
/// ```
pub fn zero() -> Result<bool> {
get(ZERO)
ZERO.name().read()
}
/// A type providing access to jemalloc's zeroing behavior.
@ -322,19 +318,18 @@ pub fn zero() -> Result<bool> {
/// }
/// ```
#[derive(Copy, Clone)]
pub struct Zero([usize; 2]);
pub struct Zero(Mib<[usize; 2]>);
impl Zero {
/// Returns a new `Zero`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(ZERO, &mut mib)?;
let mib = ZERO.name().mib()?;
Ok(Zero(mib))
}
/// Returns the `jemalloc` zeroing behavior.
pub fn get(self) -> Result<bool> {
get_mib(&self.0)
self.0.read()
}
}
@ -359,7 +354,7 @@ const TCACHE: &[u8] = b"opt.tcache\0";
/// }
/// ```
pub fn tcache() -> Result<bool> {
get(TCACHE)
TCACHE.name().read()
}
/// A type providing access to thread-local allocation caching behavior.
@ -385,19 +380,18 @@ pub fn tcache() -> Result<bool> {
/// }
/// ```
#[derive(Copy, Clone)]
pub struct Tcache([usize; 2]);
pub struct Tcache(Mib<[usize; 2]>);
impl Tcache {
/// Returns a new `Tcache`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(TCACHE, &mut mib)?;
let mib = TCACHE.name().mib()?;
Ok(Tcache(mib))
}
/// Returns the thread-local caching behavior.
pub fn get(self) -> Result<bool> {
get_mib(&self.0)
self.0.read()
}
}
@ -422,7 +416,7 @@ const LG_TCACHE_MAX: &[u8] = b"opt.lg_tcache_max\0";
/// }
/// ```
pub fn lg_tcache_max() -> Result<usize> {
get(LG_TCACHE_MAX)
LG_TCACHE_MAX.name().read()
}
/// A type providing access to the maximum size class (log base 2) to cache in the thread-specific
@ -449,19 +443,18 @@ pub fn lg_tcache_max() -> Result<usize> {
/// }
/// ```
#[derive(Copy, Clone)]
pub struct LgTcacheMax([usize; 2]);
pub struct LgTcacheMax(Mib<[usize; 2]>);
impl LgTcacheMax {
/// Returns a new `LgTcacheMax`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(LG_TCACHE_MAX, &mut mib)?;
let mib = LG_TCACHE_MAX.name().mib()?;
Ok(LgTcacheMax(mib))
}
/// Returns the maximum cached size class.
pub fn get(self) -> Result<usize> {
get_mib(&self.0)
self.0.read()
}
}
@ -487,7 +480,7 @@ const BACKGROUND_THREAD: &[u8] = b"opt.background_thread\0";
/// }
/// ```
pub fn background_thread() -> Result<bool> {
get(BACKGROUND_THREAD)
BACKGROUND_THREAD.name().read()
}
/// A type determining if `jemalloc` will be initialized with background worker
@ -514,18 +507,17 @@ pub fn background_thread() -> Result<bool> {
/// }
/// ```
#[derive(Copy, Clone)]
pub struct BackgroundThread([usize; 2]);
pub struct BackgroundThread(Mib<[usize; 2]>);
impl BackgroundThread {
/// Returns a new `BackgroundThread`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(BACKGROUND_THREAD, &mut mib)?;
let mib = BACKGROUND_THREAD.name().mib()?;
Ok(BackgroundThread(mib))
}
/// Returns the background thread initialization behavior.
pub fn get(self) -> Result<bool> {
get_mib(&self.0)
self.0.read()
}
}

View File

@ -1,6 +1,6 @@
//! Raw `malloctl` getter/setters
use error::{cvt, Error, Result};
use error::{cvt, Result};
use libc::c_char;
use {mem, ptr, slice};
@ -60,74 +60,94 @@ pub fn name_to_mib(name: &[u8], mib: &mut [usize]) -> Result<()> {
///
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
/// to a `mib` (Management Information Base).
pub fn get_mib<T: Copy>(mib: &[usize]) -> Result<T> {
unsafe {
let mut value = MaybeUninit { init: () };
let mut len = mem::size_of::<T>();
cvt(jemalloc_sys::mallctlbymib(
mib.as_ptr(),
mib.len(),
&mut value.init as *mut _ as *mut _,
&mut len,
ptr::null_mut(),
0,
))?;
assert_eq!(len, mem::size_of::<T>());
Ok(value.maybe_uninit)
}
///
/// # Safety
///
/// This function is `unsafe` because it is possible to use it to construct an
/// invalid `T`, for example, by passing `T=bool` for a key returning `u8`. The
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
/// `u8` can.
pub unsafe fn get_mib<T: Copy>(mib: &[usize]) -> Result<T> {
let mut value = MaybeUninit { init: () };
let mut len = mem::size_of::<T>();
cvt(jemalloc_sys::mallctlbymib(
mib.as_ptr(),
mib.len(),
&mut value.init as *mut _ as *mut _,
&mut len,
ptr::null_mut(),
0,
))?;
assert_eq!(len, mem::size_of::<T>());
Ok(value.maybe_uninit)
}
/// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and
/// reads its value.
pub fn get<T: Copy>(name: &[u8]) -> Result<T> {
unsafe {
validate_name(name);
///
/// # Safety
///
/// This function is `unsafe` because it is possible to use it to construct an
/// invalid `T`, for example, by passing `T=bool` for a key returning `u8`. The
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
/// `u8` can.
pub unsafe fn get<T: Copy>(name: &[u8]) -> Result<T> {
validate_name(name);
let mut value = MaybeUninit { init: () };
let mut len = mem::size_of::<T>();
cvt(jemalloc_sys::mallctl(
name as *const _ as *const c_char,
&mut value.init as *mut _ as *mut _,
&mut len,
ptr::null_mut(),
0,
))?;
assert_eq!(len, mem::size_of::<T>());
Ok(value.maybe_uninit)
}
let mut value = MaybeUninit { init: () };
let mut len = mem::size_of::<T>();
cvt(jemalloc_sys::mallctl(
name as *const _ as *const c_char,
&mut value.init as *mut _ as *mut _,
&mut len,
ptr::null_mut(),
0,
))?;
assert_eq!(len, mem::size_of::<T>());
Ok(value.maybe_uninit)
}
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and sets its `value`.
///
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
/// to a `mib` (Management Information Base).
pub fn set_mib<T>(mib: &[usize], mut value: T) -> Result<()> {
unsafe {
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>(),
))
}
///
/// # Safety
///
/// This function is `unsafe` because it is possible to use it to construct an
/// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
/// `u8` can.
pub unsafe fn set_mib<T>(mib: &[usize], mut value: T) -> 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>(),
))
}
/// Uses the null-terminated string `name` as the key to the _MALLCTL NAMESPACE_
/// and sets it `value`
pub fn set<T>(name: &[u8], mut value: T) -> Result<()> {
unsafe {
validate_name(name);
///
/// # Safety
///
/// This function is `unsafe` because it is possible to use it to construct an
/// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
/// `u8` can.
pub unsafe fn set<T>(name: &[u8], mut value: T) -> Result<()> {
validate_name(name);
cvt(jemalloc_sys::mallctl(
name as *const _ as *const c_char,
ptr::null_mut(),
ptr::null_mut(),
&mut value as *mut _ as *mut _,
mem::size_of::<T>(),
))
}
cvt(jemalloc_sys::mallctl(
name as *const _ as *const c_char,
ptr::null_mut(),
ptr::null_mut(),
&mut value as *mut _ as *mut _,
mem::size_of::<T>(),
))
}
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and sets its `value`
@ -135,68 +155,214 @@ pub fn set<T>(name: &[u8], mut value: T) -> Result<()> {
///
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
/// to a `mib` (Management Information Base).
pub fn get_set_mib<T>(mib: &[usize], mut value: T) -> Result<T> {
unsafe {
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,
))?;
assert_eq!(len, mem::size_of::<T>());
Ok(value)
}
///
/// # Safety
///
/// This function is `unsafe` because it is possible to use it to construct an
/// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
/// `u8` can.
pub unsafe fn get_set_mib<T>(mib: &[usize], mut value: T) -> 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,
))?;
assert_eq!(len, mem::size_of::<T>());
Ok(value)
}
/// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and
/// sets its `value` returning its previous value.
pub fn get_set<T>(name: &[u8], mut value: T) -> Result<T> {
unsafe {
validate_name(name);
///
/// # Safety
///
/// This function is `unsafe` because it is possible to use it to construct an
/// invalid `T`, for example, by passing `T=u8` for a key expecting `bool`. The
/// sizes of `bool` and `u8` match, but `bool` cannot represent all values that
/// `u8` can.
pub unsafe fn get_set<T>(name: &[u8], mut value: T) -> Result<T> {
validate_name(name);
let mut len = mem::size_of::<T>();
cvt(jemalloc_sys::mallctl(
name as *const _ as *const c_char,
&mut value as *mut _ as *mut _,
&mut len,
&mut value as *mut _ as *mut _,
len,
))?;
assert_eq!(len, mem::size_of::<T>());
Ok(value)
}
let mut len = mem::size_of::<T>();
cvt(jemalloc_sys::mallctl(
name as *const _ as *const c_char,
&mut value as *mut _ as *mut _,
&mut len,
&mut value as *mut _ as *mut _,
len,
))?;
assert_eq!(len, mem::size_of::<T>());
Ok(value)
}
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and reads its value of
/// type `&str`
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and reads its value.
///
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
/// to a `mib` (Management Information Base).
pub fn get_str_mib(mib: &[usize]) -> Result<&'static str> {
unsafe {
let ptr: *const c_char = get_mib(mib)?;
ptr2str(ptr)
}
///
/// # Safety
///
/// This function is unsafe because if the key does not return a pointer to a
/// null-terminated string the behavior is undefined.
///
/// For example, a key for a `u64` value can be used to read a pointer on 64-bit
/// platform, where this pointer will point to the address denoted by the `u64`s
/// representation. Also, a key to a `*mut extent_hooks_t` will return a pointer
/// that will not point to a null-terminated string.
///
/// This function needs to compute the length of the string by looking for the
/// null-terminator: `\0`. This requires reading the memory behind the pointer.
///
/// If the pointer is invalid (e.g. because it was converted from a `u64` that
/// does not represent a valid address), reading the string to look for `\0`
/// will dereference a non-dereferenceable pointer, which is undefined behavior.
///
/// If the pointer is valid but it does not point to a null-terminated string,
/// looking for `\0` will read garbage and might end up reading out-of-bounds,
/// which is undefined behavior.
pub unsafe fn get_str_mib(mib: &[usize]) -> Result<&'static [u8]> {
let ptr: *const c_char = get_mib(mib)?;
ptr2str(ptr)
}
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and sets its `value`.
///
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
/// to a `mib` (Management Information Base).
///
/// # Panics
///
/// If `value` is not a non-empty null-terminated string.
pub fn set_str_mib(mib: &[usize], value: &'static [u8]) -> Result<()> {
assert!(!value.is_empty(), "value cannot be empty");
assert_eq!(*value.last().unwrap(), b'\0');
// This is safe because `value` will always point to a null-terminated
// string, which makes it safe for all key value types: pointers to
// null-terminated strings, pointers, pointer-sized integers, etc.
unsafe { set_mib(mib, value.as_ptr() as *const c_char) }
}
/// Uses the MIB `mib` as key to the _MALLCTL NAMESPACE_ and sets its `value`
/// returning its previous value.
///
/// The [`name_to_mib`] API translates a string of the key (e.g. `arenas.nbins`)
/// to a `mib` (Management Information Base).
///
/// # Safety
///
/// This function is unsafe because if the key does not return a pointer to a
/// null-terminated string the behavior is undefined.
///
/// For example, a key for a `u64` value can be used to read a pointer on 64-bit
/// platform, where this pointer will point to the address denoted by the `u64`s
/// representation. Also, a key to a `*mut extent_hooks_t` will return a pointer
/// that will not point to a null-terminated string.
///
/// This function needs to compute the length of the string by looking for the
/// null-terminator: `\0`. This requires reading the memory behind the pointer.
///
/// If the pointer is invalid (e.g. because it was converted from a `u64` that
/// does not represent a valid address), reading the string to look for `\0`
/// will dereference a non-dereferenceable pointer, which is undefined behavior.
///
/// If the pointer is valid but it does not point to a null-terminated string,
/// looking for `\0` will read garbage and might end up reading out-of-bounds,
/// which is undefined behavior.
pub unsafe fn get_set_str_mib(mib: &[usize], value: &'static [u8]) -> Result<&'static [u8]> {
let ptr: *const c_char = get_set_mib(mib, value.as_ptr() as *const c_char)?;
ptr2str(ptr)
}
/// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and
/// reads its value of type `&str`.
pub fn get_str(name: &[u8]) -> Result<&'static str> {
unsafe {
validate_name(name);
let ptr: *const c_char = get(name)?;
ptr2str(ptr)
}
/// reads its value.
///
/// # Safety
///
/// This function is unsafe because if the key does not return a pointer to a
/// null-terminated string the behavior is undefined.
///
/// For example, a key for a `u64` value can be used to read a pointer on 64-bit
/// platform, where this pointer will point to the address denoted by the `u64`s
/// representation. Also, a key to a `*mut extent_hooks_t` will return a pointer
/// that will not point to a null-terminated string.
///
/// This function needs to compute the length of the string by looking for the
/// null-terminator: `\0`. This requires reading the memory behind the pointer.
///
/// If the pointer is invalid (e.g. because it was converted from a `u64` that
/// does not represent a valid address), reading the string to look for `\0`
/// will dereference a non-dereferenceable pointer, which is undefined behavior.
///
/// If the pointer is valid but it does not point to a null-terminated string,
/// looking for `\0` will read garbage and might end up reading out-of-bounds,
/// which is undefined behavior.
pub unsafe fn get_str(name: &[u8]) -> Result<&'static [u8]> {
let ptr: *const c_char = get(name)?;
ptr2str(ptr)
}
unsafe fn ptr2str(ptr: *const c_char) -> Result<&'static str> {
/// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and
/// sets its `value`.
pub fn set_str(name: &[u8], value: &'static [u8]) -> Result<()> {
assert!(!value.is_empty(), "value cannot be empty");
assert_eq!(*value.last().unwrap(), b'\0');
// This is safe because `value` will always point to a null-terminated
// string, which makes it safe for all key value types: pointers to
// null-terminated strings, pointers, pointer-sized integers, etc.
unsafe { set(name, value.as_ptr() as *const c_char) }
}
/// Uses the null-terminated string `name` as key to the _MALLCTL NAMESPACE_ and
/// sets its `value` returning its previous value.
///
/// # Safety
///
/// This function is unsafe because if the key does not return a pointer to a
/// null-terminated string the behavior is undefined.
///
/// For example, a key for a `u64` value can be used to read a pointer on 64-bit
/// platform, where this pointer will point to the address denoted by the `u64`s
/// representation. Also, a key to a `*mut extent_hooks_t` will return a pointer
/// that will not point to a null-terminated string.
///
/// This function needs to compute the length of the string by looking for the
/// null-terminator: `\0`. This requires reading the memory behind the pointer.
///
/// If the pointer is invalid (e.g. because it was converted from a `u64` that
/// does not represent a valid address), reading the string to look for `\0`
/// will dereference a non-dereferenceable pointer, which is undefined behavior.
///
/// If the pointer is valid but it does not point to a null-terminated string,
/// looking for `\0` will read garbage and might end up reading out-of-bounds,
/// which is undefined behavior.
pub unsafe fn get_set_str(name: &[u8], value: &'static [u8]) -> Result<&'static [u8]> {
let ptr: *const c_char = get_set(name, value.as_ptr() as *const c_char)?;
ptr2str(ptr)
}
/// Converts a non-empty null-terminated character string at `ptr` into a valid
/// null-terminated UTF-8 string.
///
/// # Panics
///
/// If `ptr.is_null()`.
///
/// # Safety
///
/// If `ptr` does not point to a null-terminated character string the behavior
/// is undefined.
unsafe fn ptr2str(ptr: *const c_char) -> Result<&'static [u8]> {
assert!(
!ptr.is_null(),
"attempt to convert a null-ptr to a UTF-8 string"
);
let len = libc::strlen(ptr);
let byte_slice = slice::from_raw_parts(ptr as *const u8, (len + 1) as _);
core::str::from_utf8(byte_slice).map_err(|_| Error::EINVAL)
Ok(slice::from_raw_parts(ptr as *const u8, len + 1))
}
fn validate_name(name: &[u8]) {
@ -230,15 +396,15 @@ mod tests {
assert!(rstr.is_ok());
let rstr = rstr.unwrap();
assert!(rstr.len() == 1);
assert_eq!(rstr, "\0");
assert_eq!(rstr, b"\0");
}
{
let cstr = b"foo baaar\0";
let rstr = ptr2str(cstr as *const _ as *const c_char);
assert!(rstr.is_ok());
let rstr = rstr.unwrap();
assert!(rstr.len() == "foo baaar\0".len());
assert_eq!(rstr, "foo baaar\0");
assert!(rstr.len() == b"foo baaar\0".len());
assert_eq!(rstr, b"foo baaar\0");
}
}
}

View File

@ -6,7 +6,7 @@
//! [`Epoch`]: ../struct.Epoch.html
use error::Result;
use raw::{get, get_mib, name_to_mib};
use keys::{Access, IntoName, Mib};
const ALLOCATED: &[u8] = b"stats.allocated\0";
@ -37,7 +37,7 @@ const ALLOCATED: &[u8] = b"stats.allocated\0";
///
/// [`epoch`]: ../fn.epoch().html
pub fn allocated() -> Result<usize> {
get(ALLOCATED)
ALLOCATED.name().read()
}
/// A type providing access to the total number of bytes allocated by the application.
@ -73,19 +73,18 @@ pub fn allocated() -> Result<usize> {
///
/// [`Epoch`]: ../struct.Epoch.html
#[derive(Copy, Clone)]
pub struct Allocated([usize; 2]);
pub struct Allocated(Mib<[usize; 2]>);
impl Allocated {
/// Returns a new `Allocated`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(ALLOCATED, &mut mib)?;
let mib = ALLOCATED.name().mib()?;
Ok(Allocated(mib))
}
/// Returns the total number of bytes allocated by the application.
pub fn get(self) -> Result<usize> {
get_mib(&self.0)
self.0.read()
}
}
@ -122,7 +121,7 @@ const ACTIVE: &[u8] = b"stats.active\0";
/// [`epoch`]: ../fn.epoch().html
/// [`allocated`]: fn.allocated.hml
pub fn active() -> Result<usize> {
get(ACTIVE)
ACTIVE.name().read()
}
/// A type providing access to the total number of bytes in active pages allocated by the
@ -163,19 +162,18 @@ pub fn active() -> Result<usize> {
/// [`Epoch`]: ../struct.Epoch.html
/// [`Allocated`]: struct.Allocated.html
#[derive(Copy, Clone)]
pub struct Active([usize; 2]);
pub struct Active(Mib<[usize; 2]>);
impl Active {
/// Returns a new `Allocated`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(ACTIVE, &mut mib)?;
let mib = ACTIVE.name().mib()?;
Ok(Active(mib))
}
/// Returns the total number of bytes in active pages allocated by the application.
pub fn get(self) -> Result<usize> {
get_mib(&self.0)
self.0.read()
}
}
@ -205,7 +203,7 @@ const METADATA: &[u8] = b"stats.metadata\0";
///
/// [`epoch`]: ../fn.epoch.html
pub fn metadata() -> Result<usize> {
get(METADATA)
METADATA.name().read()
}
/// A type providing access to the total number of bytes dedicated to jemalloc metadata.
@ -239,19 +237,18 @@ pub fn metadata() -> Result<usize> {
///
/// [`Epoch`]: ../struct.Epoch.html
#[derive(Copy, Clone)]
pub struct Metadata([usize; 2]);
pub struct Metadata(Mib<[usize; 2]>);
impl Metadata {
/// Returns a new `Metadata`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(METADATA, &mut mib)?;
let mib = METADATA.name().mib()?;
Ok(Metadata(mib))
}
/// Returns the total number of bytes dedicated to jemalloc metadata.
pub fn get(self) -> Result<usize> {
get_mib(&self.0)
self.0.read()
}
}
@ -288,7 +285,7 @@ const RESIDENT: &[u8] = b"stats.resident\0";
/// [`epoch`]: ../fn.epoch.html
/// [`active`]: fn.active.html
pub fn resident() -> Result<usize> {
get(RESIDENT)
RESIDENT.name().read()
}
/// A type providing access to the total number of bytes in physically resident data pages mapped
@ -330,19 +327,18 @@ pub fn resident() -> Result<usize> {
/// [`Epoch`]: ../struct.Epoch.html
/// [`Active`]: struct.Active.html
#[derive(Copy, Clone)]
pub struct Resident([usize; 2]);
pub struct Resident(Mib<[usize; 2]>);
impl Resident {
/// Returns a new `Resident`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(RESIDENT, &mut mib)?;
let mib = RESIDENT.name().mib()?;
Ok(Resident(mib))
}
/// Returns the total number of bytes in physically resident data pages mapped by the allocator.
pub fn get(self) -> Result<usize> {
get_mib(&self.0)
self.0.read()
}
}
@ -378,7 +374,7 @@ const MAPPED: &[u8] = b"stats.mapped\0";
/// [`resident`]: fn.resident.html
/// [`active`]: fn.active.html
pub fn mapped() -> Result<usize> {
get(MAPPED)
MAPPED.name().read()
}
/// A type providing access to the total number of bytes in active extents mapped by the allocator.
@ -418,19 +414,18 @@ pub fn mapped() -> Result<usize> {
/// [`Resident`]: struct.Resident.html
/// [`Active`]: struct.Active.html
#[derive(Copy, Clone)]
pub struct Mapped([usize; 2]);
pub struct Mapped(Mib<[usize; 2]>);
impl Mapped {
/// Returns a new `Mapped`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(MAPPED, &mut mib)?;
let mib = MAPPED.name().mib()?;
Ok(Mapped(mib))
}
/// Returns the total number of bytes in active extents mapped by the allocator.
pub fn get(self) -> Result<usize> {
get_mib(&self.0)
self.0.read()
}
}
@ -465,7 +460,7 @@ const RETAINED: &[u8] = b"stats.retained\0";
/// [`epoch`]: ../fn.epoch.html
/// [`mapped`]: fn.mapped.html
pub fn retained() -> Result<usize> {
get(RETAINED)
RETAINED.name().read()
}
/// A type providing access to the total number of bytes in virtual memory mappings that were retained rather than being
@ -504,18 +499,17 @@ pub fn retained() -> Result<usize> {
/// [`Epoch`]: ../struct.Epoch.html
/// [`Mapped`]: struct.Mapped.html
#[derive(Copy, Clone)]
pub struct Retained([usize; 2]);
pub struct Retained(Mib<[usize; 2]>);
impl Retained {
/// Returns a new `Retained`.
pub fn new() -> Result<Self> {
let mut mib = [0; 2];
name_to_mib(RETAINED, &mut mib)?;
let mib = RETAINED.name().mib()?;
Ok(Retained(mib))
}
/// Returns the total number of bytes in virtual memory mappings that were retained.
pub fn get(self) -> Result<usize> {
get_mib(&self.0)
self.0.read()
}
}

View File

@ -41,7 +41,7 @@ const ALLOCATEDP: &[u8] = b"thread.allocatedp\0";
/// }
/// ```
pub fn allocatedp() -> Result<ThreadLocal<u64>> {
get(ALLOCATEDP).map(ThreadLocal)
unsafe { get(ALLOCATEDP).map(ThreadLocal) }
}
/// A type providing access to the total number of bytes allocated by the current thread.
@ -95,7 +95,7 @@ impl AllocatedP {
/// Returns a thread-local pointer to the total number of bytes allocated by this thread.
pub fn get(&self) -> Result<ThreadLocal<u64>> {
get_mib(&self.0).map(ThreadLocal)
unsafe { get_mib(&self.0).map(ThreadLocal) }
}
}
@ -133,7 +133,7 @@ const DEALLOCATEDP: &[u8] = b"thread.deallocatedp\0";
/// }
/// ```
pub fn deallocatedp() -> Result<ThreadLocal<u64>> {
get(DEALLOCATEDP).map(ThreadLocal)
unsafe { get(DEALLOCATEDP).map(ThreadLocal) }
}
/// A type providing access to the total number of bytes deallocated by the current thread.
@ -181,7 +181,7 @@ impl DeallocatedP {
/// Returns a thread-local pointer to the total number of bytes deallocated by this thread.
pub fn get(&self) -> Result<ThreadLocal<u64>> {
let ptr = get_mib::<*mut u64>(&self.0)?;
let ptr = unsafe { get_mib::<*mut u64>(&self.0)? };
Ok(ThreadLocal(ptr))
}
}

View File

@ -1,7 +1,7 @@
//! Version operations.
use error::Result;
use raw::{get_str, get_str_mib, name_to_mib};
use keys::{Access, IntoName, MibStr};
const VERSION: &[u8] = b"version\0";
@ -25,7 +25,7 @@ const VERSION: &[u8] = b"version\0";
/// }
/// ```
pub fn version() -> Result<&'static str> {
get_str(VERSION)
VERSION.name().read()
}
/// A type providing access to the jemalloc version string.
@ -47,18 +47,17 @@ pub fn version() -> Result<&'static str> {
/// println!("jemalloc version {}", version.get().unwrap());
/// }
#[derive(Copy, Clone)]
pub struct Version([usize; 1]);
pub struct Version(MibStr<[usize; 1]>);
impl Version {
/// Returns a new `Version`.
pub fn new() -> Result<Self> {
let mut mib = [0; 1];
name_to_mib(VERSION, &mut mib)?;
let mib = VERSION.name().mib_str()?;
Ok(Version(mib))
}
/// Returns the jemalloc version string.
pub fn get(self) -> Result<&'static str> {
get_str_mib(&self.0)
self.0.read()
}
}