#include #include #include #include #include #include "tlsf/tlsf.h" #include "Allocator.h" //Used for dummy allocations DummyAllocator DummyAlloc; //recursive type class to avoid void *v = *(void**)v style casting struct next_t { next_t *next; size_t pool_size; }; void *data(next_t *n) { return n+sizeof(next_t); } struct AllocatorImpl { void *tlsf = 0; //singly linked list of memory pools //XXX this may violate alignment on some platforms if malloc doesn't return //nice values next_t *pools = 0; unsigned long long totalAlloced = 0; }; Allocator::Allocator(void) : transaction_active() { impl = new AllocatorImpl; size_t default_size = 10*1024*1024; impl->pools = (next_t*)malloc(default_size); impl->pools->next = 0x0; impl->pools->pool_size = default_size; size_t off = tlsf_size() + tlsf_pool_overhead() + sizeof(next_t); //printf("Generated Memory Pool with '%p'\n", impl->pools); impl->tlsf = tlsf_create_with_pool(((char*)impl->pools)+off, default_size-2*off); //printf("Allocator(%p)\n", impl); } Allocator::~Allocator(void) { next_t *n = impl->pools; while(n) { next_t *nn = n->next; free(n); n = nn; } delete impl; } void *AllocatorClass::alloc_mem(size_t mem_size) { impl->totalAlloced += mem_size; void *mem = tlsf_malloc(impl->tlsf, mem_size); //printf("Allocator.malloc(%p, %d) = %p\n", impl, mem_size, mem); //void *mem = malloc(mem_size); //printf("Allocator result = %p\n", mem); return mem; } void AllocatorClass::dealloc_mem(void *memory) { //printf("dealloc_mem(%d)\n", tlsf_block_size(memory)); tlsf_free(impl->tlsf, memory); //free(memory); } bool AllocatorClass::lowMemory(unsigned n, size_t chunk_size) const { //This should stay on the stack void *buf[n]; for(unsigned i=0; itlsf, chunk_size); bool outOfMem = false; for(unsigned i=0; itlsf, buf[i]); return outOfMem; } void AllocatorClass::addMemory(void *v, size_t mem_size) { next_t *n = impl->pools; while(n->next) n = n->next; n->next = (next_t*)v; n->next->next = 0x0; n->next->pool_size = mem_size; //printf("Inserting '%p'\n", v); off_t off = sizeof(next_t) + tlsf_pool_overhead(); void *result = tlsf_add_pool(impl->tlsf, ((char*)n->next)+off, //0x0eadbeef); mem_size-off-sizeof(size_t)); if(!result) printf("FAILED TO INSERT MEMORY POOL\n"); };//{(void)mem_size;}; #ifndef INCLUDED_tlsfbits //From tlsf internals typedef struct block_header_t { /* Points to the previous physical block. */ struct block_header_t* prev_phys_block; /* The size of this block, excluding the block header. */ size_t size; /* Next and previous free blocks. */ struct block_header_t* next_free; struct block_header_t* prev_free; } block_header_t; static const size_t block_header_free_bit = 1 << 0; #endif void Allocator::beginTransaction() { // TODO: log about unsupported nested transaction when a RT compliant // logging is available and transaction_active == true transaction_active = true; transaction_alloc_index = 0; } void Allocator::endTransaction() { // TODO: log about invalid end of transaction when a RT copmliant logging // is available and transaction_active == false transaction_active = false; } bool Allocator::memFree(void *pool) const { size_t bh_shift = sizeof(next_t)+sizeof(size_t); //Assume that memory is free to start with bool isFree = true; //Get the block header from the pool block_header_t &bh = *(block_header_t*)((char*)pool+bh_shift); //The first block must be free if((bh.size&block_header_free_bit) == 0) isFree = false; block_header_t &bhn = *(block_header_t*) (((char*)&bh)+((bh.size&~0x3)+bh_shift-2*sizeof(size_t))); //The next block must be 'non-free' and zero length if((bhn.size&block_header_free_bit) != 0) isFree = false; if((bhn.size&~0x3) != 0) isFree = false; return isFree; } int Allocator::memPools() const { int i = 1; next_t *n = impl->pools; while(n->next) { i++; n = n->next; } return i; } int Allocator::freePools() const { int i = 0; next_t *n = impl->pools->next; while(n) { if(memFree(n)) i++; n = n->next; } return i; } unsigned long long Allocator::totalAlloced() const { return impl->totalAlloced; } void Allocator::rollbackTransaction() { // if a transaction is active if (transaction_active) { // deallocate all allocated memory within this transaction for (size_t temp_idx = 0; temp_idx < transaction_alloc_index; ++temp_idx) { dealloc_mem(transaction_alloc_content[temp_idx]); } } transaction_active = false; } /* * Notes on tlsf internals * - TLSF consists of blocks linked by block headers and these form a doubly * linked list of free segments * - Original memory is [control_t pool] * base sentinal * Pools are [block_t block_t blocks ...] * Blocks are [memory block_t](??) * - These are stored in the control_t structure in an order dependent on the * size that they are * it's a bit unclear how collisions are handled here, but the basic premise * makes sense * - Additional structure is added before the start of each pool to define the * pool size and the next pool in the list as this information is not * accessible in O(good) time */