Skip to content

Commit

Permalink
Merge pull request #678 from evoskuil/master
Browse files Browse the repository at this point in the history
Refactor block_arena.
  • Loading branch information
evoskuil authored Aug 22, 2024
2 parents 926ae40 + 3920d8d commit 3d3a915
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 85 deletions.
41 changes: 25 additions & 16 deletions include/bitcoin/node/block_arena.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,37 +40,46 @@ class BCN_API block_arena final
block_arena& operator=(block_arena&& other) NOEXCEPT;

/// Start an allocation of linked chunks.
void* start(size_t wire_size) THROWS override;
NODISCARD void* start(size_t wire_size) THROWS override;

/// Finalize allocation and reset allocator, return total allocation.
size_t detach() THROWS override;
size_t detach() NOEXCEPT override;

/// Release all chunks chained to the address.
void release(void* address) NOEXCEPT override;

protected:
struct record{ void* next; size_t size; };

/// Link a memory chunk to the allocated list.
void* link_new_chunk(size_t minimum=zero) THROWS;

/// Trim chunk to offset_, invalidates capacity.
void trim_to_offset() THROWS;
/// Link a memory chunk to the allocated stack.
void push(size_t minimum=zero) THROWS;

/// Close out chunk with link to next.
void set_record(uint8_t* next_address, size_t own_size) NOEXCEPT;
INLINE void set_link(uint8_t* next_address) NOEXCEPT
{
// Don't set previous when current is the first chunk.
if (!is_null(memory_map_))
{
BC_PUSH_WARNING(NO_REINTERPRET_CAST)
reinterpret_cast<void*&>(*memory_map_) = next_address;
BC_POP_WARNING()
}
}

/// Get size of address chunk and address of next chunk (or nullptr).
record get_record(uint8_t* address) const NOEXCEPT;
INLINE void* get_link(uint8_t* address) const NOEXCEPT
{
BC_ASSERT(!is_null(address));
BC_PUSH_WARNING(NO_REINTERPRET_CAST)
return reinterpret_cast<void*&>(*address);
BC_POP_WARNING()
}

/// Number of bytes remaining to be allocated.
size_t capacity() const NOEXCEPT;

/// Reset members (does not free).
size_t reset(size_t chunk_size=zero) NOEXCEPT;
INLINE size_t capacity() const NOEXCEPT
{
return system::floored_subtract(size_, offset_);
}

private:
static constexpr size_t record_size = sizeof(record);
constexpr size_t to_aligned(size_t value, size_t align) NOEXCEPT
{
using namespace system;
Expand Down
105 changes: 36 additions & 69 deletions src/block_arena.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ namespace node {

using namespace system;

BC_PUSH_WARNING(NO_MALLOC_OR_FREE)
BC_PUSH_WARNING(NO_REINTERPRET_CAST)
BC_PUSH_WARNING(NO_POINTER_ARITHMETIC)

// construct/destruct/assign
// ----------------------------------------------------------------------------

Expand Down Expand Up @@ -80,93 +76,66 @@ void* block_arena::start(size_t wire_size) THROWS
if (is_multiply_overflow(wire_size, multiple_))
throw allocation_exception{};

release(memory_map_);
reset(multiple_ * wire_size);
return link_new_chunk();
size_ = wire_size * multiple_;
memory_map_ = nullptr;
offset_ = zero;
total_ = zero;
push();
return memory_map_;
}

size_t block_arena::detach() THROWS
size_t block_arena::detach() NOEXCEPT
{
trim_to_offset();
set_record(nullptr, offset_);
return reset();
set_link(nullptr);
memory_map_ = nullptr;
return total_ + offset_;
}

void block_arena::release(void* address) NOEXCEPT
{
while (!is_null(address))
{
const auto value = get_record(pointer_cast<uint8_t>(address));
std::free(address/*, value.size */);
address = value.next;
const auto link = get_link(pointer_cast<uint8_t>(address));

BC_PUSH_WARNING(NO_MALLOC_OR_FREE)
std::free(address);
BC_POP_WARNING()

address = link;
}
}

// protected
// ----------------------------------------------------------------------------

void* block_arena::link_new_chunk(size_t minimum) THROWS
void block_arena::push(size_t minimum) THROWS
{
// Ensure next allocation accomodates record plus current request.
BC_ASSERT(!is_add_overflow(minimum, record_size));
size_ = std::max(size_, minimum + record_size);
static constexpr size_t link_size = sizeof(void*);

// Ensure next allocation accomodates link plus current request.
BC_ASSERT(!is_add_overflow(minimum, link_size));
size_ = std::max(size_, minimum + link_size);

// Allocate size to temporary.
BC_PUSH_WARNING(NO_MALLOC_OR_FREE)
const auto map = pointer_cast<uint8_t>(std::malloc(size_));
BC_POP_WARNING()

if (is_null(map))
throw allocation_exception{};

// Set previous chunk record pointer to new allocation and own size.
set_record(map, offset_);
offset_ = record_size;
return memory_map_ = map;
}

void block_arena::trim_to_offset() THROWS
{
// Memory map must not move. Move by realloc is allowed but not expected
// for truncation. If moves then this should drop into mmap/munmap/mremap.
////const auto map = std::realloc(memory_map_, offset_);
////if (map != memory_map_)
//// throw allocation_exception{};
}

void block_arena::set_record(uint8_t* next_address, size_t own_size) NOEXCEPT
{
// Don't set previous when current is the first chunk.
if (is_null(memory_map_))
return;

reinterpret_cast<record&>(*memory_map_) = { next_address, own_size };
total_ += own_size;
}

block_arena::record block_arena::get_record(uint8_t* address) const NOEXCEPT
{
return reinterpret_cast<const record&>(*address);
}

size_t block_arena::capacity() const NOEXCEPT
{
return floored_subtract(size_, offset_);
}

size_t block_arena::reset(size_t chunk_size) NOEXCEPT
{
// Chunk resets to nullptr/full with no total allocation.
const auto total = total_;
memory_map_ = nullptr;
offset_ = chunk_size;
size_ = chunk_size;
total_ = zero;
return total;
// Set previous chunk's link pointer to the new allocation.
set_link(map);
memory_map_ = map;
total_ += offset_;
offset_ = link_size;
}

// protected interface
// ----------------------------------------------------------------------------

void* block_arena::do_allocate(size_t bytes, size_t align) THROWS
{
BC_ASSERT(!is_null(memory_map_));
const auto aligned_offset = to_aligned(offset_, align);
const auto padding = aligned_offset - offset_;

Expand All @@ -175,14 +144,16 @@ void* block_arena::do_allocate(size_t bytes, size_t align) THROWS

if (allocation > capacity())
{
trim_to_offset();
link_new_chunk(allocation);
push(allocation);
return do_allocate(bytes, align);
}
else
{
offset_ += allocation;

BC_PUSH_WARNING(NO_POINTER_ARITHMETIC)
return memory_map_ + aligned_offset;
BC_POP_WARNING()
}
}

Expand All @@ -196,9 +167,5 @@ bool block_arena::do_is_equal(const arena& other) const NOEXCEPT
return &other == this;
}

BC_POP_WARNING()
BC_POP_WARNING()
BC_POP_WARNING()

} // namespace node
} // namespace libbitcoin

0 comments on commit 3d3a915

Please sign in to comment.