1 //! Memory blocks. 2 //! 3 //! Blocks are the main unit for the memory bookkeeping. A block is a simple construct with a 4 //! `Pointer` pointer and a size. Occupied (non-free) blocks are represented by a zero-sized block. 5 6 use core::{ptr, cmp, mem, fmt}; 7 8 use ptr::Pointer; 9 use sys; 10 11 /// A contiguous memory block. 12 /// 13 /// This provides a number of guarantees, 14 /// 15 /// 1. The inner pointer is never aliased. No byte in the block is contained in another block 16 /// (aliased in this case is defined purely based on liveliness). 17 /// 2. The buffer is valid, but not necessarily initialized. 18 /// 19 /// All this is enforced through the type system. 20 pub struct Block { 21 /// The size of this block, in bytes. 22 size: usize, 23 /// The pointer to the start of this block. 24 ptr: Pointer<u8>, 25 } 26 27 impl Block { 28 /// Create an empty block starting at `ptr`. 29 pub fn empty(ptr: &Pointer<u8>) -> Block { 30 Block { 31 size: 0, 32 // This won't alias `ptr`, since the block is empty. 33 ptr: unsafe { Pointer::new(**ptr) }, 34 } 35 } 36 37 /// Construct a block from its raw parts (pointer and size). 38 pub unsafe fn from_raw_parts(ptr: Pointer<u8>, size: usize) -> Block { 39 Block { 40 size: size, 41 ptr: ptr, 42 } 43 } 44 45 /// Get the size of the block. 46 pub fn size(&self) -> usize { 47 self.size 48 } 49 50 /// BRK allocate a block. 51 /// 52 /// This is unsafe due to the allocator assuming that only it makes use of BRK. 53 pub unsafe fn brk(size: usize) -> Block { 54 Block { 55 size: size, 56 ptr: sys::inc_brk(size).unwrap_or_else(|x| x.handle()), 57 } 58 } 59 60 /// Merge this block with a block to the right. 61 /// 62 /// This will simply extend the block, adding the size of the block, and then set the size to 63 /// zero. The return value is `Ok(())` on success, and `Err(())` on failure (e.g., the blocks 64 /// are not adjacent). 65 pub fn merge_right(&mut self, block: &mut Block) -> Result<(), ()> { 66 if self.left_to(&block) { 67 // Since the end of `block` is bounded by the address space, adding them cannot 68 // overflow. 69 self.size += block.pop().size; 70 // We pop it to make sure it isn't aliased. 71 Ok(()) 72 } else { Err(()) } 73 } 74 75 /// Is this block empty/free? 76 pub fn is_empty(&self) -> bool { 77 self.size != 0 78 } 79 80 /// Is this block aligned to `align`? 81 pub fn aligned_to(&self, align: usize) -> bool { 82 *self.ptr as usize % align == 0 83 } 84 85 /// Get the inner pointer. 86 pub fn into_ptr(self) -> Pointer<u8> { 87 self.ptr 88 } 89 90 /// memcpy the block to another pointer. 91 /// 92 /// # Panics 93 /// 94 /// This will panic if the target block is smaller than the source. 95 pub fn copy_to(&self, block: &mut Block) { 96 // Bound check. 97 assert!(self.size <= block.size, "Block too small."); 98 99 unsafe { 100 ptr::copy_nonoverlapping(*self.ptr, *block.ptr, self.size); 101 } 102 } 103 104 /// "Pop" this block. 105 /// 106 /// This marks it as free, and returns the old value. 107 pub fn pop(&mut self) -> Block { 108 let empty = Block::empty(&self.ptr); 109 mem::replace(self, empty) 110 } 111 112 /// Is this block placed left to the given other block? 113 pub fn left_to(&self, to: &Block) -> bool { 114 // This won't overflow due to the end being bounded by the address space. 115 self.size + *self.ptr as usize == *to.ptr as usize 116 } 117 118 /// Split the block at some position. 119 /// 120 /// # Panics 121 /// 122 /// Panics if `pos` is out of bound. 123 pub fn split(self, pos: usize) -> (Block, Block) { 124 assert!(pos <= self.size, "Split {} out of bound (size is {})!", pos, self.size); 125 126 ( 127 Block { 128 size: pos, 129 ptr: self.ptr.duplicate(), 130 }, 131 Block { 132 size: self.size - pos, 133 ptr: unsafe { self.ptr.offset(pos as isize) }, 134 } 135 ) 136 } 137 138 /// Split this block, such that the second block is aligned to `align`. 139 /// 140 /// Returns an `None` holding the intact block if `align` is out of bounds. 141 pub fn align(&mut self, align: usize) -> Option<(Block, Block)> { 142 let aligner = align - *self.ptr as usize % align; 143 144 // Bound check. 145 if aligner < self.size { 146 // Invalidate the old block. 147 let old = self.pop(); 148 149 Some(( 150 Block { 151 size: aligner, 152 ptr: old.ptr.duplicate(), 153 }, 154 Block { 155 size: old.size - aligner, 156 ptr: unsafe { old.ptr.offset(aligner as isize) }, 157 } 158 )) 159 } else { None } 160 } 161 } 162 163 impl PartialOrd for Block { 164 fn partial_cmp(&self, other: &Block) -> Option<cmp::Ordering> { 165 self.ptr.partial_cmp(&other.ptr) 166 } 167 } 168 169 /// Compare the blocks address. 170 impl Ord for Block { 171 fn cmp(&self, other: &Block) -> cmp::Ordering { 172 self.ptr.cmp(&other.ptr) 173 } 174 } 175 176 impl cmp::PartialEq for Block { 177 fn eq(&self, other: &Block) -> bool { 178 self.size == other.size && *self.ptr == *other.ptr 179 } 180 } 181 182 impl cmp::Eq for Block {} 183 184 impl fmt::Debug for Block { 185 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 186 write!(f, "0x{:x}[0x{:x}]", *self.ptr as usize, self.size) 187 } 188 } 189 190 #[cfg(test)] 191 mod test { 192 use super::*; 193 194 use ptr::Pointer; 195 196 #[test] 197 fn test_array() { 198 let arr = b"Lorem ipsum dolor sit amet"; 199 let block = unsafe { 200 Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len()) 201 }; 202 203 // Test split. 204 let (mut lorem, mut rest) = block.split(5); 205 assert_eq!(lorem.size(), 5); 206 assert_eq!(lorem.size() + rest.size(), arr.len()); 207 assert!(lorem < rest); 208 209 /* TODO 210 assert_eq!(unsafe { 211 slice::from_raw_parts(*lorem.into_ptr() as *const _, lorem.size()) 212 }, b"Lorem"); 213 */ 214 215 assert_eq!(lorem, lorem); 216 assert!(rest.is_empty()); 217 assert!(lorem.align(2).unwrap().1.aligned_to(2)); 218 assert!(rest.align(16).unwrap().1.aligned_to(16)); 219 assert_eq!(*lorem.into_ptr() as usize + 5, *rest.into_ptr() as usize); 220 } 221 222 #[test] 223 fn test_merge() { 224 let arr = b"Lorem ipsum dolor sit amet"; 225 let block = unsafe { 226 Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len()) 227 }; 228 229 let (mut lorem, mut rest) = block.split(5); 230 lorem.merge_right(&mut rest).unwrap(); 231 } 232 233 #[test] 234 #[should_panic] 235 fn test_oob() { 236 let arr = b"lorem"; 237 let block = unsafe { 238 Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len()) 239 }; 240 241 // Test OOB. 242 block.split(6); 243 } 244 } 245