浏览代码

Add Bookkeeper IDs

This improves the logging by adding a way to distinguish between allocators (namely local and global).

- Fix a bug related to a malformed assertion in Bookkeeper::push().
ticki 8 年之前
父节点
当前提交
180fdbdd42
共有 3 个文件被更改,包括 45 次插入22 次删除
  1. 2 1
      Cargo.toml
  2. 39 18
      src/bookkeeper.rs
  3. 4 3
      src/log.rs

+ 2 - 1
Cargo.toml

@@ -34,10 +34,11 @@ codegen-units = 1
 [features]
 default = ["allocator", "clippy"]
 # ---
+alloc_id = []
 allocator = []
 debug_tools = []
 libc_write = []
-log = ["libc_write"]
+log = ["libc_write", "alloc_id"]
 security = []
 testing = ["log", "libc_write", "debug_tools"]
 unsafe_no_brk_lock = []

+ 39 - 18
src/bookkeeper.rs

@@ -10,6 +10,14 @@ use core::{ptr, mem, ops};
 /// See guarantee 4.
 pub const EXTRA_ELEMENTS: usize = 2;
 
+#[cfg(feature = "alloc_id")]
+use core::sync::atomic::{self, AtomicUsize};
+/// The bookkeeper ID count.
+///
+/// This is atomically incremented whenever a new `Bookkeeper` is created.
+#[cfg(feature = "alloc_id")]
+static BOOKKEEPER_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
+
 /// The memory bookkeeper.
 ///
 /// This stores data about the state of the allocator, and in particular, the free memory.
@@ -37,6 +45,11 @@ pub struct Bookkeeper {
     /// These are **not** invariants: If these assumpptions are not held, it will simply act strange
     /// (e.g. logic bugs), but not memory unsafety.
     pool: Vec<Block>,
+    /// The allocator ID.
+    ///
+    /// This is simply to be able to distinguish allocators in the locks.
+    #[cfg(feature = "alloc_id")]
+    id: usize,
 }
 
 impl Bookkeeper {
@@ -46,6 +59,14 @@ impl Bookkeeper {
         debug_assert!(vec.capacity() >= EXTRA_ELEMENTS, "Not enough initial capacity of the vector.");
         debug_assert!(vec.is_empty(), "Initial vector isn't empty.");
 
+        // TODO, when added use expr field attributes
+        #[cfg(feature = "alloc_id")]
+        let res = Bookkeeper {
+            pool: vec,
+            // Increment the ID counter to get a brand new ID.
+            id: BOOKKEEPER_ID_COUNTER.fetch_add(1, atomic::Ordering::SeqCst),
+        };
+        #[cfg(not(feature = "alloc_id"))]
         let res = Bookkeeper {
             pool: vec,
         };
@@ -63,7 +84,7 @@ impl Bookkeeper {
     fn find(&mut self, block: &Block) -> usize {
         // TODO optimize this function.
         // Logging.
-        log!(self.pool, "Searching (exact) for {:?}.", block);
+        log!(self, "Searching (exact) for {:?}.", block);
 
         let ind = match self.pool.binary_search(block) {
             Ok(x) | Err(x) => x,
@@ -86,7 +107,7 @@ impl Bookkeeper {
     fn find_bound(&mut self, block: &Block) -> Range<usize> {
         // TODO optimize this function.
         // Logging.
-        log!(self.pool, "Searching (bounds) for {:?}.", block);
+        log!(self, "Searching (bounds) for {:?}.", block);
 
         let mut left_ind = match self.pool.binary_search(block) {
             Ok(x) | Err(x) => x,
@@ -139,7 +160,7 @@ impl Bookkeeper {
     fn check(&self) {
         if cfg!(debug_assertions) {
             // Logging.
-            log!(self.pool, "Checking...");
+            log!(self, "Checking...");
 
             // Reverse iterator over the blocks.
             let mut it = self.pool.iter().enumerate().rev();
@@ -169,7 +190,7 @@ impl Bookkeeper {
             }
 
             // Logging...
-            log!(self.pool, "Check OK!");
+            log!(self, "Check OK!");
         }
     }
 }
@@ -244,7 +265,7 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
         // TODO: scan more intelligently.
 
         // Logging.
-        log!(self.pool, "Allocating {} bytes with alignment {}.", size, align);
+        log!(self, "Allocating {} bytes with alignment {}.", size, align);
 
         if let Some((n, b)) = self.pool.iter_mut().enumerate().filter_map(|(n, i)| {
             if i.size() >= size {
@@ -336,7 +357,7 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
     #[inline]
     fn free(&mut self, block: Block) {
         // Just logging for the unlucky people debugging this shit. No problem.
-        log!(self.pool, "Freeing {:?}...", block);
+        log!(self, "Freeing {:?}...", block);
 
         // Binary search for the block.
         let bound = self.find_bound(&block);
@@ -381,7 +402,7 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
         let ind = self.find_bound(&block);
 
         // Logging.
-        log!(self.pool;ind, "Reallocating {:?} to size {} with align {}...", block, new_size, align);
+        log!(self;ind, "Reallocating {:?} to size {} with align {}...", block, new_size, align);
 
         // Try to do an inplace reallocation.
         match self.realloc_inplace_bound(ind, block, new_size) {
@@ -424,7 +445,7 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
     #[inline]
     fn realloc_inplace(&mut self, block: Block, new_size: usize) -> Result<Block, Block> {
         // Logging.
-        log!(self.pool, "Reallocating {:?} inplace to {}...", block, new_size);
+        log!(self, "Reallocating {:?} inplace to {}...", block, new_size);
 
         // Find the bounds of given block.
         let bound = self.find_bound(&block);
@@ -444,7 +465,7 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
     /// See [`realloc_inplace`](#method.realloc_inplace.html) for more information.
     fn realloc_inplace_bound(&mut self, ind: Range<usize>, mut block: Block, new_size: usize) -> Result<Block, Block> {
         // Logging.
-        log!(self.pool;ind, "Try inplace reallocating {:?} to size {}.", block, new_size);
+        log!(self;ind, "Try inplace reallocating {:?} to size {}.", block, new_size);
 
         /// Assertions...
         debug_assert!(self.find(&block) == ind.start, "Block is not inserted at the appropriate \
@@ -452,7 +473,7 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
 
         if new_size <= block.size() {
             // Shrink the block.
-            log!(self.pool;ind, "Shrinking {:?}.", block);
+            log!(self;ind, "Shrinking {:?}.", block);
 
             // Split the block in two segments, the main segment and the excessive segment.
             let (block, excessive) = block.split(new_size);
@@ -478,7 +499,7 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
             // the current block.
             if mergable {
                 // Logging...
-                log!(self.pool;ind, "Merging {:?} to the right.", block);
+                log!(self;ind, "Merging {:?} to the right.", block);
 
                 // We'll merge it with the block at the end of the range.
                 block.merge_right(&mut self.remove_at(ind.end)).unwrap();
@@ -514,7 +535,7 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
     #[inline]
     fn free_bound(&mut self, ind: Range<usize>, mut block: Block) {
         // Logging.
-        log!(self.pool;ind, "Freeing {:?}.", block);
+        log!(self;ind, "Freeing {:?}.", block);
 
         // Short circuit in case of empty block.
         if block.is_empty() { return; }
@@ -561,7 +582,7 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
     /// The returned pointer is guaranteed to be aligned to `align`.
     fn alloc_external(&mut self, size: usize, align: usize) -> Block {
         // Logging.
-        log!(self.pool, "Fresh allocation of size {} with alignment {}.", size, align);
+        log!(self, "Fresh allocation of size {} with alignment {}.", size, align);
 
         // Break it to me!
         let res = self.alloc_fresh(size, align);
@@ -575,10 +596,10 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
     /// Push an element without reserving.
     fn push(&mut self, mut block: Block) {
         // Logging.
-        log!(self.pool;self.pool.len(), "Pushing {:?}.", block);
+        log!(self;self.pool.len(), "Pushing {:?}.", block);
 
         // Some assertions...
-        debug_assert!(self.pool.is_empty() || &block <= self.pool.last().unwrap(), "Pushing will \
+        debug_assert!(self.pool.is_empty() || &block > self.pool.last().unwrap(), "Pushing will \
                       make the list unsorted.");
 
         // Short-circuit in case on empty block.
@@ -689,7 +710,7 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
     #[inline]
     fn insert(&mut self, ind: usize, block: Block) {
         // Logging.
-        log!(self.pool;ind, "Inserting block {:?}...", block);
+        log!(self;ind, "Inserting block {:?}...", block);
 
         // Bound check.
         assert!(self.pool.len() >= ind, "Insertion out of bounds.");
@@ -721,7 +742,7 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
         };
 
         // Log the operation.
-        log!(self.pool;ind, "Moving {} blocks to the right.", n);
+        log!(self;ind, "Moving {} blocks to the right.", n);
 
         unsafe {
             // TODO clean this mess up.
@@ -751,7 +772,7 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
     /// Remove a block.
     fn remove_at(&mut self, ind: usize) -> Block {
         // Logging.
-        log!(self.pool;ind, "Removing block.");
+        log!(self;ind, "Removing block.");
 
         if ind + 1 == self.pool.len() {
             let res = self.pool[ind].pop();

+ 4 - 3
src/log.rs

@@ -16,7 +16,7 @@ macro_rules! log {
     ($pool:expr, $( $arg:expr ),*) => {
         log!($pool;(), $( $arg ),*);
     };
-    ($pool:expr;$cur:expr, $( $arg:expr ),*) => {{
+    ($bk:expr;$cur:expr, $( $arg:expr ),*) => {{
         #[cfg(feature = "log")]
         {
             use core::fmt::Write;
@@ -26,9 +26,9 @@ macro_rules! log {
 
             // Print the pool state.
             let mut stderr = write::Writer::stderr();
-            let _ = write!(stderr, "{:10?} : ", log::internal::BlockLogger {
+            let _ = write!(stderr, "({:2})   {:10?} : ", $bk.id, log::internal::BlockLogger {
                 cur: $cur.clone().into_cursor(),
-                blocks: &$pool,
+                blocks: &$bk.pool,
             });
 
             // Print the log message.
@@ -60,6 +60,7 @@ pub mod internal {
         /// formatter if the underlying condition is true.
         ///
         /// For example, a plain position cursor will write `"|"` when `n == self.pos`.
+        // TODO use an iterator instead.
         fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result;
 
         /// The after hook.