asn1: use byte buffer pool for temporary variable length field generation instead of stack array

This commit is contained in:
Francisco Paisana 2022-01-06 13:10:15 +01:00
parent e84908dec8
commit c8f7976014
4 changed files with 63 additions and 23 deletions

View File

@ -13,6 +13,7 @@
#ifndef SRSASN_COMMON_UTILS_H
#define SRSASN_COMMON_UTILS_H
#include "srsran/common/buffer_pool.h"
#include "srsran/srslog/srslog.h"
#include "srsran/support/srsran_assert.h"
#include <algorithm>
@ -21,7 +22,6 @@
#include <cstdint>
#include <cstring>
#include <limits>
#include <map>
#include <string>
#include <vector>
@ -1320,11 +1320,13 @@ public:
~varlength_field_pack_guard();
private:
bit_ref brefstart;
// bit_ref bref0;
bit_ref* bref_tracker;
uint8_t buffer[4096];
bool align;
using byte_array_t = std::array<uint8_t, srsran::byte_buffer_pool::BLOCK_SIZE>;
using byte_array_ptr = srsran::any_pool_ptr<byte_array_t>;
bit_ref brefstart;
bit_ref* bref_tracker;
byte_array_ptr buffer_ptr;
bool align;
};
class varlength_field_unpack_guard

View File

@ -157,8 +157,10 @@ private:
uint32_t capacity;
};
/// Type of global byte buffer pool
using byte_buffer_pool = concurrent_fixed_memory_pool<sizeof(byte_buffer_t)>;
/// Function used to generate unique byte buffers
inline unique_byte_buffer_t make_byte_buffer() noexcept
{
return std::unique_ptr<byte_buffer_t>(new (std::nothrow) byte_buffer_t());
@ -197,12 +199,30 @@ inline unique_byte_buffer_t make_byte_buffer(const uint8_t* payload, uint32_t le
namespace detail {
template <typename T>
struct byte_buffer_pool_deleter {
void operator()(void* ptr) { byte_buffer_pool::get_instance()->deallocate_node(ptr); }
void operator()(T* ptr) const { byte_buffer_pool::get_instance()->deallocate_node(ptr); }
};
} // namespace detail
/// Unique ptr to global byte buffer pool
template <typename T>
using buffer_pool_ptr = std::unique_ptr<T, detail::byte_buffer_pool_deleter<T> >;
/// Method to create unique_ptrs of type T allocated in global byte buffer pool
template <typename T, typename... CtorArgs>
buffer_pool_ptr<T> make_buffer_pool_obj(CtorArgs&&... args) noexcept
{
static_assert(sizeof(T) <= byte_buffer_pool::BLOCK_SIZE, "pool_bounded_vector does not fit buffer pool block size");
void* memblock = byte_buffer_pool::get_instance()->allocate_node(sizeof(T));
if (memblock == nullptr) {
return buffer_pool_ptr<T>();
}
new (memblock) T(std::forward<CtorArgs>(args)...);
return buffer_pool_ptr<T>(static_cast<T*>(memblock), detail::byte_buffer_pool_deleter<T>());
}
/**
* Class to wrap objects of type T which get allocated/deallocated using the byte_buffer_pool
* @tparam T type of the object being allocated
@ -230,21 +250,19 @@ public:
template <typename... CtorArgs>
static byte_buffer_pool_ptr<T> make(CtorArgs&&... args)
{
void* memblock = byte_buffer_pool::get_instance()->allocate_node(sizeof(T));
if (memblock == nullptr) {
return byte_buffer_pool_ptr<T>();
}
new (memblock) T(std::forward<CtorArgs>(args)...);
byte_buffer_pool_ptr<T> ret;
ret.ptr = std::unique_ptr<T, detail::byte_buffer_pool_deleter>(static_cast<T*>(memblock),
detail::byte_buffer_pool_deleter());
ret.ptr = make_buffer_pool_obj<T>(std::forward<CtorArgs>(args)...);
return ret;
};
private:
std::unique_ptr<T, detail::byte_buffer_pool_deleter> ptr;
buffer_pool_ptr<T> ptr;
};
/// unique_ptr with virtual deleter, so it can be used by any pool
template <typename T>
using any_pool_ptr = std::unique_ptr<T, std::function<void(T*)> >;
} // namespace srsran
#endif // SRSRAN_BUFFER_POOL_H

View File

@ -1412,10 +1412,15 @@ SRSASN_CODE ext_groups_unpacker_guard::unpack(cbit_ref& bref)
Open Field
*********************/
varlength_field_pack_guard::varlength_field_pack_guard(bit_ref& bref, bool align_)
varlength_field_pack_guard::varlength_field_pack_guard(bit_ref& bref, bool align_) :
buffer_ptr(srsran::make_buffer_pool_obj<byte_array_t>())
{
if (buffer_ptr == nullptr) {
// failed to allocate from global byte buffer pool. Fallback to malloc
buffer_ptr = std::unique_ptr<byte_array_t>(new byte_array_t());
}
brefstart = bref;
bref = bit_ref(&buffer[0], sizeof(buffer));
bref = bit_ref(buffer_ptr->data(), buffer_ptr->size());
bref_tracker = &bref;
align = align_;
}
@ -1423,16 +1428,15 @@ varlength_field_pack_guard::varlength_field_pack_guard(bit_ref& bref, bool align
varlength_field_pack_guard::~varlength_field_pack_guard()
{
// fill the spare bits
const bit_ref bref0 = bit_ref(&buffer[0], sizeof(buffer));
uint32_t leftover = 7 - ((bref_tracker->distance(bref0) - (uint32_t)1) % (uint32_t)8);
uint32_t leftover = 7 - ((bref_tracker->distance() - (uint32_t)1) % (uint32_t)8);
bref_tracker->pack(0, leftover);
// check how many bytes were written in total
uint32_t nof_bytes = bref_tracker->distance(bref0) / (uint32_t)8;
if (nof_bytes > sizeof(buffer)) {
uint32_t nof_bytes = bref_tracker->distance() / (uint32_t)8;
if (nof_bytes > buffer_ptr->size()) {
log_error("The packed variable sized field is too long for the reserved buffer (%zd > %zd)",
(size_t)nof_bytes,
sizeof(buffer));
buffer_ptr->size());
}
// go back in time to pack length
@ -1440,7 +1444,7 @@ varlength_field_pack_guard::~varlength_field_pack_guard()
// pack encoded bytes
for (uint32_t i = 0; i < nof_bytes; ++i) {
brefstart.pack(buffer[i], 8);
brefstart.pack((*buffer_ptr)[i], 8);
}
*bref_tracker = brefstart;
}

View File

@ -644,6 +644,21 @@ int test_big_integers()
return 0;
}
void test_varlength_field_pack()
{
uint8_t buffer[128];
bit_ref bref(&buffer[0], sizeof(buffer));
TESTASSERT_EQ(SRSRAN_SUCCESS, bref.pack(0, 1));
TESTASSERT_EQ(1, bref.distance());
{
varlength_field_pack_guard guard(bref);
TESTASSERT_EQ(0, bref.distance());
bref.pack(0, 8);
TESTASSERT_EQ(1, bref.distance_bytes());
}
TESTASSERT_EQ(17, bref.distance()); // accounts for length determinant and 1 byte of data
}
int main()
{
// Setup the log spy to intercept error and warning log entries.
@ -672,6 +687,7 @@ int main()
TESTASSERT(test_copy_ptr() == 0);
TESTASSERT(test_enum() == 0);
TESTASSERT(test_big_integers() == 0);
test_varlength_field_pack();
// TESTASSERT(test_json_writer()==0);
srslog::flush();