xo-gc stack: coverage improvement + related tidying
This commit is contained in:
parent
002c94d02e
commit
eea239d6ad
14 changed files with 287 additions and 48 deletions
|
|
@ -35,6 +35,8 @@ namespace xo {
|
|||
|
||||
// builtin methods
|
||||
typeseq _typeseq() const noexcept override { return s_typeseq; }
|
||||
|
||||
// LCOV_EXCL_START
|
||||
void _drop(Opaque) const noexcept override { _fatal(); }
|
||||
|
||||
// const methods
|
||||
|
|
@ -58,9 +60,6 @@ namespace xo {
|
|||
[[noreturn]] value_type alloc(Opaque, typeseq, std::size_t) const override { _fatal(); }
|
||||
[[noreturn]] value_type super_alloc(Opaque, typeseq, std::size_t) const override { _fatal(); }
|
||||
[[noreturn]] value_type sub_alloc(Opaque, std::size_t, bool) const override { _fatal(); }
|
||||
#ifdef OBSOLETE
|
||||
[[noreturn]] value_type alloc_copy(Opaque, value_type) const override { _fatal(); }
|
||||
#endif
|
||||
[[noreturn]] void clear(Opaque) const override { _fatal(); }
|
||||
[[noreturn]] void barrier_assign_aux(Opaque,
|
||||
void *,
|
||||
|
|
@ -69,6 +68,7 @@ namespace xo {
|
|||
|
||||
private:
|
||||
[[noreturn]] static void _fatal();
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
public:
|
||||
static typeseq s_typeseq;
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ namespace xo {
|
|||
void * parent,
|
||||
AGCObject * lhs_iface, void ** lhs_data,
|
||||
AGCObject * rhs_iface, void * rhs_data);
|
||||
static void destruct_data(DArena &);
|
||||
//static void destruct_data(DArena &);
|
||||
};
|
||||
|
||||
// template <>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public:
|
|||
void * alloc_copy_for(const T * src) noexcept {
|
||||
return O::iface()->alloc_copy(O::data(), (std::byte *)const_cast<T *>(src));
|
||||
}
|
||||
|
||||
|
||||
/** convenience template for move-constructible T (this is common) **/
|
||||
template <typename T>
|
||||
T * std_move_for(T * src) noexcept {
|
||||
|
|
@ -62,28 +62,28 @@ public:
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/** forward faceted object pointer in place. Defined in GCObject.hpp to avoid #include cycle **/
|
||||
template <typename DRepr>
|
||||
void forward_inplace(obj<AGCObject,DRepr> * p_obj);
|
||||
|
||||
|
||||
/** another convenience template for forwarding.
|
||||
* Defined in RGCObject.hpp to avoid #include cycle.
|
||||
**/
|
||||
template <typename DRepr>
|
||||
void forward_inplace(DRepr ** pp_repr);
|
||||
|
||||
|
||||
/** convenience template where pointer requires pivot **/
|
||||
template <typename AFacet, typename DRepr>
|
||||
requires (!std::is_same_v<AFacet, AGCObject>)
|
||||
void forward_pivot_inplace(obj<AFacet,DRepr> * p_obj);
|
||||
|
||||
|
||||
/** add root @p p_root **/
|
||||
template<typename DRepr>
|
||||
void add_gc_root(obj<AGCObject, DRepr> * p_root) {
|
||||
O::iface()->add_gc_root_poly(O::data(), (obj<AGCObject> *)p_root);
|
||||
}
|
||||
|
||||
|
||||
/** remove root @p p_root **/
|
||||
template <typename DRepr>
|
||||
void remove_gc_root(obj<AGCObject, DRepr> * p_root) {
|
||||
|
|
@ -91,6 +91,7 @@ public:
|
|||
}
|
||||
|
||||
// builtin methods
|
||||
bool _has_null_vptr() const noexcept { return O::iface()->_has_null_vptr(); }
|
||||
typeseq _typeseq() const noexcept { return O::iface()->_typeseq(); }
|
||||
void _drop() const noexcept { O::iface()->_drop(O::data()); }
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ namespace xo {
|
|||
|
||||
namespace mm {
|
||||
|
||||
// LCOV_EXCL_START
|
||||
void
|
||||
IAllocator_Any::_fatal()
|
||||
{
|
||||
|
|
@ -29,6 +30,7 @@ namespace xo {
|
|||
|
||||
std::terminate();
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
typeseq
|
||||
IAllocator_Any::s_typeseq = typeseq::id<DVariantPlaceholder>();
|
||||
|
|
|
|||
|
|
@ -173,11 +173,13 @@ namespace xo {
|
|||
*lhs_data = rhs_data;
|
||||
}
|
||||
|
||||
#ifdef OBSOLETE
|
||||
void
|
||||
IAllocator_DArena::destruct_data(DArena & s)
|
||||
{
|
||||
s.~DArena();
|
||||
}
|
||||
#endif
|
||||
} /*namespace mm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ set(UTEST_SRCS
|
|||
alloc2_utest_main.cpp
|
||||
objectmodel.test.cpp
|
||||
arena.test.cpp
|
||||
IAllocator_Any.test.cpp
|
||||
DArenaIterator.test.cpp
|
||||
# Collector.test.cpp
|
||||
# DX1CollectorIterator.test.cpp
|
||||
|
|
|
|||
29
xo-alloc2/utest/IAllocator_Any.test.cpp
Normal file
29
xo-alloc2/utest/IAllocator_Any.test.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/** @file IAllocator_Any.test.cpp
|
||||
*
|
||||
* @author Roland Conybeare, May 2026
|
||||
**/
|
||||
|
||||
#include <xo/alloc2/Allocator.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
namespace xo {
|
||||
using xo::mm::AAllocator;
|
||||
|
||||
namespace ut {
|
||||
|
||||
TEST_CASE("IAllocator_Any", "[alloc2][death]")
|
||||
{
|
||||
// null allocator
|
||||
obj<AAllocator> alloc_any;
|
||||
|
||||
// NOTE: tried using a fork() strategy to verify termination,
|
||||
// but child process doesn't get measured by gcov
|
||||
}
|
||||
|
||||
} /*namespace ut*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end IAllocator_Any.test.cpp */
|
||||
|
|
@ -97,6 +97,8 @@ namespace xo {
|
|||
//obj<AAllocator, DArena> a1o{&arena};
|
||||
auto a1o = with_facet<AAllocator>::mkobj(&arena);
|
||||
|
||||
REQUIRE(!a1o._has_null_vptr());
|
||||
|
||||
REQUIRE(a1o);
|
||||
REQUIRE(a1o.iface() != nullptr);
|
||||
REQUIRE(a1o.data() != nullptr);
|
||||
|
|
@ -110,6 +112,12 @@ namespace xo {
|
|||
REQUIRE(a1o.size() == 0);
|
||||
REQUIRE(a1o.committed() == 0);
|
||||
REQUIRE(a1o.allocated() == 0);
|
||||
|
||||
a1o._drop();
|
||||
{
|
||||
REQUIRE(a1o.allocated() == 0);
|
||||
REQUIRE(a1o.committed() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("allocator-expand-1", "[alloc2][AAllocator]")
|
||||
|
|
@ -122,6 +130,8 @@ namespace xo {
|
|||
//obj<AAllocator, DArena> a1o{&arena};
|
||||
auto a1o = with_facet<AAllocator>::mkobj(&arena);
|
||||
|
||||
REQUIRE(!a1o._has_null_vptr());
|
||||
|
||||
REQUIRE(a1o.available() == 0);
|
||||
REQUIRE(a1o.allocated() == 0);
|
||||
|
||||
|
|
@ -141,6 +151,11 @@ namespace xo {
|
|||
REQUIRE(a1o.available() == a1o.committed());
|
||||
REQUIRE(a1o.allocated() == 0);
|
||||
|
||||
a1o._drop();
|
||||
{
|
||||
REQUIRE(a1o.allocated() == 0);
|
||||
REQUIRE(a1o.committed() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("allocator-alloc-1", "[alloc2][AAllocator]")
|
||||
|
|
@ -152,6 +167,8 @@ namespace xo {
|
|||
DArena arena = DArena::map(cfg);
|
||||
auto a1o = with_facet<AAllocator>::mkobj(&arena);
|
||||
|
||||
REQUIRE(!a1o._has_null_vptr());
|
||||
|
||||
REQUIRE(a1o.reserved() >= cfg.size_);
|
||||
REQUIRE(a1o.committed() == 0);
|
||||
REQUIRE(a1o.available() == 0);
|
||||
|
|
@ -180,6 +197,12 @@ namespace xo {
|
|||
REQUIRE(a1o.allocated() <= a1o.committed());
|
||||
REQUIRE(a1o.allocated() + a1o.available() == a1o.committed());
|
||||
REQUIRE(a1o.committed() <= a1o.reserved());
|
||||
|
||||
a1o._drop();
|
||||
{
|
||||
REQUIRE(a1o.allocated() == 0);
|
||||
REQUIRE(a1o.committed() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("allocator-alloc-2", "[alloc2][Allocator]")
|
||||
|
|
@ -202,6 +225,8 @@ namespace xo {
|
|||
//obj<AAllocator, DArena> a1o{&arena};
|
||||
auto a1o = with_facet<AAllocator>::mkobj(&arena);
|
||||
|
||||
REQUIRE(!a1o._has_null_vptr());
|
||||
|
||||
REQUIRE(a1o.reserved() >= cfg.size_);
|
||||
REQUIRE(a1o.committed() == 0);
|
||||
REQUIRE(a1o.available() == 0);
|
||||
|
|
@ -244,19 +269,26 @@ namespace xo {
|
|||
}
|
||||
|
||||
a1o.clear();
|
||||
{
|
||||
// allocated size got reset
|
||||
REQUIRE(a1o.allocated() == 0);
|
||||
// committed size unchanged
|
||||
REQUIRE(a1o.committed() == committed0_z);
|
||||
REQUIRE(a1o.last_error().error_ == error::ok);
|
||||
REQUIRE(a1o.last_error().error_seq_ == 0);
|
||||
|
||||
// allocated size got reset
|
||||
REQUIRE(a1o.allocated() == 0);
|
||||
// committed size unchanged
|
||||
REQUIRE(a1o.committed() == committed0_z);
|
||||
REQUIRE(a1o.last_error().error_ == error::ok);
|
||||
REQUIRE(a1o.last_error().error_seq_ == 0);
|
||||
// allocator no longer contains m0 (now points to unallocated but committed memory
|
||||
// (not exposed via AAllocator!
|
||||
// REQUIRE(a1o.contains_allocated(m0) == false);
|
||||
|
||||
// allocator no longer contains m0 (now points to unallocated but committed memory
|
||||
// (not exposed via AAllocator!
|
||||
// REQUIRE(a1o.contains_allocated(m0) == false);
|
||||
REQUIRE(a1o.contains(m0));
|
||||
}
|
||||
|
||||
REQUIRE(a1o.contains(m0));
|
||||
a1o._drop();
|
||||
{
|
||||
REQUIRE(a1o.allocated() == 0);
|
||||
REQUIRE(a1o.committed() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("allocator-alloc-3", "[alloc2][Allocator]")
|
||||
|
|
@ -279,6 +311,8 @@ namespace xo {
|
|||
//obj<AAllocator, DArena> a1o{&arena};
|
||||
auto a1o = with_facet<AAllocator>::mkobj(&arena);
|
||||
|
||||
REQUIRE(!a1o._has_null_vptr());
|
||||
|
||||
REQUIRE(a1o.reserved() >= cfg.size_);
|
||||
REQUIRE(a1o.committed() == 0);
|
||||
REQUIRE(a1o.available() == 0);
|
||||
|
|
@ -301,23 +335,30 @@ namespace xo {
|
|||
header_type* header = (header_type*)(m0 - sizeof(header_type));
|
||||
size_t pad = padding::with_padding(z0) - z0;
|
||||
byte * guard1 = m0 + z0 + pad;
|
||||
{
|
||||
REQUIRE(a1o.contains(guard0));
|
||||
REQUIRE(a1o.contains(header));
|
||||
REQUIRE(cfg.header_.size(*header) == padding::with_padding(z0));
|
||||
//REQUIRE(((*header) & cfg.header_size_mask_) == padding::with_padding(z0));
|
||||
|
||||
REQUIRE(a1o.contains(guard0));
|
||||
REQUIRE(a1o.contains(header));
|
||||
REQUIRE(cfg.header_.size(*header) == padding::with_padding(z0));
|
||||
//REQUIRE(((*header) & cfg.header_size_mask_) == padding::with_padding(z0));
|
||||
REQUIRE(a1o.last_error().error_ == error::ok);
|
||||
REQUIRE(a1o.last_error().error_seq_ == 0);
|
||||
|
||||
REQUIRE(a1o.last_error().error_ == error::ok);
|
||||
REQUIRE(a1o.last_error().error_seq_ == 0);
|
||||
REQUIRE(a1o.allocated() == (cfg.header_.guard_z_
|
||||
+ sizeof(header_type)
|
||||
+ z0
|
||||
+ pad
|
||||
+ cfg.header_.guard_z_));
|
||||
REQUIRE(a1o.allocated() <= a1o.committed());
|
||||
REQUIRE(a1o.allocated() + a1o.available() == a1o.committed());
|
||||
REQUIRE(a1o.committed() <= a1o.reserved());
|
||||
}
|
||||
|
||||
REQUIRE(a1o.allocated() == (cfg.header_.guard_z_
|
||||
+ sizeof(header_type)
|
||||
+ z0
|
||||
+ pad
|
||||
+ cfg.header_.guard_z_));
|
||||
REQUIRE(a1o.allocated() <= a1o.committed());
|
||||
REQUIRE(a1o.allocated() + a1o.available() == a1o.committed());
|
||||
REQUIRE(a1o.committed() <= a1o.reserved());
|
||||
a1o._drop();
|
||||
{
|
||||
REQUIRE(a1o.allocated() == 0);
|
||||
REQUIRE(a1o.committed() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("allocator-fail-1", "[alloc2][AAllocator]")
|
||||
|
|
@ -332,6 +373,8 @@ namespace xo {
|
|||
|
||||
REQUIRE(cfg.size_ <= cfg.hugepage_z_);
|
||||
|
||||
REQUIRE(!a1o._has_null_vptr());
|
||||
|
||||
REQUIRE(a1o.reserved() >= cfg.size_);
|
||||
REQUIRE(a1o.committed() == 0);
|
||||
REQUIRE(a1o.available() == 0);
|
||||
|
|
@ -339,17 +382,22 @@ namespace xo {
|
|||
|
||||
size_t z0 = cfg.hugepage_z_ + 1;
|
||||
byte * m0 = a1o.alloc(typeseq::sentinel(), z0);
|
||||
|
||||
REQUIRE(!m0);
|
||||
|
||||
AllocError err = a1o.last_error();
|
||||
{
|
||||
REQUIRE(!m0);
|
||||
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_ == arena.reserved());
|
||||
}
|
||||
|
||||
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_ == arena.reserved());
|
||||
a1o._drop();
|
||||
{
|
||||
REQUIRE(a1o.allocated() == 0);
|
||||
REQUIRE(a1o.committed() == 0);
|
||||
}
|
||||
}
|
||||
} /*namespace ut*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue