diff --git a/libuavcan/include/uavcan/dynamic_memory.hpp b/libuavcan/include/uavcan/dynamic_memory.hpp index 425d7ca6b4..51e0fb912f 100644 --- a/libuavcan/include/uavcan/dynamic_memory.hpp +++ b/libuavcan/include/uavcan/dynamic_memory.hpp @@ -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 -class UAVCAN_EXPORT PoolAllocator : public IPoolAllocator, Noncopyable +template +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(NumBlocks - used_); } + uint16_t getNumUsedBlocks() const + { + RaiiSynchronizer lock; + (void)lock; + return used_; + } + uint16_t getNumFreeBlocks() const + { + RaiiSynchronizer lock; + (void)lock; + return static_cast(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 -const uint16_t PoolAllocator::NumBlocks; +template +const uint16_t PoolAllocator::NumBlocks; -template -PoolAllocator::PoolAllocator() : +template +PoolAllocator::PoolAllocator() : free_list_(reinterpret_cast(pool_.bytes)), used_(0), max_used_(0) @@ -128,14 +156,17 @@ PoolAllocator::PoolAllocator() : free_list_[NumBlocks - 1].next = NULL; } -template -void* PoolAllocator::allocate(std::size_t size) +template +void* PoolAllocator::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::allocate(std::size_t size) return pmem; } -template -void PoolAllocator::deallocate(const void* ptr) +template +void PoolAllocator::deallocate(const void* ptr) { if (ptr == NULL) { return; } + RaiiSynchronizer lock; + (void)lock; + Node* p = static_cast(const_cast(ptr)); p->next = free_list_; free_list_ = p;