From c5f53aed84e739fbbfdc991b75863d439162f51f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 17 Oct 2026 03:42:32 +0200 Subject: [PATCH] Parameters: verify sane storage handling - as it turns out: we need `UninitialisedStorage` to avoid spurious ctor calls - and the extent-index is computed by div, not mod !! With these fixes, I can now demonstrate that the allocation procees exactly as expected, the registry can be filled completely, and no memory is leaked or corrupted (the latter only verified with some probes) --- src/lib/par/type-registry.hpp | 22 +++-- tests/lib/par/type-registry-test.cpp | 99 ++++++++++++++++++++- wiki/thinkPad.ichthyo.mm | 123 +++++++++++++++++++++++++-- 3 files changed, 223 insertions(+), 21 deletions(-) diff --git a/src/lib/par/type-registry.hpp b/src/lib/par/type-registry.hpp index cdd28358b..313e14262 100644 --- a/src/lib/par/type-registry.hpp +++ b/src/lib/par/type-registry.hpp @@ -38,6 +38,7 @@ #include "lib/error.hpp" #include "lib/nocopy.hpp" #include "lib/format-string.hpp" +#include "lib/uninitialised-storage.hpp" //#include "lib/meta/trait.hpp" #include "lib/util.hpp" @@ -68,7 +69,7 @@ namespace par { static constexpr uint EXTENT_SIZ = 256; static constexpr uint INDEX_SIZ = 256; - using Extent = std::array; + using Extent = lib::UninitialisedStorage; using Index = std::array, INDEX_SIZ>; Index index_{}; @@ -82,6 +83,10 @@ namespace par { ELM& operator[] (ID) const; + /* == Registry state == */ + uint size() const { return size_; } + uint numExtents() const { return size_? 1 + (size_-1) / EXTENT_SIZ : 0; } + ~TypeRegistry(); private: Extent* accessExtent (ID) const; @@ -120,14 +125,14 @@ namespace par { Lock sync{this}; ID entryID{size_}; - auto& indexSlot = index_[entryID % EXTENT_SIZ]; + auto& indexSlot = index_[entryID / EXTENT_SIZ]; Extent* extent = indexSlot.load (std::memory_order_acquire); if (not extent) - indexSlot.store (new Extent{} // heap-allocate new Extent + indexSlot.store (extent = new Extent{} // heap-allocate new Extent ,std::memory_order_release); - void* storage = indexSlot + (entryID % EXTENT_SIZ); - new (storage) ELM(std::forward (initArg)...); + extent->createAt (entryID % EXTENT_SIZ + ,std::forward (initArg)...); ++size_; return entryID; } @@ -145,9 +150,8 @@ namespace par { try { for (uint slot=0; slotdestroyAt (slot % EXTENT_SIZ); } for (uint idxSlot=0; idxSlot::Extent* TypeRegistry::accessExtent (ID entryID) const { - auto& indexSlot = index_[entryID % EXTENT_SIZ]; + auto& indexSlot = index_[entryID / EXTENT_SIZ]; return indexSlot.load (std::memory_order_acquire); } diff --git a/tests/lib/par/type-registry-test.cpp b/tests/lib/par/type-registry-test.cpp index ef828cdb7..60d909a96 100644 --- a/tests/lib/par/type-registry-test.cpp +++ b/tests/lib/par/type-registry-test.cpp @@ -88,18 +88,109 @@ namespace test{ } - /** @test - * @todo WIP 9/26 🔁 define ⟶ implement + /** @test verify coherent storage handling and proper clean-up + * - slots are filled-up in sequence + * - the ID corresponds to the slot-count + * - new extents are opend precisely when the + * previous Extent is filled completely + * - Exceptions during slot-allocation are absorbed, + * without blocking the slot or corrupting data + * - the designate storage space can be utilised completely + * - when the registry is full, further allocations are blocked + * - but even a then the registry remains in sane state + * - all destructors of all slots are invoked + * @todo WIP 10/26 ✔ define ⟶ ✔ implement */ void verify_storageSanity() { - UNIMPLEMENTED ("verify coherent storage handling and proper clean-up"); + Dummy::checksum() = 0; + { // track instances by checksum... + Registry registry; + CHECK (0 == registry.size()); + CHECK (0 == registry.numExtents()); + + RegID i0 = registry.makeSlot(); + CHECK (1 == registry.size()); + CHECK (1 == registry.numExtents()); + + CHECK (i0 == 0); + int rand0 = registry[i0].getID(); + CHECK (0 < rand0); + CHECK (Dummy::checksum() == registry[i0].getID()); + + RegID i1 = registry.makeSlot(); + CHECK (2 == registry.size()); + CHECK (1 == registry.numExtents()); + int rand1 = registry[i1].getID(); + + CHECK (i1 == 1); + CHECK (Dummy::checksum() == registry[i0].getID() + + registry[i1].getID()); + + for (uint i=0; i<256; ++i) + registry.makeSlot(); + // first Extent was filled up + CHECK (256+2 == registry.size()); + CHECK (2 == registry.numExtents()); + CHECK (rand1 == registry[i1] .getID()); + CHECK (rand0 == registry[i0] .getID()); + + // Verify no leak in case of Exceptions during slot allocation + int rand257 = registry[257].getID(); + CHECK (0 < rand257); + long checkPre = Dummy::checksum(); + Dummy::activateCtorFailure(); + try { + registry.makeSlot(-55); + NOTREACHED ("did not throw"); + } + catch (int& magic) + { + CHECK (magic == -55); + // since the dtor is not called on ctor failure, + // we have to fix the checksum explicitly here + Dummy::checksum() -= (-55); + Dummy::activateCtorFailure(false); + } + // now the important point: + CHECK (256+2 == registry.size()); // next slot was not marked as claimed + CHECK (2 == registry.numExtents()); + CHECK (Dummy::checksum() == checkPre); + CHECK (rand257 == registry[257].getID()); + CHECK (rand1 == registry[i1] .getID()); + CHECK (rand0 == registry[i0] .getID()); + + // fill-up the second Extent completely + for (uint i=2; i<256; ++i) + registry.makeSlot(); + CHECK (2*256 == registry.size()); + CHECK (2 == registry.numExtents()); + + // and then fill up all the designated storage + for (uint i=registry.size(); i<256*256; ++i) + registry.makeSlot(); + CHECK (256*256 == registry.size()); + CHECK (256 == registry.numExtents()); + + // can not allocate further... + checkPre = Dummy::checksum(); + VERIFY_FAIL ("space exhausted for type Dummy" + , registry.makeSlot() ); + + // yet the registry is in sane state + CHECK (Dummy::checksum() == checkPre); + CHECK (rand0 == registry[i0] .getID()); + CHECK (rand1 == registry[i1] .getID()); + CHECK (rand257 == registry[257].getID()); + + }//automatic clean-up of Registry triggered here + CHECK (0 == Dummy::checksum()); } /** @test - * @todo WIP 9/26 🔁 define ⟶ implement + * @todo WIP 10/26 🔁 define ⟶ implement */ void verify_concurrentAccess() diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 5d83802d4..87244b388 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -86291,8 +86291,8 @@ class ScaleRegistry - - + + @@ -86312,20 +86312,99 @@ class ScaleRegistry - + - + + + + + + + + + + + + + + + + + + + + + + + + + +

+ ...außer in zwei sehr alten Tracking-Tickets +

+

+ Also ist das Problem, daß jemand, der neu im Projekt ist, diese Policy nicht findet +

+ +
+ + +
+
+
- - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - @@ -199475,6 +199554,34 @@ that situation will improve in forseeable future. + + + + + + + + + + + + + + + + + + + + + + + + + + + +