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

master
Francisco Paisana 3 years ago
parent e84908dec8
commit c8f7976014

@ -13,6 +13,7 @@
#ifndef SRSASN_COMMON_UTILS_H #ifndef SRSASN_COMMON_UTILS_H
#define SRSASN_COMMON_UTILS_H #define SRSASN_COMMON_UTILS_H
#include "srsran/common/buffer_pool.h"
#include "srsran/srslog/srslog.h" #include "srsran/srslog/srslog.h"
#include "srsran/support/srsran_assert.h" #include "srsran/support/srsran_assert.h"
#include <algorithm> #include <algorithm>
@ -21,7 +22,6 @@
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <limits> #include <limits>
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
@ -1320,10 +1320,12 @@ public:
~varlength_field_pack_guard(); ~varlength_field_pack_guard();
private: private:
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 brefstart;
// bit_ref bref0;
bit_ref* bref_tracker; bit_ref* bref_tracker;
uint8_t buffer[4096]; byte_array_ptr buffer_ptr;
bool align; bool align;
}; };

@ -157,8 +157,10 @@ private:
uint32_t capacity; uint32_t capacity;
}; };
/// Type of global byte buffer pool
using byte_buffer_pool = concurrent_fixed_memory_pool<sizeof(byte_buffer_t)>; 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 inline unique_byte_buffer_t make_byte_buffer() noexcept
{ {
return std::unique_ptr<byte_buffer_t>(new (std::nothrow) byte_buffer_t()); 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 { namespace detail {
template <typename T>
struct byte_buffer_pool_deleter { 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 } // 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 * Class to wrap objects of type T which get allocated/deallocated using the byte_buffer_pool
* @tparam T type of the object being allocated * @tparam T type of the object being allocated
@ -230,21 +250,19 @@ public:
template <typename... CtorArgs> template <typename... CtorArgs>
static byte_buffer_pool_ptr<T> make(CtorArgs&&... args) 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; byte_buffer_pool_ptr<T> ret;
ret.ptr = std::unique_ptr<T, detail::byte_buffer_pool_deleter>(static_cast<T*>(memblock), ret.ptr = make_buffer_pool_obj<T>(std::forward<CtorArgs>(args)...);
detail::byte_buffer_pool_deleter());
return ret; return ret;
}; };
private: 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 } // namespace srsran
#endif // SRSRAN_BUFFER_POOL_H #endif // SRSRAN_BUFFER_POOL_H

@ -1412,10 +1412,15 @@ SRSASN_CODE ext_groups_unpacker_guard::unpack(cbit_ref& bref)
Open Field 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; brefstart = bref;
bref = bit_ref(&buffer[0], sizeof(buffer)); bref = bit_ref(buffer_ptr->data(), buffer_ptr->size());
bref_tracker = &bref; bref_tracker = &bref;
align = align_; 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() varlength_field_pack_guard::~varlength_field_pack_guard()
{ {
// fill the spare bits // fill the spare bits
const bit_ref bref0 = bit_ref(&buffer[0], sizeof(buffer)); uint32_t leftover = 7 - ((bref_tracker->distance() - (uint32_t)1) % (uint32_t)8);
uint32_t leftover = 7 - ((bref_tracker->distance(bref0) - (uint32_t)1) % (uint32_t)8);
bref_tracker->pack(0, leftover); bref_tracker->pack(0, leftover);
// check how many bytes were written in total // check how many bytes were written in total
uint32_t nof_bytes = bref_tracker->distance(bref0) / (uint32_t)8; uint32_t nof_bytes = bref_tracker->distance() / (uint32_t)8;
if (nof_bytes > sizeof(buffer)) { if (nof_bytes > buffer_ptr->size()) {
log_error("The packed variable sized field is too long for the reserved buffer (%zd > %zd)", log_error("The packed variable sized field is too long for the reserved buffer (%zd > %zd)",
(size_t)nof_bytes, (size_t)nof_bytes,
sizeof(buffer)); buffer_ptr->size());
} }
// go back in time to pack length // go back in time to pack length
@ -1440,7 +1444,7 @@ varlength_field_pack_guard::~varlength_field_pack_guard()
// pack encoded bytes // pack encoded bytes
for (uint32_t i = 0; i < nof_bytes; ++i) { for (uint32_t i = 0; i < nof_bytes; ++i) {
brefstart.pack(buffer[i], 8); brefstart.pack((*buffer_ptr)[i], 8);
} }
*bref_tracker = brefstart; *bref_tracker = brefstart;
} }

@ -644,6 +644,21 @@ int test_big_integers()
return 0; 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() int main()
{ {
// Setup the log spy to intercept error and warning log entries. // Setup the log spy to intercept error and warning log entries.
@ -672,6 +687,7 @@ int main()
TESTASSERT(test_copy_ptr() == 0); TESTASSERT(test_copy_ptr() == 0);
TESTASSERT(test_enum() == 0); TESTASSERT(test_enum() == 0);
TESTASSERT(test_big_integers() == 0); TESTASSERT(test_big_integers() == 0);
test_varlength_field_pack();
// TESTASSERT(test_json_writer()==0); // TESTASSERT(test_json_writer()==0);
srslog::flush(); srslog::flush();

Loading…
Cancel
Save