You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
4.5 KiB
C++

/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsRAN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSRAN_CIRCULAR_MAP_STACK_POOL_H
#define SRSRAN_CIRCULAR_MAP_STACK_POOL_H
#include "batch_mem_pool.h"
#include "linear_allocator.h"
#include "srsran/adt/circular_array.h"
#include <mutex>
namespace srsran {
template <size_t NofStacks>
class circular_stack_pool
{
struct mem_block_elem_t {
std::mutex mutex;
size_t key = std::numeric_limits<size_t>::max();
size_t count = 0;
linear_allocator alloc;
void clear()
{
key = std::numeric_limits<size_t>::max();
count = 0;
alloc.clear();
}
};
public:
circular_stack_pool(size_t nof_objs_per_batch, size_t stack_size, size_t batch_thres, int initial_size = -1) :
central_cache(std::min(NofStacks, nof_objs_per_batch), stack_size, batch_thres, initial_size),
logger(srslog::fetch_basic_logger("POOL"))
{}
circular_stack_pool(circular_stack_pool&&) = delete;
circular_stack_pool(const circular_stack_pool&) = delete;
circular_stack_pool& operator=(circular_stack_pool&&) = delete;
circular_stack_pool& operator=(const circular_stack_pool&) = delete;
~circular_stack_pool()
{
for (mem_block_elem_t& elem : pools) {
std::unique_lock<std::mutex> lock(elem.mutex);
srsran_expect(elem.count == 0, "There are missing deallocations for stack id=%zd", elem.key);
if (elem.alloc.is_init()) {
void* ptr = elem.alloc.memblock_ptr();
elem.alloc.clear();
central_cache.deallocate_node(ptr);
}
}
}
void* allocate(size_t key, size_t size, size_t alignment) noexcept
{
size_t idx = key % NofStacks;
mem_block_elem_t& elem = pools[idx];
std::unique_lock<std::mutex> lock(elem.mutex);
if (not elem.alloc.is_init()) {
void* block = central_cache.allocate_node(central_cache.get_node_max_size());
if (block == nullptr) {
logger.warning("Failed to allocate memory block from central cache");
return nullptr;
}
elem.key = key;
elem.alloc = linear_allocator(block, central_cache.get_node_max_size());
}
void* ptr = elem.alloc.allocate(size, alignment);
if (ptr == nullptr) {
logger.warning("No space left in memory block with key=%zd of circular stack pool", key);
} else {
elem.count++;
}
return ptr;
}
void deallocate(size_t key, void* p)
{
size_t idx = key % NofStacks;
mem_block_elem_t& elem = pools[idx];
std::lock_guard<std::mutex> lock(elem.mutex);
elem.alloc.deallocate(p);
elem.count--;
if (elem.count == 0) {
// return back to central cache
void* ptr = elem.alloc.memblock_ptr();
elem.clear();
central_cache.deallocate_node(ptr);
}
}
void allocate_batch() { central_cache.allocate_batch(); }
size_t cache_size() const { return central_cache.cache_size(); }
private:
srsran::circular_array<mem_block_elem_t, NofStacks> pools;
srsran::background_mem_pool central_cache;
srslog::basic_logger& logger;
};
template <typename T, size_t N, typename... Args>
unique_pool_ptr<T> make_pool_obj_with_fallback(circular_stack_pool<N>& pool, size_t key, Args&&... args)
{
void* block = pool.allocate(key, sizeof(T), alignof(T));
if (block == nullptr) {
// allocated with "new" as a fallback
return unique_pool_ptr<T>(new T(std::forward<Args>(args)...), std::default_delete<T>());
}
// allocation using memory pool was successful
new (block) T(std::forward<Args>(args)...);
return unique_pool_ptr<T>(static_cast<T*>(block), [key, &pool](T* ptr) {
ptr->~T();
pool.deallocate(key, ptr);
});
}
} // namespace srsran
#endif // SRSRAN_CIRCULAR_MAP_STACK_POOL_H