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
//! Thread specific operations.

use crate::error::Result;
use crate::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
    ///
    /// ```
    /// # #[global_allocator]
    /// # static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
    /// #
    /// # fn main() {
    /// use tikv_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
    ///
    /// ```
    /// # #[global_allocator]
    /// # static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
    /// #
    /// # fn main() {
    /// use tikv_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 }
    }
}