Files
FrameLib/FrameLib_Framework/FrameLib_Memory.h
T

366 lines
9.9 KiB
C++

#ifndef FRAMELIB_MEMORY_H
#define FRAMELIB_MEMORY_H
#include "../FrameLib_Dependencies/tlsf/tlsf.h"
#include "FrameLib_Types.h"
#include "FrameLib_Errors.h"
#include "FrameLib_Parameters.h"
#include "FrameLib_Threading.h"
#include <vector>
#include <ctime>
#include <string>
// The Global Allocator (adds threadsafety to the CoreAllocator)
class FrameLib_GlobalAllocator
{
private:
// The Core Allocator (has no threadsafety)
class CoreAllocator
{
// ************************************************************************************** //
// Memory Pools
struct Pool
{
Pool(void *mem, size_t size) : mUsedRecently(true), mTime(0), mSize(size), mPrev(nullptr), mNext(nullptr), mMem(mem) {}
bool isFree() { return tlsf_pool_is_free(mMem); }
bool mUsedRecently;
time_t mTime;
size_t mSize;
Pool *mPrev;
Pool *mNext;
void *mMem;
};
// ************************************************************************************** //
// Thread for Allocating System Memory
class NewThread final : public DelegateThread
{
public:
NewThread(CoreAllocator *allocator) : DelegateThread(Thread::kHighPriority), mAllocator(allocator) {}
private:
void doTask() override { mAllocator->addScheduledPool(); };
CoreAllocator *mAllocator;
};
// ************************************************************************************** //
// Thread for Freeing System Memory
class FreeThread final : public TriggerableThread
{
public:
FreeThread(CoreAllocator *allocator) : TriggerableThread(Thread::kLowPriority), mAllocator(allocator) {}
private:
void doTask() override { mAllocator->destroyScheduledPool(); };
CoreAllocator *mAllocator;
};
// ************************************************************************************** //
public:
CoreAllocator(FrameLib_ErrorReporter& errorReporter);
~CoreAllocator();
// Allocate and deallocate memory (plus pruning)
void *alloc(size_t size);
void dealloc(void *ptr);
void prune();
private:
// Get a Pool Class a tlsf pool_t
Pool *getPool(pool_t pool);
// Pool Helpers
static Pool *createPool(size_t size);
static void destroyPool(Pool *pool);
void linkPool(Pool *pool);
void unlinkPool(Pool *pool);
void poolToTop(Pool *pool);
void insertPool(Pool *pool);
void removePool(Pool *pool);
// Scheduled creation/deletion
void addScheduledPool();
void destroyScheduledPool();
// Member Variables
tlsf_t mTLSF;
Pool *mPools;
size_t mOSAllocated;
size_t mAllocated;
size_t mLastDisposedPoolSize;
AtomicPtr<Pool> mScheduledNewPool;
AtomicPtr<Pool> mScheduledDisposePool;
NewThread mAllocThread;
FreeThread mFreeThread;
FrameLib_ErrorReporter& mErrorReporter;
};
// ************************************************************************************** //
public:
// The Pruner uses RAII to lock the CoreAllocator allowing repeated deallocation followed by a prune with a single lock
class Pruner
{
public:
Pruner(FrameLib_GlobalAllocator *allocator) : mAllocator(allocator)
{
mAllocator->mLock.acquire();
}
~Pruner()
{
mAllocator->mAllocator.prune();
mAllocator->mLock.release();
}
void dealloc(void *ptr) { mAllocator->mAllocator.dealloc(ptr); }
private:
// Deleted
Pruner(const Pruner&) = delete;
Pruner& operator=(const Pruner&) = delete;
// Allocator
FrameLib_GlobalAllocator *mAllocator;
};
// ************************************************************************************** //
// Constructor / Destructor
FrameLib_GlobalAllocator(FrameLib_ErrorReporter& errorReporter) : mAllocator(errorReporter) {}
~FrameLib_GlobalAllocator() {}
// Allocate / Deallocate Memory
void *alloc(size_t size);
void dealloc(void *ptr);
// Alignment Helpers
static size_t getAlignment();
static size_t alignSize(size_t x);
private:
// Deleted
FrameLib_GlobalAllocator(const FrameLib_GlobalAllocator&) = delete;
FrameLib_GlobalAllocator& operator=(const FrameLib_GlobalAllocator&) = delete;
// Member Variables
SpinLock mLock;
CoreAllocator mAllocator;
};
// ************************************************************************************** //
// The Local Allocator
class FrameLib_LocalAllocator
{
// Local Blocks (free memory in double linked list (using internal pointers))
static const int numLocalFreeBlocks = 16;
struct FreeBlock
{
FreeBlock() : mMemory(nullptr), mSize(0), mPrev(nullptr), mNext(nullptr) {}
void *mMemory;
size_t mSize;
FreeBlock *mPrev;
FreeBlock *mNext;
};
// ************************************************************************************** //
public:
// Named Storage Local to Each Context
class Storage
{
typedef FrameLib_Parameters::Serial Serial;
friend class FrameLib_LocalAllocator;
public:
// The Access Class Enforces Thread Safety for Storage
class Access
{
public:
// Constructor and Destructor
Access(Storage *storage) : mStorage(storage) { mStorage->mLock.acquire(); }
~Access() { mStorage->mLock.release(); }
// Getters
FrameType getType() const { return mStorage->getType(); }
double *getVector() const { return mStorage->getVector(); }
unsigned long getVectorSize() const { return mStorage->getVectorSize(); }
unsigned long getTaggedSize() const { return mStorage->getTaggedSize(); }
Serial *getTagged() const { return mStorage->getTagged(); }
// Resize
void resize(bool tagged, size_t size) { mStorage->resize(tagged, size); }
private:
// Deleted
Access(const Access&) = delete;
Access& operator=(const Access&) = delete;
// Data
Storage *mStorage;
};
const char *getName() const { return mName.c_str(); }
protected:
// Getters
FrameType getType() const { return mType; }
double *getVector() const { return mType == kFrameNormal ? static_cast<double *>(mData) : nullptr; }
unsigned long getVectorSize() const { return mType == kFrameNormal ? mSize : 0; }
unsigned long getTaggedSize() const { return mType == kFrameTagged ? mSize : 0; }
Serial *getTagged() const { return mType == kFrameTagged ? static_cast<Serial *>(mData) : nullptr; }
// Resize the storage
void resize(bool tagged, size_t size);
// Constructor / Destructor
Storage(const char *name, FrameLib_LocalAllocator *allocator);
~Storage();
// Reference Counting
void increment() { mCount++; }
unsigned long decrement() { return --mCount; }
private:
// Deleted
Storage(const Storage&) = delete;
Storage& operator=(const Storage&) = delete;
// Member Variables
std::string mName;
FrameType mType;
void *mData;
size_t mSize;
size_t mMaxSize;
unsigned long mCount;
SpinLock mLock;
FrameLib_LocalAllocator *mAllocator;
};
// ************************************************************************************** //
// Constructor / Destructor
FrameLib_LocalAllocator(FrameLib_GlobalAllocator *allocator);
~FrameLib_LocalAllocator();
// Allocate / Deallocate Memory
void *alloc(size_t size);
void dealloc(void *ptr);
// Clear Local Free Blocks (and prune global allocator)
void clear();
// Alignment Helpers
static size_t getAlignment() { return FrameLib_GlobalAllocator::getAlignment(); }
static size_t alignSize(size_t x) { return FrameLib_GlobalAllocator::alignSize(x); }
// Register and Release Storage
Storage *registerStorage(const char *name);
void releaseStorage(const char *name);
private:
// Deleted
FrameLib_LocalAllocator(const FrameLib_LocalAllocator&) = delete;
FrameLib_LocalAllocator& operator=(const FrameLib_LocalAllocator&) = delete;
// Find Storage by Name
std::vector<Storage *>::iterator findStorage(const char *name);
// Remove a Free Block after Allocation and Return the Pointer
void *removeBlock(FreeBlock *block);
// Member Variables
FrameLib_GlobalAllocator *mAllocator;
FreeBlock mFreeLists[numLocalFreeBlocks];
FreeBlock *mTail;
std::vector <Storage *> mStorage;
};
#endif