Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static Allocator - Aligned allocations #31

Merged
merged 5 commits into from
May 15, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 17 additions & 24 deletions osrf_testing_tools_cpp/src/memory_tools/impl/linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,21 @@ find_original_function(const char * name)
return original_function;
}

// An amount of memory that is greater than what is needed for static initialization
// for any test we run. It was found experimentally on Ubuntu Linux 16.04 x86_64.
static const size_t STATIC_ALLOCATOR_SIZE = 0x800000;
emersonknapp marked this conversation as resolved.
Show resolved Hide resolved
using osrf_testing_tools_cpp::memory_tools::impl::StaticAllocator;
// the size was found experimentally on Ubuntu Linux 16.04 x86_64
using StaticAllocatorT = StaticAllocator<8388608>;
// used to fullfil calloc call from dlerror.c during initialization of original functions
// constructor is called on first use with a placement-new and the static storage
using StaticAllocatorT = StaticAllocator<STATIC_ALLOCATOR_SIZE>;
static uint8_t g_static_allocator_storage[sizeof(StaticAllocatorT)];
static StaticAllocatorT * g_static_allocator = nullptr;

// Contains global allocator to make 100% sure to avoid Static Initialization Order Fiasco.
// "Construct on first use" idiom
StaticAllocatorT * g_static_allocator() {
emersonknapp marked this conversation as resolved.
Show resolved Hide resolved
// placement-new the static allocator in preallocated storage
// which is used while finding the original memory functions
static StaticAllocatorT * alloc = new (g_static_allocator_storage) StaticAllocatorT;
return alloc;
}

// storage for original malloc/realloc/calloc/free
using MallocSignature = void * (*)(size_t);
Expand Down Expand Up @@ -78,12 +86,7 @@ void *
malloc(size_t size) noexcept
{
if (!get_static_initialization_complete()) {
if (nullptr == g_static_allocator) {
// placement-new the static allocator
// which is used while finding the original memory functions
g_static_allocator = new (g_static_allocator_storage) StaticAllocatorT;
}
return g_static_allocator->allocate(size);
return g_static_allocator()->allocate(size);
}
return unix_replacement_malloc(size, g_original_malloc);
}
Expand All @@ -92,12 +95,7 @@ void *
realloc(void * pointer, size_t size) noexcept
{
if (!get_static_initialization_complete()) {
if (nullptr == g_static_allocator) {
// placement-new the static allocator
// which is used while finding the original memory functions
g_static_allocator = new (g_static_allocator_storage) StaticAllocatorT;
}
return g_static_allocator->reallocate(pointer, size);
return g_static_allocator()->reallocate(pointer, size);
}
return unix_replacement_realloc(pointer, size, g_original_realloc);
}
Expand All @@ -106,20 +104,15 @@ void *
calloc(size_t count, size_t size) noexcept
{
if (!get_static_initialization_complete()) {
if (nullptr == g_static_allocator) {
// placement-new the static allocator
// which is used while finding the original memory functions
g_static_allocator = new (g_static_allocator_storage) StaticAllocatorT;
}
return g_static_allocator->zero_allocate(count, size);
return g_static_allocator()->zero_allocate(count, size);
}
return unix_replacement_calloc(count, size, g_original_calloc);
}

void
free(void * pointer) noexcept
{
if (nullptr == pointer || g_static_allocator->deallocate(pointer)) {
if (nullptr == pointer || g_static_allocator()->deallocate(pointer)) {
// free of nullptr or,
// memory was originally allocated by static allocator, no need to pass to "real" free
return;
Expand Down
22 changes: 11 additions & 11 deletions osrf_testing_tools_cpp/src/memory_tools/impl/static_allocator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ class StaticAllocator
void *
allocate(size_t size)
{
if (size <= size_t(std::distance(stack_pointer_, end_))) {
auto const aligned_size = align_up(size);
emersonknapp marked this conversation as resolved.
Show resolved Hide resolved
if (aligned_size <= static_cast<decltype(aligned_size)>(std::distance(end_, stack_pointer_))) {
emersonknapp marked this conversation as resolved.
Show resolved Hide resolved
uint8_t * result = stack_pointer_;
stack_pointer_ += size;
stack_pointer_ += aligned_size;
return result;
}
SAFE_FWRITE(stderr, "StackAllocator.allocate() -> nullptr\n");
Expand Down Expand Up @@ -105,7 +106,14 @@ class StaticAllocator
}

private:
uint8_t memory_pool_[MemoryPoolSize];
static std::size_t
align_up(std::size_t n) noexcept
{
return (n+(alignment-1)) & ~(alignment-1);
wjwwood marked this conversation as resolved.
Show resolved Hide resolved
}

static auto constexpr alignment = alignof(std::max_align_t);
emersonknapp marked this conversation as resolved.
Show resolved Hide resolved
alignas(alignment) uint8_t memory_pool_[MemoryPoolSize];
emersonknapp marked this conversation as resolved.
Show resolved Hide resolved
uint8_t * begin_;
uint8_t * end_;
uint8_t * stack_pointer_;
Expand All @@ -115,12 +123,4 @@ class StaticAllocator
} // namespace memory_tools
} // namespace osrf_testing_tools_cpp

int main(void)
{
osrf_testing_tools_cpp::memory_tools::impl::StaticAllocator<64> sa;
void * mem = sa.allocate(16);
(void)mem;
return 0;
}

#endif // MEMORY_TOOLS__IMPL__STATIC_ALLOCATOR_HPP_