use memory::bucket::Bucket;
use memory::bucket::BUCKET_PAGES;
use memory::heap::Heap;
use memory::heapbucket::HeapBucket;
use memory::page::Page;
use memory::page::PAGE_SIZE;
use std::alloc::alloc;
use std::alloc::dealloc;
use std::alloc::Layout;
use std::mem::size_of;
use std::ptr::null_mut;
use std::usize::MAX;
pub struct Pool {
pub map: usize,
heap: *mut Heap,
}
impl Pool {
pub fn create(heap: *mut Heap) -> *mut Pool {
unsafe {
let memory = alloc(Layout::from_size_align_unchecked(
PAGE_SIZE * BUCKET_PAGES * BUCKET_PAGES,
PAGE_SIZE * BUCKET_PAGES,
));
if memory == null_mut() {
panic!("Unable to create pool: Out of memory.");
}
let mut pool: *mut Pool = null_mut();
for i in 0..BUCKET_PAGES {
let bucket_page = (memory as usize + PAGE_SIZE * BUCKET_PAGES * i) as *mut Page;
(*bucket_page).reset();
let bucket = (*bucket_page).allocate(Bucket::Heap(HeapBucket {
pool: null_mut(),
map: MAX,
}));
if i == 0 {
pool = (*bucket_page).allocate(Pool {
map: MAX,
heap: heap,
});
}
match *bucket {
Bucket::Stack(ref _s) => (),
Bucket::Heap(ref mut h) => h.pool = pool,
}
}
pool
}
}
pub fn allocate_page(&mut self) -> *mut Page {
if self.map == 0 {
unsafe {
(*self.heap).mark_as_full(self);
return (*self.heap).allocate_page();
};
}
let pool_page_address = Page::get(self as *const Pool as usize) as usize;
let bucket_page_address = {
let position = Bucket::find_least_position(self.map);
pool_page_address + PAGE_SIZE * BUCKET_PAGES * (position - 1)
};
let bucket = (bucket_page_address + size_of::<Page>()) as *mut Bucket;
unsafe { (*bucket).allocate_page() }
}
fn get_allocation_bit(&self, page: usize) -> usize {
let first_bucket_address = Page::get(self as *const Pool as usize) as usize;
let distance = page - first_bucket_address;
let position = distance / PAGE_SIZE / BUCKET_PAGES;
1 << (BUCKET_PAGES - 1 - position)
}
pub fn mark_as_full(&mut self, page: usize) {
let bit = self.get_allocation_bit(page);
self.map = self.map & !bit;
}
pub fn mark_as_free(&mut self, page: usize) {
let bit = self.get_allocation_bit(page);
let old_map = self.map;
self.map = self.map | bit;
if old_map == 0 {
unsafe {
(*self.heap).mark_as_free(self);
}
}
}
pub fn deallocate(&mut self) {
if self.map != MAX {
panic!("Pool is not empty!")
}
unsafe {
dealloc(
Page::get(self as *const Pool as usize) as *mut u8,
Layout::from_size_align(
PAGE_SIZE * BUCKET_PAGES * BUCKET_PAGES,
PAGE_SIZE * BUCKET_PAGES,
)
.unwrap(),
);
}
}
}