change: change code style to Linux style except indent.
This commit is contained in:
+249
-245
@@ -31,7 +31,8 @@
|
||||
|
||||
#include "common/define.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief MemoryPool base class
|
||||
@@ -46,386 +47,389 @@ namespace olive {
|
||||
* `Get()` will return an ElementPtr. The original desired data can be accessed through ElementPtr::data(). This data
|
||||
* will belong to the caller until ElementPtr goes out of scope and the memory is freed back into the pool.
|
||||
*/
|
||||
class MemoryPool : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
class MemoryPool : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param element_count
|
||||
*
|
||||
* Number of elements per arena
|
||||
*/
|
||||
MemoryPool(int element_count)
|
||||
{
|
||||
element_count_ = element_count;
|
||||
MemoryPool(int element_count)
|
||||
{
|
||||
element_count_ = element_count;
|
||||
|
||||
clear_timer_ = new QTimer();
|
||||
clear_timer_->setInterval(kMaxEmptyArenaLife);
|
||||
clear_timer_->moveToThread(qApp->thread());
|
||||
connect(clear_timer_, &QTimer::timeout, this, &MemoryPool::ClearEmptyArenas, Qt::DirectConnection);
|
||||
QMetaObject::invokeMethod(clear_timer_, "start", Qt::QueuedConnection);
|
||||
}
|
||||
clear_timer_ = new QTimer();
|
||||
clear_timer_->setInterval(kMaxEmptyArenaLife);
|
||||
clear_timer_->moveToThread(qApp->thread());
|
||||
connect(clear_timer_, &QTimer::timeout, this,
|
||||
&MemoryPool::ClearEmptyArenas, Qt::DirectConnection);
|
||||
QMetaObject::invokeMethod(clear_timer_, "start", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Destructor
|
||||
*
|
||||
* Deletes all arenas.
|
||||
*/
|
||||
virtual ~MemoryPool()
|
||||
{
|
||||
Clear();
|
||||
clear_timer_->deleteLater();
|
||||
}
|
||||
virtual ~MemoryPool()
|
||||
{
|
||||
Clear();
|
||||
clear_timer_->deleteLater();
|
||||
}
|
||||
|
||||
DISABLE_COPY_MOVE(MemoryPool)
|
||||
DISABLE_COPY_MOVE(MemoryPool)
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Clears all arenas, freeing all of their memory
|
||||
*
|
||||
* Note that this function is not safe, any elements that are still out there will be invalid
|
||||
* and accessing them will cause a crash. You'll need to make sure all elements are already
|
||||
* relinquished before then.
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
qDeleteAll(arenas_);
|
||||
arenas_.clear();
|
||||
}
|
||||
void Clear()
|
||||
{
|
||||
qDeleteAll(arenas_);
|
||||
arenas_.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Returns whether any arenas are successfully allocated
|
||||
*/
|
||||
inline bool IsAllocated() const
|
||||
{
|
||||
return !arenas_.empty();
|
||||
}
|
||||
inline bool IsAllocated() const
|
||||
{
|
||||
return !arenas_.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Returns current number of allocated arenas
|
||||
*/
|
||||
inline int GetArenaCount() const
|
||||
{
|
||||
return arenas_.size();
|
||||
}
|
||||
inline int GetArenaCount() const
|
||||
{
|
||||
return arenas_.size();
|
||||
}
|
||||
|
||||
class Arena;
|
||||
class Arena;
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief A handle for a chunk of memory in an arena
|
||||
*
|
||||
* Calling Get() on the pool or arena will return a shared pointer to an element which will contain a pointer to
|
||||
* the desired object/data in data(). When Element is destroyed (i.e. when ElementPtr goes out of scope), the memory
|
||||
* is released back into the pool so it can be used by another class.
|
||||
*/
|
||||
class Element {
|
||||
public:
|
||||
/**
|
||||
class Element {
|
||||
public:
|
||||
/**
|
||||
* @brief Element Constructor
|
||||
*
|
||||
* There is no need to use this outside of the memory pool's internal functions.
|
||||
*/
|
||||
Element(Arena* parent, uint8_t* data)
|
||||
{
|
||||
parent_ = parent;
|
||||
data_ = data;
|
||||
accessed_ = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
Element(Arena *parent, uint8_t *data)
|
||||
{
|
||||
parent_ = parent;
|
||||
data_ = data;
|
||||
accessed_ = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Element Destructor
|
||||
*
|
||||
* Automatically releases this element's memory back to the arena it was retrieved from.
|
||||
*/
|
||||
~Element()
|
||||
{
|
||||
release();
|
||||
}
|
||||
~Element()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
DISABLE_COPY_MOVE(Element)
|
||||
DISABLE_COPY_MOVE(Element)
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Access data represented in the pool
|
||||
*/
|
||||
inline uint8_t* data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
inline uint8_t *data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
inline const int64_t& timestamp() const
|
||||
{
|
||||
return timestamp_;
|
||||
}
|
||||
inline const int64_t ×tamp() const
|
||||
{
|
||||
return timestamp_;
|
||||
}
|
||||
|
||||
inline void set_timestamp(const int64_t& timestamp)
|
||||
{
|
||||
timestamp_ = timestamp;
|
||||
}
|
||||
inline void set_timestamp(const int64_t ×tamp)
|
||||
{
|
||||
timestamp_ = timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Register that this element has been accessed
|
||||
*
|
||||
* \see last_accessed()
|
||||
*/
|
||||
inline void access()
|
||||
{
|
||||
accessed_ = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
inline void access()
|
||||
{
|
||||
accessed_ = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Returns the last time `access()` was called on this function
|
||||
*
|
||||
* Useful for determining the relative age of an element (i.e. if it hasn't been accessed for a certain amount of
|
||||
* time, it can probably be freed back into the pool). This requires all usages to call `access()`.
|
||||
*/
|
||||
inline const int64_t& last_accessed() const
|
||||
{
|
||||
return accessed_;
|
||||
}
|
||||
inline const int64_t &last_accessed() const
|
||||
{
|
||||
return accessed_;
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if (data_) {
|
||||
parent_->Release(this);
|
||||
data_ = nullptr;
|
||||
}
|
||||
}
|
||||
void release()
|
||||
{
|
||||
if (data_) {
|
||||
parent_->Release(this);
|
||||
data_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Arena* parent_;
|
||||
private:
|
||||
Arena *parent_;
|
||||
|
||||
uint8_t* data_;
|
||||
uint8_t *data_;
|
||||
|
||||
int64_t timestamp_;
|
||||
int64_t timestamp_;
|
||||
|
||||
int64_t accessed_;
|
||||
int64_t accessed_;
|
||||
};
|
||||
|
||||
};
|
||||
using ElementPtr = std::shared_ptr<Element>;
|
||||
|
||||
using ElementPtr = std::shared_ptr<Element>;
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief A memory pool arena - a subsection of memory
|
||||
*
|
||||
* The pool itself does not store memory, it stores "arenas". This is so that the pool can handle the situation of
|
||||
* an arena becoming full with no more memory to lend. A pool can automatically allocate another arena and continue
|
||||
* providing memory (and freeing arenas when they're no longer in use).
|
||||
*/
|
||||
class Arena {
|
||||
public:
|
||||
Arena(MemoryPool* parent)
|
||||
{
|
||||
parent_ = parent;
|
||||
data_ = nullptr;
|
||||
allocated_sz_ = 0;
|
||||
empty_time_ = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
class Arena {
|
||||
public:
|
||||
Arena(MemoryPool *parent)
|
||||
{
|
||||
parent_ = parent;
|
||||
data_ = nullptr;
|
||||
allocated_sz_ = 0;
|
||||
empty_time_ = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
~Arena()
|
||||
{
|
||||
std::list<Element*> copy = lent_elements_;
|
||||
foreach (Element* e, copy) {
|
||||
e->release();
|
||||
}
|
||||
~Arena()
|
||||
{
|
||||
std::list<Element *> copy = lent_elements_;
|
||||
foreach (Element *e, copy) {
|
||||
e->release();
|
||||
}
|
||||
|
||||
delete [] data_;
|
||||
}
|
||||
delete[] data_;
|
||||
}
|
||||
|
||||
DISABLE_COPY_MOVE(Arena)
|
||||
DISABLE_COPY_MOVE(Arena)
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Returns an element if there is free memory to do so
|
||||
*/
|
||||
ElementPtr Get()
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
ElementPtr Get()
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
|
||||
for (int i=0;i<available_.size();i++) {
|
||||
if (available_.at(i)) {
|
||||
// This buffer is available
|
||||
available_.replace(i, false);
|
||||
for (int i = 0; i < available_.size(); i++) {
|
||||
if (available_.at(i)) {
|
||||
// This buffer is available
|
||||
available_.replace(i, false);
|
||||
|
||||
ElementPtr e = std::make_shared<Element>(this,
|
||||
reinterpret_cast<uint8_t*>(data_ + i * element_sz_));
|
||||
lent_elements_.push_back(e.get());
|
||||
ElementPtr e = std::make_shared<Element>(
|
||||
this,
|
||||
reinterpret_cast<uint8_t *>(data_ + i * element_sz_));
|
||||
lent_elements_.push_back(e.get());
|
||||
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Releases an element back into the pool for use elsewhere
|
||||
*/
|
||||
void Release(Element* e)
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
quintptr diff = reinterpret_cast<quintptr>(e->data()) - reinterpret_cast<quintptr>(data_);
|
||||
void Release(Element *e)
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
quintptr diff = reinterpret_cast<quintptr>(e->data()) -
|
||||
reinterpret_cast<quintptr>(data_);
|
||||
|
||||
int index = diff / element_sz_;
|
||||
int index = diff / element_sz_;
|
||||
|
||||
available_.replace(index, true);
|
||||
available_.replace(index, true);
|
||||
|
||||
lent_elements_.remove(e);
|
||||
lent_elements_.remove(e);
|
||||
|
||||
if (lent_elements_.empty()) {
|
||||
empty_time_ = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
}
|
||||
if (lent_elements_.empty()) {
|
||||
empty_time_ = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
}
|
||||
|
||||
int GetUsageCount()
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
return lent_elements_.size();
|
||||
}
|
||||
int GetUsageCount()
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
return lent_elements_.size();
|
||||
}
|
||||
|
||||
bool Allocate(size_t ele_sz, size_t nb_elements)
|
||||
{
|
||||
if (IsAllocated()) {
|
||||
return true;
|
||||
}
|
||||
bool Allocate(size_t ele_sz, size_t nb_elements)
|
||||
{
|
||||
if (IsAllocated()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
element_sz_ = ele_sz;
|
||||
element_sz_ = ele_sz;
|
||||
|
||||
allocated_sz_ = element_sz_ * nb_elements;
|
||||
allocated_sz_ = element_sz_ * nb_elements;
|
||||
|
||||
if ((data_ = new uint8_t[allocated_sz_])) {
|
||||
available_.resize(nb_elements);
|
||||
available_.fill(true);
|
||||
if ((data_ = new uint8_t[allocated_sz_])) {
|
||||
available_.resize(nb_elements);
|
||||
available_.fill(true);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
available_.clear();
|
||||
return true;
|
||||
} else {
|
||||
available_.clear();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline int GetElementCount() const
|
||||
{
|
||||
return available_.size();
|
||||
}
|
||||
inline int GetElementCount() const
|
||||
{
|
||||
return available_.size();
|
||||
}
|
||||
|
||||
inline bool IsAllocated() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
inline bool IsAllocated() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
inline qint64 GetTimeArenaWasMadeEmpty()
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
return empty_time_;
|
||||
}
|
||||
inline qint64 GetTimeArenaWasMadeEmpty()
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
return empty_time_;
|
||||
}
|
||||
|
||||
private:
|
||||
MemoryPool* parent_;
|
||||
private:
|
||||
MemoryPool *parent_;
|
||||
|
||||
uint8_t* data_;
|
||||
uint8_t *data_;
|
||||
|
||||
size_t allocated_sz_;
|
||||
size_t allocated_sz_;
|
||||
|
||||
QVector<bool> available_;
|
||||
QVector<bool> available_;
|
||||
|
||||
QMutex lock_;
|
||||
QMutex lock_;
|
||||
|
||||
size_t element_sz_;
|
||||
size_t element_sz_;
|
||||
|
||||
std::list<Element*> lent_elements_;
|
||||
std::list<Element *> lent_elements_;
|
||||
|
||||
qint64 empty_time_;
|
||||
qint64 empty_time_;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Retrieves an element from an available arena
|
||||
*/
|
||||
ElementPtr Get()
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
ElementPtr Get()
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
|
||||
// Attempt to get an element from an arena
|
||||
foreach (Arena* a, arenas_) {
|
||||
ElementPtr e = a->Get();
|
||||
// Attempt to get an element from an arena
|
||||
foreach (Arena *a, arenas_) {
|
||||
ElementPtr e = a->Get();
|
||||
|
||||
if (e) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
if (e) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
// All arenas were empty, we'll need to create a new one
|
||||
if (arenas_.empty()) {
|
||||
qDebug() << "No arenas, creating new...";
|
||||
} else {
|
||||
qDebug() << "All arenas are full, creating new...";
|
||||
}
|
||||
// All arenas were empty, we'll need to create a new one
|
||||
if (arenas_.empty()) {
|
||||
qDebug() << "No arenas, creating new...";
|
||||
} else {
|
||||
qDebug() << "All arenas are full, creating new...";
|
||||
}
|
||||
|
||||
size_t ele_sz = GetElementSize();
|
||||
size_t ele_sz = GetElementSize();
|
||||
|
||||
if (!ele_sz) {
|
||||
qCritical() << "Failed to create arena, element size was 0";
|
||||
return nullptr;
|
||||
}
|
||||
if (!ele_sz) {
|
||||
qCritical() << "Failed to create arena, element size was 0";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (element_count_ <= 0) {
|
||||
qCritical() << "Failed to create arena, element count was invalid:" << element_count_;
|
||||
return nullptr;
|
||||
}
|
||||
if (element_count_ <= 0) {
|
||||
qCritical() << "Failed to create arena, element count was invalid:"
|
||||
<< element_count_;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Arena* a = new Arena(this);
|
||||
if (!a->Allocate(ele_sz, element_count_)) {
|
||||
qCritical() << "Failed to create arena, allocation failed. Out of memory?";
|
||||
delete a;
|
||||
return nullptr;
|
||||
}
|
||||
Arena *a = new Arena(this);
|
||||
if (!a->Allocate(ele_sz, element_count_)) {
|
||||
qCritical()
|
||||
<< "Failed to create arena, allocation failed. Out of memory?";
|
||||
delete a;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
arenas_.push_back(a);
|
||||
return a->Get();
|
||||
}
|
||||
arenas_.push_back(a);
|
||||
return a->Get();
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
/**
|
||||
* @brief The size of each element
|
||||
*
|
||||
* Override this to use a custom size (e.g. a char array where T = char but the element size is > 1)
|
||||
*/
|
||||
virtual size_t GetElementSize()
|
||||
{
|
||||
return sizeof(uint8_t);
|
||||
}
|
||||
virtual size_t GetElementSize()
|
||||
{
|
||||
return sizeof(uint8_t);
|
||||
}
|
||||
|
||||
private:
|
||||
int element_count_;
|
||||
int element_count_;
|
||||
|
||||
std::list<Arena*> arenas_;
|
||||
std::list<Arena *> arenas_;
|
||||
|
||||
QMutex lock_;
|
||||
QMutex lock_;
|
||||
|
||||
QTimer *clear_timer_;
|
||||
QTimer *clear_timer_;
|
||||
|
||||
static const qint64 kMaxEmptyArenaLife = 5000;
|
||||
static const qint64 kMaxEmptyArenaLife = 5000;
|
||||
|
||||
private slots:
|
||||
void ClearEmptyArenas()
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
void ClearEmptyArenas()
|
||||
{
|
||||
QMutexLocker locker(&lock_);
|
||||
|
||||
const qint64 min_time = QDateTime::currentMSecsSinceEpoch() - kMaxEmptyArenaLife;
|
||||
const qint64 min_time =
|
||||
QDateTime::currentMSecsSinceEpoch() - kMaxEmptyArenaLife;
|
||||
|
||||
for (auto it=arenas_.begin(); it!=arenas_.end(); ) {
|
||||
Arena* arena = (*it);
|
||||
|
||||
if (arena->GetUsageCount() == 0 && arena->GetTimeArenaWasMadeEmpty() <= min_time) {
|
||||
qDebug() << "Removing an empty arena";
|
||||
delete arena;
|
||||
it = arenas_.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto it = arenas_.begin(); it != arenas_.end();) {
|
||||
Arena *arena = (*it);
|
||||
|
||||
if (arena->GetUsageCount() == 0 &&
|
||||
arena->GetTimeArenaWasMadeEmpty() <= min_time) {
|
||||
qDebug() << "Removing an empty arena";
|
||||
delete arena;
|
||||
it = arenas_.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user