1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! Thread specific operations.

use error::Result;
use raw::{read, read_mib};

option! {
    allocatedp[ str: b"thread.allocatedp\0", non_str: 2 ] => *mut u64 |
    ops:  |
    docs:
    /// Access to the total number of bytes allocated by the current thread.
    ///
    /// Unlike [`::stats::allocated`], the value returned by this type is not the
    /// number of bytes *currently* allocated, but rather the number of bytes
    /// that have *ever* been allocated by this thread.
    ///
    /// The `read` method doesn't return the value directly, but actually a
    /// pointer to the value. This allows for very fast repeated lookup, since
    /// there is no function call overhead. The pointer type cannot be sent to
    /// other threads, but `allocated::read` can be called on different threads
    /// and will return the appropriate pointer for each of them.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate jemallocator;
    /// # extern crate jemalloc_ctl;
    /// #
    /// # #[global_allocator]
    /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
    /// #
    /// # fn main() {
    /// use jemalloc_ctl::thread;
    /// let allocated = thread::allocatedp::mib().unwrap();
    /// let allocated = allocated.read().unwrap();
    ///
    /// let a = allocated.get();
    /// let buf = vec![0; 1024 * 1024];
    /// let b = allocated.get();
    /// drop(    buf);
    /// let c = allocated.get();
    ///
    /// assert!(a < b);
    /// assert_eq!(b, c);
    /// # }
    /// ```
    mib_docs: /// See [`allocatedp`].
}

impl allocatedp {
    /// Reads value using string API.
    pub fn read() -> Result<ThreadLocal<u64>> {
        unsafe { read(Self::name().as_bytes()).map(ThreadLocal) }
    }
}

impl allocatedp_mib {
    /// Reads value using MIB API.
    pub fn read(&self) -> Result<ThreadLocal<u64>> {
        unsafe { read_mib(self.0.as_ref()).map(ThreadLocal) }
    }
}

option! {
    deallocatedp[ str: b"thread.deallocatedp\0", non_str: 2 ] => *mut u64 |
    ops:  |
    docs:
    /// Access to the total number of bytes deallocated by the current thread.
    ///
    /// The `read` method doesn't return the value directly, but actually a
    /// pointer to the value. This allows for very fast repeated lookup, since
    /// there is no function call overhead. The pointer type cannot be sent to
    /// other threads, but [`deallocatedp::read`] can be called on different
    /// threads and will return the appropriate pointer for each of them.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate jemallocator;
    /// # extern crate jemalloc_ctl;
    /// #
    /// # #[global_allocator]
    /// # static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
    /// #
    /// # fn main() {
    /// use jemalloc_ctl::thread;
    /// let deallocated = thread::deallocatedp::mib().unwrap();
    /// let deallocated = deallocated.read().unwrap();
    ///
    /// let a = deallocated.get();
    /// let buf = vec![0; 1024 * 1024];
    /// let b = deallocated.get();
    /// drop(buf);
    /// let c = deallocated.get();
    ///
    /// assert_eq!(a, b);
    /// assert!(b < c);
    /// # }
    /// ```
    mib_docs: /// See [`deallocatedp`].
}

impl deallocatedp {
    /// Reads value using string API.
    pub fn read() -> Result<ThreadLocal<u64>> {
        unsafe { read(Self::name().as_bytes()).map(ThreadLocal) }
    }
}

impl deallocatedp_mib {
    /// Reads value using MIB API.
    pub fn read(&self) -> Result<ThreadLocal<u64>> {
        unsafe { read_mib(self.0.as_ref()).map(ThreadLocal) }
    }
}

/// A thread-local pointer.
///
/// It is neither `Sync` nor `Send`.
// NB we need *const here specifically since it's !Sync + !Send
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct ThreadLocal<T>(*const T);

impl<T> ThreadLocal<T>
where
    T: Copy,
{
    /// Returns the current value at the pointer.
    #[inline]
    pub fn get(self) -> T {
        unsafe { *self.0 }
    }
}