xo-alloc2: capture error info, retire exceptions in alloc path

This commit is contained in:
Roland Conybeare 2025-12-12 13:10:26 -05:00
commit 360ae4cb45
6 changed files with 103 additions and 48 deletions

View file

@ -14,6 +14,42 @@ namespace xo {
using Copaque = const void *;
using Opaque = void *;
enum class error : int32_t {
/** sentinel **/
invalid = -1,
/** not an error **/
none,
/** reserved size exhauged **/
reserve_exhausted,
/** unable to commit (i.e. mprotect failure) **/
commit_failed,
};
struct AllocatorError {
using size_type = std::size_t;
using value_type = std::byte*;
AllocatorError() = default;
explicit AllocatorError(error err) : error_{err} {}
AllocatorError(error err,
size_type req_z,
size_type com_z,
size_type rsv_z) : error_{err},
request_z_{req_z},
committed_z_{com_z},
reserved_z_{rsv_z} {}
/** error code **/
error error_ = error::none;
/** reqeust size assoc'd with errror **/
size_type request_z_ = 0;
/** committed allocator memory at time of error **/
size_type committed_z_ = 0;
/** reserved allocator memory at time of error **/
size_type reserved_z_ = 0;
};
/** @class AAllocator
* @brief Abstract facet for allocation
*
@ -41,32 +77,32 @@ namespace xo {
///@{
/** RTTI: unique id# for actual runtime data representation **/
virtual int32_t _typeseq() const = 0;
virtual int32_t _typeseq() const noexcept = 0;
/** optional name for allocator @p d
* Labeling, for diagnostics.
**/
virtual const std::string & name(Copaque d) const = 0;
virtual const std::string & name(Copaque d) const noexcept = 0;
/** reserved size in bytes for allocator @p d.
* Includes committed + uncommitted memory.
* Cannot be increased.
**/
virtual size_type reserved(Copaque d) const = 0;
virtual size_type reserved(Copaque d) const noexcept = 0;
/** Synonym for @ref committed.
* Can increase on @ref alloc
**/
virtual size_type size(Copaque d) const = 0;
virtual size_type size(Copaque d) const noexcept = 0;
/** committed size (physical addresses obtained)
* for allocator @p d.
* @ref alloc may auto-increase this
**/
virtual size_type committed(Copaque d) const = 0;
virtual size_type committed(Copaque d) const noexcept = 0;
/** unallocated (but committed) size in bytes for allocator @p d **/
virtual size_type available(Copaque d) const = 0;
virtual size_type available(Copaque d) const noexcept = 0;
/** allocated (i.e. in-use) amount in bytes for allocator @p d **/
virtual size_type allocated(Copaque d) const = 0;
virtual size_type allocated(Copaque d) const noexcept = 0;
/** true iff allocator @p d is responsible for memory at address @p p.
**/
virtual bool contains(Copaque d, const void * p) const = 0;
virtual bool contains(Copaque d, const void * p) const noexcept = 0;
/** expand committed space in arena @p d
* to size at least @p z

View file

@ -37,7 +37,7 @@ namespace xo {
* @brief represent arena allocator state
*
* Provides minimal RAII functionality around memory mapping.
* For allocation see @ref IAllocator_DArena
* For allocation implementation see @ref IAllocator_DArena
**/
struct DArena {
/*
@ -92,7 +92,7 @@ namespace xo {
ArenaConfig config_;
/** size of a VM page (obtained automatically via getpagesize()). Likely 4k **/
std::size_t page_z_ = 0;
size_type page_z_ = 0;
/** arena owns memory in range [@ref lo_, @ref hi_)
**/
@ -101,7 +101,7 @@ namespace xo {
/** prefix of this size is committed.
* Remainder mapped but uncommitted.
**/
std::size_t committed_z_ = 0;
size_type committed_z_ = 0;
/** free pointer.
* Memory in range [@ref lo_, @ref free_) current in use
@ -119,6 +119,12 @@ namespace xo {
**/
std::byte * hi_ = nullptr;
/** count runtime errors. Each error updates @ref last_error_ **/
uint32_t error_count_ = 0;
/** capture some error details if/when error **/
AllocatorError last_error_;
///@}
};

View file

@ -29,15 +29,15 @@ namespace xo {
using size_type = std::size_t;
// from AAllocator
int32_t _typeseq() const override { return s_typeseq; }
int32_t _typeseq() const noexcept override { return s_typeseq; }
[[noreturn]] const std::string & name(Copaque) const override { _fatal(); }
[[noreturn]] size_type reserved(Copaque) const override { _fatal(); }
[[noreturn]] size_type size(Copaque) const override { _fatal(); }
[[noreturn]] size_type committed(Copaque) const override { _fatal(); }
[[noreturn]] size_type available(Copaque) const override { _fatal(); }
[[noreturn]] size_type allocated(Copaque) const override { _fatal(); }
[[noreturn]] bool contains(Copaque, const void *) const override { _fatal(); }
[[noreturn]] const std::string & name(Copaque) const noexcept override { _fatal(); }
[[noreturn]] size_type reserved(Copaque) const noexcept override { _fatal(); }
[[noreturn]] size_type size(Copaque) const noexcept override { _fatal(); }
[[noreturn]] size_type committed(Copaque) const noexcept override { _fatal(); }
[[noreturn]] size_type available(Copaque) const noexcept override { _fatal(); }
[[noreturn]] size_type allocated(Copaque) const noexcept override { _fatal(); }
[[noreturn]] bool contains(Copaque, const void *) const noexcept override { _fatal(); }
[[noreturn]] bool expand(Opaque, std::size_t) const override { _fatal(); }
[[noreturn]] std::byte * alloc(Opaque, std::size_t) const override { _fatal(); }

View file

@ -24,27 +24,27 @@ namespace xo {
static DRepr & _dcast(Opaque d) { return *(DRepr *)d; }
// from AAllocator
int32_t _typeseq() const override { return s_typeseq; }
const std::string & name(Copaque d) const override {
int32_t _typeseq() const noexcept override { return s_typeseq; }
const std::string & name(Copaque d) const noexcept override {
return Impl::name(_dcast(d));
}
size_type reserved(Copaque d) const override {
size_type reserved(Copaque d) const noexcept override {
return Impl::reserved(_dcast(d));
}
size_type size(Copaque d) const override {
size_type size(Copaque d) const noexcept override {
return Impl::size(_dcast(d));
}
size_type committed(Copaque d) const override {
size_type committed(Copaque d) const noexcept override {
return Impl::committed(_dcast(d));
}
size_type available(Copaque d) const override {
size_type available(Copaque d) const noexcept override {
return I::available(_dcast(d));
}
size_type allocated(Copaque d) const override {
size_type allocated(Copaque d) const noexcept override {
return I::allocated(_dcast(d));
}
bool contains(Copaque d, const void * p) const override {
bool contains(Copaque d, const void * p) const noexcept override {
return Impl::contains(_dcast(d), p);
}