Optional thread-safety for default allocator

This commit is contained in:
Pavel Kirienko
2015-10-16 16:46:10 +03:00
parent 12c5fc8256
commit 04381686bd
+47 -13
View File
@@ -34,9 +34,22 @@ public:
/**
* Classic implementation of a pool allocator (Meyers).
*
* The allocator can be made thread-safe (optional) by means of providing a RAII-lock type via the second template
* argument. The allocator uses the lock only to access the shared state, therefore critical sections are only a few
* cycles long, which implies that it should be acceptable to use hardware IRQ disabling instead of a mutex for
* performance reasons. For example, an IRQ-based RAII-lock type can be implemented as follows:
* struct RaiiSynchronizer
* {
* RaiiSynchronizer() { __disable_irq(); }
* ~RaiiSynchronizer() { __enable_irq(); }
* };
*/
template <std::size_t PoolSize, uint8_t BlockSize>
class UAVCAN_EXPORT PoolAllocator : public IPoolAllocator, Noncopyable
template <std::size_t PoolSize,
uint8_t BlockSize,
typename RaiiSynchronizer = char>
class UAVCAN_EXPORT PoolAllocator : public IPoolAllocator,
Noncopyable
{
union Node
{
@@ -69,13 +82,28 @@ public:
/**
* Return the number of blocks that are currently allocated/unallocated.
*/
uint16_t getNumUsedBlocks() const { return used_; }
uint16_t getNumFreeBlocks() const { return static_cast<uint16_t>(NumBlocks - used_); }
uint16_t getNumUsedBlocks() const
{
RaiiSynchronizer lock;
(void)lock;
return used_;
}
uint16_t getNumFreeBlocks() const
{
RaiiSynchronizer lock;
(void)lock;
return static_cast<uint16_t>(NumBlocks - used_);
}
/**
* Returns the maximum number of blocks that were ever allocated at the same time.
*/
uint16_t getPeakNumUsedBlocks() const { return max_used_; }
uint16_t getPeakNumUsedBlocks() const
{
RaiiSynchronizer lock;
(void)lock;
return max_used_;
}
};
/**
@@ -107,11 +135,11 @@ public:
/*
* PoolAllocator<>
*/
template <std::size_t PoolSize, uint8_t BlockSize>
const uint16_t PoolAllocator<PoolSize, BlockSize>::NumBlocks;
template <std::size_t PoolSize, uint8_t BlockSize, typename RaiiSynchronizer>
const uint16_t PoolAllocator<PoolSize, BlockSize, RaiiSynchronizer>::NumBlocks;
template <std::size_t PoolSize, uint8_t BlockSize>
PoolAllocator<PoolSize, BlockSize>::PoolAllocator() :
template <std::size_t PoolSize, uint8_t BlockSize, typename RaiiSynchronizer>
PoolAllocator<PoolSize, BlockSize, RaiiSynchronizer>::PoolAllocator() :
free_list_(reinterpret_cast<Node*>(pool_.bytes)),
used_(0),
max_used_(0)
@@ -128,14 +156,17 @@ PoolAllocator<PoolSize, BlockSize>::PoolAllocator() :
free_list_[NumBlocks - 1].next = NULL;
}
template <std::size_t PoolSize, uint8_t BlockSize>
void* PoolAllocator<PoolSize, BlockSize>::allocate(std::size_t size)
template <std::size_t PoolSize, uint8_t BlockSize, typename RaiiSynchronizer>
void* PoolAllocator<PoolSize, BlockSize, RaiiSynchronizer>::allocate(std::size_t size)
{
if (free_list_ == NULL || size > BlockSize)
{
return NULL;
}
RaiiSynchronizer lock;
(void)lock;
void* pmem = free_list_;
free_list_ = free_list_->next;
@@ -150,14 +181,17 @@ void* PoolAllocator<PoolSize, BlockSize>::allocate(std::size_t size)
return pmem;
}
template <std::size_t PoolSize, uint8_t BlockSize>
void PoolAllocator<PoolSize, BlockSize>::deallocate(const void* ptr)
template <std::size_t PoolSize, uint8_t BlockSize, typename RaiiSynchronizer>
void PoolAllocator<PoolSize, BlockSize, RaiiSynchronizer>::deallocate(const void* ptr)
{
if (ptr == NULL)
{
return;
}
RaiiSynchronizer lock;
(void)lock;
Node* p = static_cast<Node*>(const_cast<void*>(ptr));
p->next = free_list_;
free_list_ = p;