From 3b9641597f92f2c7a61481d742820c2d6ab0f010 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 24 May 2026 20:02:48 +0200 Subject: [PATCH] BufferProvider: cover effect of an immediate allocation This is a fall-back situation, in case the allocation ''was not announced beforehand'' A direct locked global access is used then, which is verified by this test --- src/vault/mem/local-buffer-store.hpp | 16 ++-- src/vault/mem/local-mem-pool.hpp | 21 ++++-- tests/vault/mem/local-buffer-store-test.cpp | 82 ++++++++++++++++++++- wiki/thinkPad.ichthyo.mm | 16 +++- 4 files changed, 122 insertions(+), 13 deletions(-) diff --git a/src/vault/mem/local-buffer-store.hpp b/src/vault/mem/local-buffer-store.hpp index b93cc6664..afbff2ff1 100644 --- a/src/vault/mem/local-buffer-store.hpp +++ b/src/vault/mem/local-buffer-store.hpp @@ -154,10 +154,16 @@ namespace mem { // possibly the request was not announced beforehand...? if (not storage) - alloc = globalPool_().requestAllocation (sizRequest); - if (not storage) - throw err::State{_Fmt{"Unable to provide further %d bytes of buffer memory."} % sizRequest - ,LUMIERA_ERROR_BUFFER_MANAGEMENT}; + { // as last resort, retrieve memory by synchronised direct call + alloc = globalPool_().requestAllocation (sizRequest); + if (not storage) + throw err::State{_Fmt{"Unable to provide further %d bytes of buffer memory."} % sizRequest + ,LUMIERA_ERROR_BUFFER_MANAGEMENT + }; + localPool_->supplyImmediately (alloc); + alloc = localPool_->retrieve (sizRequest); + ENSURE (storage); + } return std::make_tuple (storage, buffSiz, specifics); } @@ -193,7 +199,7 @@ namespace mem { friend PoolDiagnostic watch (LocalBufferStore const&); }; - + /** entrance point to inspection for test */ inline PoolDiagnostic watch (LocalBufferStore const& lstor) diff --git a/src/vault/mem/local-mem-pool.hpp b/src/vault/mem/local-mem-pool.hpp index 6d11661f4..444e8b619 100644 --- a/src/vault/mem/local-mem-pool.hpp +++ b/src/vault/mem/local-mem-pool.hpp @@ -254,6 +254,20 @@ namespace mem { AllocReceiver::supply (alloc); } + /** + * Pass an allocation directly and transfer discretionary power. + * @warning this call is _not_ threadsafe and can only be used by the worker itself, + * after forcibly retrieving an allocation by synchronised direct request. + * @remark similar to the regular case, LocalMemPool is responsible for clean-up. + */ + void + supplyImmediately (Alloc alloc) + { + if (alloc.mem) + blocks_.emplace_front (move(alloc)); + // otherwise: allocation not serviced, do not add anything + } + /** * Return an used memory block back to the pool * @param mem a chunk of memory previously handed out by \ref retrieve() @@ -397,12 +411,7 @@ namespace mem { void ingest() { - inQueue_.consume_all ([this](Alloc alloc) - { - if (alloc.mem) - blocks_.emplace_front (move(alloc)); - // otherwise: allocation not possible, do not add anything - }); + inQueue_.consume_all ([this](Alloc alloc){ supplyImmediately (move(alloc)); }); } template diff --git a/tests/vault/mem/local-buffer-store-test.cpp b/tests/vault/mem/local-buffer-store-test.cpp index e637b7fd1..8a5d6b64a 100644 --- a/tests/vault/mem/local-buffer-store-test.cpp +++ b/tests/vault/mem/local-buffer-store-test.cpp @@ -281,11 +281,91 @@ namespace test { - /** @test + /** @test request an allocation from the local store, without prior announcement + * - again, a coordinated test setup is necessary to watch the effects + * - Step-1: test worker triggers the allocation and retrieves it immediately + * - Step-2: allocation and the leased-out memory is visible in the global pool + * - test worker unwinds, allocations are returned */ void verify_allocate() { + // »central BufferPool« (transient instance for this test) + lib::DependInject::Local globalPool; + + // *test subject* + LocalBufferStore localStore; + BufferProviderSetup::Store& storeAPI = localStore; + + const size_t BUFFSIZ = 1024; + const HashVal TYPEID = 12345; + + // coordination of test steps + std::atomic_uint step{1}; + + Thread testWorker{[&] /* === Scenario: test subject requests allocation immediately === */ + { + // Step-1 + CHECK (watch(localStore).isEmpty()); + + BuffAlloc slot1 = storeAPI.provideBuffer (TYPEID, BUFFSIZ, 0,0); + auto& [storage,buffSiz,_] = slot1; + CHECK (storage); + CHECK (BUFFSIZ <= buffSiz); + + CHECK (not watch(localStore).isEmpty()); + CHECK (watch(localStore).size() == 1); + CHECK (watch(localStore).cntFree() == 0); + + ++step; + // allocation can be re-used locally, + // without any further exchange with the global pool + + storeAPI.detachBuffer (TYPEID, slot1); + + CHECK (watch(localStore).canServe(BUFFSIZ)); + CHECK (watch(localStore).cntFree() == 1); + CHECK (watch(localStore).size() == 1); + + BuffAlloc slot2 = storeAPI.provideBuffer (TYPEID, BUFFSIZ, 0,0); + CHECK (watch(localStore).cntFree() == 0); + + // the same memory address was re-used + CHECK (slot1 == slot2); + + storeAPI.detachBuffer (TYPEID, slot2); + + // can even reserve that memory without any round-trip to the global pool + CHECK (watch(localStore).cntFree() == 1); + CHECK (watch(localStore).cntResd() == 0); + + uint avail = storeAPI.prepareBuffers(TYPEID, 1, BUFFSIZ); + CHECK (1 == avail); + CHECK (watch(localStore).cntFree() == 1); + CHECK (watch(localStore).cntResd() == 1); + CHECK (watch(localStore).size() == 1); + CHECK (watch(localStore).canServe(BUFFSIZ)); + + }}; // block automatically sent back after thread end + + + /* === Main thread: observe effects in the global pool === */ + + // wait until memory was claimed + while (step < 2) + sleep_for(1ms); + + // Step-2 + CHECK (watch(*globalPool).numAllocs() == 1); + CHECK (watch(*globalPool).bytesLeased() >= BUFFSIZ); + + // wait until test thread terminates + while (testWorker) + sleep_for(1ms); + sleep_for(1ms); // additional wait for the dtor + + globalPool->processPendingRequests(); + CHECK (watch(*globalPool).bytesLeased() == 0); } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 62b49d7da..43876fec9 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -145647,11 +145647,25 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + + + + + + + + + + + + +