xo-arena: + src_fn argument in alloc_error + contributaries

This commit is contained in:
Roland Conybeare 2026-04-10 20:32:23 -04:00
commit a3e72f33a5
9 changed files with 73 additions and 37 deletions

View file

@ -48,10 +48,12 @@ namespace xo {
uint32_t seq) : error_{err},
error_seq_{seq} {}
AllocError(error err,
const char * src_fn,
uint32_t seq,
size_type req_z,
size_type com_z,
size_type rsv_z) : error_{err},
src_fn_{src_fn},
error_seq_{seq},
request_z_{req_z},
committed_z_{com_z},
@ -61,7 +63,10 @@ namespace xo {
/** error code **/
error error_ = error::ok;
/** source function. Typically injected with __PRETTY_FUNCTION__
* somewhere suitable on stack
**/
const char * src_fn_ = nullptr;
/** sequence# of this error.
* Each error event within an allocator gets next sequence number
**/

View file

@ -203,19 +203,21 @@ namespace xo {
/** capture error information: advance error count + set last_error **/
void capture_error(error err,
const char * src_fn,
size_type target_z = 0) const;
/** alloc driver. shared by alloc(), super_alloc(), sub_alloc() **/
value_type _alloc(std::size_t req_z,
alloc_mode mode,
typeseq tseq,
uint32_t age);
uint32_t age,
const char * src_fn);
/** expand committed space in arena @p d
* to size at least @p z
* to size at least @p z, on behalf of @p src_fn
* In practice will round up to a multiple of @ref page_z_.
**/
bool expand(size_type z) noexcept;
bool expand(size_type z, const char * src_fn) noexcept;
/** create initial guard **/
void establish_initial_guard() noexcept;

View file

@ -181,7 +181,7 @@ namespace xo {
template <typename T>
void
DArenaVector<T>::reserve(size_type z) {
store_.expand(z * sizeof(T));
store_.expand(z * sizeof(T), __PRETTY_FUNCTION__);
}
template <typename T>
@ -193,7 +193,7 @@ namespace xo {
if (z > size_) {
// expand arena to accomodate
if (!store_.expand(req_z))
if (!store_.expand(req_z, __PRETTY_FUNCTION__))
return false;
// run ctors
@ -258,7 +258,7 @@ namespace xo {
size_type new_z = size_ + 1;
size_type req_z = new_z * sizeof(T);
store_.expand(req_z);
store_.expand(req_z, __PRETTY_FUNCTION__);
}
// move elements [i .. z-1] right by one position.
@ -283,7 +283,7 @@ namespace xo {
size_type new_z = size_ + 1;
size_type req_z = new_z * sizeof(T);
store_.expand(req_z);
store_.expand(req_z, __PRETTY_FUNCTION__);
}
// move elements [i .. z-1] right by one position.
@ -322,7 +322,7 @@ namespace xo {
size_type z = size_ + 1;
size_type req_z = z * sizeof(T);
if (this->store_.expand(req_z)) {
if (this->store_.expand(req_z, __PRETTY_FUNCTION__)) {
T * addr = this->_address_of(size_);
new (addr) T{std::move(x)};
@ -336,7 +336,7 @@ namespace xo {
DArenaVector<T>::push_back(const T & x) {
size_type z = size_ + 1;
if (this->store_.expand(z * sizeof(T))) {
if (this->store_.expand(z * sizeof(T), __PRETTY_FUNCTION__)) {
T * addr = this->_address_of(size_);
new (addr) T{x};

View file

@ -20,12 +20,17 @@ namespace xo {
inline std::ostream &
operator<<(std::ostream & os, const AllocError & x) {
os << "<AllocError"
<< xtag("error", x.error_)
<< xtag("seq", x.error_seq_)
<< xtag("error", x.error_);
if (x.src_fn_)
os << xtag("src_fn", x.src_fn_);
os << xtag("seq", x.error_seq_)
<< xtag("req_z", x.request_z_)
<< xtag("commit_z", x.committed_z_)
<< xtag("resv_z", x.reserved_z_)
<< ">";
return os;
}
}

View file

@ -11,6 +11,7 @@ set(SELF_SRCS
DArena.cpp
DArenaIterator.cpp
DCircularBuffer.cpp
backtrace.cpp
)
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
@ -24,5 +25,7 @@ xo_install_include_tree3(include/xo/arena)
xo_dependency(${SELF_LIB} xo_reflectutil)
xo_dependency(${SELF_LIB} indentlog)
xo_external_pkgconfig_dependency(${SELF_LIB} LIBUNWIND libunwind-generic)
xo_external_pkgconfig_dependency(${SELF_LIB} LIBDW libdw)
# end src/CMakeLists.txt

View file

@ -7,6 +7,7 @@
#include "DArena.hpp"
#include "DArenaIterator.hpp"
#include "mmap_util.hpp"
#include "backtrace.hpp"
#include <xo/arena/padding.hpp>
#include <xo/indentlog/scope.hpp>
#include <xo/indentlog/print/tag.hpp>
@ -230,7 +231,7 @@ namespace xo {
DArena::alloc_info(value_type mem) const noexcept
{
if (!config_.store_header_flag_) [[unlikely]] {
this->capture_error(error::alloc_info_disabled);
this->capture_error(error::alloc_info_disabled, __PRETTY_FUNCTION__);
return AllocInfo::error_not_configured(&config_.header_);
}
@ -272,7 +273,7 @@ namespace xo {
DArena::begin_header() const noexcept
{
if (config_.store_header_flag_ == false) {
this->capture_error(error::alloc_iterator_not_supported);
this->capture_error(error::alloc_iterator_not_supported, __PRETTY_FUNCTION__);
return nullptr;
}
@ -284,7 +285,7 @@ namespace xo {
DArena::end_header() const noexcept
{
if (config_.store_header_flag_ == false) {
this->capture_error(error::alloc_iterator_not_supported);
this->capture_error(error::alloc_iterator_not_supported, __PRETTY_FUNCTION__);
return nullptr;
}
@ -299,7 +300,11 @@ namespace xo {
* exactly 1 header per alloc() call.
* - store_header_flag follows configuration
*/
return _alloc(req_z, alloc_mode::standard, t, 0 /*age*/);
return _alloc(req_z,
alloc_mode::standard,
t,
0 /*age*/,
__PRETTY_FUNCTION__);
}
std::byte *
@ -316,7 +321,8 @@ namespace xo {
return _alloc(req_z,
alloc_mode::super,
t,
0 /*age*/);
0 /*age*/,
__PRETTY_FUNCTION__);
}
std::byte *
@ -334,7 +340,8 @@ namespace xo {
? alloc_mode::sub_complete
: alloc_mode::sub_incomplete),
typeseq::sentinel() /*typeseq: ignored*/,
0 /*age - ignored */);
0 /*age - ignored */,
__PRETTY_FUNCTION__);
}
std::byte *
@ -354,17 +361,20 @@ namespace xo {
typeseq tseq = typeseq(src_info.tseq());
uint32_t age = src_info.age();
return _alloc(req_z, alloc_mode::standard, tseq, age + 1);
return _alloc(req_z, alloc_mode::standard, tseq, age + 1,
__PRETTY_FUNCTION__);
}
void
DArena::capture_error(error err,
const char * src_fn,
size_type target_z) const
{
DArena * self = const_cast<DArena *>(this);
++(self->error_count_);
self->last_error_ = AllocError(err,
src_fn,
error_count_,
target_z,
committed_z_,
@ -375,7 +385,8 @@ namespace xo {
DArena::_alloc(std::size_t req_z,
alloc_mode mode,
typeseq tseq,
uint32_t age)
uint32_t age,
const char * src_fn)
{
scope log(XO_DEBUG(config_.debug_flag_));
@ -444,7 +455,7 @@ namespace xo {
hz = sizeof(header);
} else {
/* req_z doesn't fit in configured header_size_mask bits */
capture_error(error::header_size_mask);
capture_error(error::header_size_mask, src_fn);
return nullptr;
}
}
@ -453,7 +464,7 @@ namespace xo {
assert(padding::is_aligned(z1));
if (!this->expand(this->allocated() + z1)) [[unlikely]] {
if (!this->expand(this->allocated() + z1, src_fn)) [[unlikely]] {
/* (error state already captured) */
return nullptr;
}
@ -509,11 +520,12 @@ namespace xo {
}
bool
DArena::expand(size_t target_z) noexcept
DArena::expand(size_t target_z, const char * src_fn) noexcept
{
scope log(XO_DEBUG(config_.debug_flag_),
xtag("target_z", target_z),
xtag("committed_z", committed_z_));
xtag("committed_z", committed_z_),
xtag("src_fn", src_fn));
if (target_z <= committed_z_) [[likely]] {
log && log("trivial success, offset within committed range",
@ -523,7 +535,12 @@ namespace xo {
}
if (lo_ + target_z > hi_) [[unlikely]] {
this->capture_error(error::reserve_exhausted, target_z);
this->capture_error(error::reserve_exhausted, src_fn, target_z);
fprintf(stderr, "DArena::expand: reserve exhausted");
print_backtrace_dwarf(true /*demangle_flag*/);
std::terminate();
return false;
}
@ -566,7 +583,11 @@ namespace xo {
);
}
capture_error(error::commit_failed, add_commit_z);
this->capture_error(error::commit_failed, src_fn, add_commit_z);
fprintf(stderr, "DArena::expand: mprotect failed (system oom?)");
print_backtrace_dwarf(false /*!demangle_flag*/);
return false;
}

View file

@ -74,7 +74,7 @@ namespace xo {
xtag("bounds_flag", bounds_flag));
if (!contains_flag || !bounds_flag) {
arena_->capture_error(error::alloc_iterator_deref);
arena_->capture_error(error::alloc_iterator_deref, __PRETTY_FUNCTION__);
return AllocInfo::error_invalid_iterator(&(arena_->config_.header_));
}
@ -122,7 +122,7 @@ namespace xo {
xtag("bounds_flag", bounds_flag));
if (!contains_flag || !bounds_flag) {
arena_->capture_error(error::alloc_iterator_next);
arena_->capture_error(error::alloc_iterator_next, __PRETTY_FUNCTION__);
return;
}

View file

@ -85,7 +85,7 @@ namespace xo {
/* note: local_ppos_ invariant across expand_to() */
arena_->expand(new_z);
arena_->expand(new_z, __PRETTY_FUNCTION__);
char * p_base = (char *)(arena_->lo_);
char * p_hi = (char *)(arena_->limit_);

View file

@ -118,7 +118,7 @@ namespace xo {
REQUIRE(arena.allocated() == 0);
size_t z2 = 512;
bool ok = arena.expand(z2);
bool ok = arena.expand(z2, __PRETTY_FUNCTION__);
INFO(xtag("last_error", arena.last_error()));