diff --git a/xo-alloc2/include/xo/alloc2/RAllocator.hpp b/xo-alloc2/include/xo/alloc2/RAllocator.hpp index 3701d997..e95c7bcd 100644 --- a/xo-alloc2/include/xo/alloc2/RAllocator.hpp +++ b/xo-alloc2/include/xo/alloc2/RAllocator.hpp @@ -30,6 +30,8 @@ namespace xo { size_type available() const { return O::iface()->available(O::data()); } size_type allocated() const { return O::iface()->allocated(O::data()); } bool contains(const void * p) const { return O::iface()->contains(O::data(), p); } + AllocatorError last_error() const { return O::iface()->last_error(O::data()); } + bool expand(size_type z) { return O::iface()->expand(O::data(), z); } std::byte * alloc(size_type z) { return O::iface()->alloc(O::data(), z); } diff --git a/xo-alloc2/include/xo/alloc2/padding.hpp b/xo-alloc2/include/xo/alloc2/padding.hpp index c58908cd..f1ca0ae1 100644 --- a/xo-alloc2/include/xo/alloc2/padding.hpp +++ b/xo-alloc2/include/xo/alloc2/padding.hpp @@ -15,6 +15,11 @@ namespace xo { /** word size for alignment**/ static constexpr std::size_t c_alloc_alignment = sizeof(std::uintptr_t); + static inline std::size_t is_aligned(std::size_t n, + std::size_t align = c_alloc_alignment) { + return n % align == 0; + } + /** how much to add to @p z to get a multiple of * @ref c_alloc_alignment **/ diff --git a/xo-alloc2/src/alloc2/IAllocator_DArena.cpp b/xo-alloc2/src/alloc2/IAllocator_DArena.cpp index 89524717..dbf708b0 100644 --- a/xo-alloc2/src/alloc2/IAllocator_DArena.cpp +++ b/xo-alloc2/src/alloc2/IAllocator_DArena.cpp @@ -148,18 +148,13 @@ namespace xo { { scope log(XO_DEBUG(s.config_.debug_flag_)); - /* word size for alignment (8 bytes) */ - constexpr size_t c_bpw = sizeof(std::uintptr_t); + assert(padding::is_aligned((size_t)s.free_)); - std::uintptr_t free_u64 = reinterpret_cast(s.free_); - - assert(free_u64 % c_bpw == 0ul); - - /* dz: pad req_z to multiple c_bpw */ + /* dz: pad req_z to alignment size (multiple of 8 bytes, probably) */ size_t dz = padding::alloc_padding(req_z); size_t z1 = req_z + dz; - assert(z1 % c_bpw == 0ul); + assert(padding::is_aligned(z1)); if (expand(s, allocated(s) + z1)) [[likely]] { byte * mem = s.free_; diff --git a/xo-alloc2/utest/arena.test.cpp b/xo-alloc2/utest/arena.test.cpp index 5006c7bc..1b7643d0 100644 --- a/xo-alloc2/utest/arena.test.cpp +++ b/xo-alloc2/utest/arena.test.cpp @@ -18,8 +18,11 @@ namespace xo { using xo::mm::AAllocator; using xo::mm::IAllocator_DArena; using xo::mm::IAllocator_Xfer; + using xo::mm::AllocatorError; using xo::mm::DArena; using xo::mm::ArenaConfig; + using xo::mm::padding; + using xo::mm::error; using xo::facet::obj; using xo::scope; using std::byte; @@ -130,11 +133,76 @@ namespace xo { REQUIRE(a1o.available() == a1o.committed()); REQUIRE(a1o.allocated() == 0); -#ifdef NOPE - byte * m = a1o.alloc(1); + } - REQUIRE(m); -#endif + TEST_CASE("allocator-alloc-1", "[alloc2][AAllocator]") + { + /* typed allocator a1o */ + ArenaConfig cfg { .name_ = "testarena", + .size_ = 64*1024, + .debug_flag_ = false }; + DArena arena = DArena::map(cfg); + obj a1o{&arena}; + + REQUIRE(a1o.reserved() >= cfg.size_); + REQUIRE(a1o.committed() == 0); + REQUIRE(a1o.available() == 0); + REQUIRE(a1o.allocated() == 0); + + size_t z0 = 1; + byte * m0 = a1o.alloc(1); + + REQUIRE(m0); + REQUIRE(a1o.last_error().error_ == error::none); + REQUIRE(a1o.last_error().error_seq_ == 0); + REQUIRE(a1o.allocated() >= z0); + REQUIRE(a1o.allocated() < z0 + padding::c_alloc_alignment ); + REQUIRE(a1o.allocated() <= a1o.committed()); + REQUIRE(a1o.allocated() + a1o.available() == a1o.committed()); + REQUIRE(a1o.committed() <= a1o.reserved()); + + size_t z1 = 16; + byte * m1 = a1o.alloc(z1); + + REQUIRE(m1); + REQUIRE(a1o.last_error().error_ == error::none); + REQUIRE(a1o.last_error().error_seq_ == 0); + REQUIRE(a1o.allocated() >= z0 + z1); + REQUIRE(a1o.allocated() < z0 + z1 + 2 * padding::c_alloc_alignment ); + REQUIRE(a1o.allocated() <= a1o.committed()); + REQUIRE(a1o.allocated() + a1o.available() == a1o.committed()); + REQUIRE(a1o.committed() <= a1o.reserved()); + } + + TEST_CASE("allocator-fail-1", "[alloc2][AAllocator]") + { + /* typed allocator a1o */ + ArenaConfig cfg { .name_ = "testarena", + .size_ = 64*1024, + .debug_flag_ = false }; + DArena arena = DArena::map(cfg); + obj a1o{&arena}; + + REQUIRE(cfg.size_ <= cfg.hugepage_z_); + + REQUIRE(a1o.reserved() >= cfg.size_); + REQUIRE(a1o.committed() == 0); + REQUIRE(a1o.available() == 0); + REQUIRE(a1o.allocated() == 0); + + size_t z0 = cfg.hugepage_z_ + 1; + byte * m0 = a1o.alloc(z0); + + REQUIRE(!m0); + + AllocatorError err = a1o.last_error(); + + REQUIRE(err.error_ == error::reserve_exhausted); + REQUIRE(err.error_seq_ == 1); + REQUIRE(err.request_z_ >= z0); + REQUIRE(err.request_z_ < z0 + padding::c_alloc_alignment); + REQUIRE(err.committed_z_ == 0); + REQUIRE(err.reserved_z_ == cfg.hugepage_z_); } } /*namespace ut*/ } /*namespace xo*/