diff --git a/include/xo/alloc2/AAllocator.hpp b/include/xo/alloc2/AAllocator.hpp index 4cb2d4e..4ff7cb5 100644 --- a/include/xo/alloc2/AAllocator.hpp +++ b/include/xo/alloc2/AAllocator.hpp @@ -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 diff --git a/include/xo/alloc2/DArena.hpp b/include/xo/alloc2/DArena.hpp index 3058b64..5919970 100644 --- a/include/xo/alloc2/DArena.hpp +++ b/include/xo/alloc2/DArena.hpp @@ -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_; + ///@} }; diff --git a/include/xo/alloc2/IAllocator_Any.hpp b/include/xo/alloc2/IAllocator_Any.hpp index 18f06f8..ca7c5c6 100644 --- a/include/xo/alloc2/IAllocator_Any.hpp +++ b/include/xo/alloc2/IAllocator_Any.hpp @@ -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(); } diff --git a/include/xo/alloc2/IAllocator_Xfer.hpp b/include/xo/alloc2/IAllocator_Xfer.hpp index cedc37a..f8438ca 100644 --- a/include/xo/alloc2/IAllocator_Xfer.hpp +++ b/include/xo/alloc2/IAllocator_Xfer.hpp @@ -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); } diff --git a/src/alloc2/DArena.cpp b/src/alloc2/DArena.cpp index b727849..09afb1f 100644 --- a/src/alloc2/DArena.cpp +++ b/src/alloc2/DArena.cpp @@ -6,6 +6,7 @@ #include "xo/alloc2/AAllocator.hpp" #include "xo/alloc2/DArena.hpp" #include "xo/alloc2/padding.hpp" +#include "xo/indentlog/print/tag.hpp" #include #include // for ::munmap() #include // for ::getpagesize() @@ -81,11 +82,8 @@ namespace xo { // 3. assess mmap success { if (base == MAP_FAILED) { - assert(false); -#ifdef NOPE throw std::runtime_error(tostr("ArenaAlloc: uncommitted allocation failed", - xtag("size", z))); -#endif + xtag("size", req_z))); } assert((size_t)aligned_base % hugepage_z == 0); @@ -138,11 +136,8 @@ namespace xo { if (!lo) { // control here implies mmap() failed silently - assert(false); -#ifdef NOPE throw std::runtime_error(tostr("ArenaAlloc: allocation failed", - xtag("size", z))); -#endif + xtag("size", cfg.size_))); } size_t page_z = getpagesize(); @@ -166,7 +161,9 @@ namespace xo { committed_z_{0}, free_{lo}, limit_{lo}, - hi_{hi} + hi_{hi}, + error_count_{0}, + last_error_{} { //retval.checkpoint_ = lo_; } @@ -179,6 +176,8 @@ namespace xo { free_ = other.free_; limit_ = other.limit_; hi_ = other.hi_; + error_count_ = other.error_count_; + last_error_ = other.last_error_; other.config_ = ArenaConfig(); other.lo_ = nullptr; @@ -186,6 +185,8 @@ namespace xo { other.free_ = nullptr; other.limit_ = nullptr; other.hi_ = nullptr; + other.error_count_ = 0; + other.last_error_ = AllocatorError(); } DArena::~DArena() @@ -200,12 +201,14 @@ namespace xo { } // hygiene - this->lo_ = nullptr; - this->committed_z_ = 0; + lo_ = nullptr; + committed_z_ = 0; // checkpoint_ = nullptr; - this->free_ = nullptr; - this->limit_ = nullptr; - this->hi_ = nullptr; + free_ = nullptr; + limit_ = nullptr; + hi_ = nullptr; + error_count_ = 0; + last_error_ = AllocatorError(); } } } /*namespace xo*/ diff --git a/src/alloc2/IAllocator_DArena.cpp b/src/alloc2/IAllocator_DArena.cpp index 77b3718..2bb7f1d 100644 --- a/src/alloc2/IAllocator_DArena.cpp +++ b/src/alloc2/IAllocator_DArena.cpp @@ -66,10 +66,16 @@ namespace xo { return true; } - if (s.lo_ + target_z > s.hi_) { + if (s.lo_ + target_z > s.hi_) [[unlikely]] { + ++(s.error_count_); + s.last_error_ = AllocatorError(error::reserve_exhausted, + target_z, s.committed_z_, reserved(s)); + +#ifdef OBSOLETE throw std::runtime_error(tostr("ArenaAlloc::expand: requested size exceeds reserved size", xtag("requested", target_z), xtag("reserved", reserved(s)))); +#endif return false; } @@ -107,11 +113,15 @@ namespace xo { // xtag("add_commit_z", add_commit_z), // xtag("commit_end", commit_start + add_commit_z)); - if (::mprotect(commit_start, add_commit_z, PROT_READ | PROT_WRITE) != 0) { - assert(false); -// throw std::runtime_error(tostr("ArenaAlloc::expand: commit failure", -// xtag("committed_z", committed_z_), -// xtag("add_commit_z", add_commit_z))); + if (::mprotect(commit_start, add_commit_z, PROT_READ | PROT_WRITE) != 0) [[unlikely]] { + ++(s.error_count_); + s.last_error_ = AllocatorError(error::commit_failed, + add_commit_z, s.committed_z_, reserved(s)); +#ifdef OBSOLETE + throw std::runtime_error(tostr("ArenaAlloc::expand: commit failure", + xtag("committed_z", s.committed_z_), + xtag("add_commit_z", add_commit_z))); +#endif return false; }