|
- #include <cstddef>
- #include <cstdlib>
- #include <cassert>
- #include <utility>
- #include <cstdio>
- #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; i<n; ++i)
- buf[i] = tlsf_malloc(impl->tlsf, chunk_size);
- bool outOfMem = false;
- for(unsigned i=0; i<n; ++i)
- outOfMem |= (buf[i] == nullptr);
- for(unsigned i=0; i<n; ++i)
- if(buf[i])
- tlsf_free(impl->tlsf, 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
- */
|