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
This commit is contained in:
Fischlurch 2026-05-24 20:02:48 +02:00
parent 0256ad8528
commit 3b9641597f
4 changed files with 122 additions and 13 deletions

View file

@ -154,10 +154,16 @@ namespace mem {
// possibly the request was not announced beforehand...?
if (not storage)
{ // 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};
,LUMIERA_ERROR_BUFFER_MANAGEMENT
};
localPool_->supplyImmediately (alloc);
alloc = localPool_->retrieve (sizRequest);
ENSURE (storage);
}
return std::make_tuple (storage, buffSiz, specifics);
}

View file

@ -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<class PRED>

View file

@ -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<EngineBufferManager>::Local<EngineBufferManager> 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);
}

View file

@ -145647,11 +145647,25 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</richcontent>
</node>
</node>
<node CREATED="1778949021417" ID="ID_1256480563" MODIFIED="1778968909103" TEXT="verify_allocate">
<node COLOR="#338800" CREATED="1778949021417" ID="ID_1256480563" MODIFIED="1779645581994" TEXT="verify_allocate">
<icon BUILTIN="button_ok"/>
<node CREATED="1778969027419" ID="ID_1633706484" MODIFIED="1778969039237" TEXT="gemeint ist: eine direkte Allokation, ohne Ank&#xfc;ndigung"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1779640817389" ID="ID_223109084" MODIFIED="1779640846459" TEXT="auch hier mu&#xdf; Beobachtung bei noch laufendem Worker erfolgen">
<icon BUILTIN="messagebox_warning"/>
</node>
<node COLOR="#435e98" CREATED="1779643076207" ID="ID_170158518" MODIFIED="1779645577004" STYLE="fork" TEXT="lokaler Pool ist empty() nach direkter Allokation">
<font NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="broken-line"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#b80267" CREATED="1779643541361" ID="ID_1231489502" MODIFIED="1779643558593" TEXT="oh wie interessant ....">
<icon BUILTIN="ksmiletris"/>
</node>
<node BACKGROUND_COLOR="#e2aa99" COLOR="#990033" CREATED="1779643563479" ID="ID_130728323" MODIFIED="1779643615605" TEXT="da habe ich ganz locker die Konsistenzbedingung &#xfc;bersehen">
<icon BUILTIN="clanbomber"/>
</node>
<node COLOR="#338800" CREATED="1779643623630" ID="ID_1926698633" MODIFIED="1779645568403" TEXT="mu&#xdf; den direkt geholten Block schon auch in die lokale Block-Liste einspeisen">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node CREATED="1778968918381" ID="ID_752345967" MODIFIED="1778968922655" TEXT="verify_release">
<node CREATED="1778969042432" ID="ID_1262962638" MODIFIED="1778969052166" TEXT="hier sollte auch ein clean-up provoziert werden"/>