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:
parent
0256ad8528
commit
3b9641597f
4 changed files with 122 additions and 13 deletions
|
|
@ -154,10 +154,16 @@ namespace mem {
|
||||||
|
|
||||||
// possibly the request was not announced beforehand...?
|
// possibly the request was not announced beforehand...?
|
||||||
if (not storage)
|
if (not storage)
|
||||||
alloc = globalPool_().requestAllocation (sizRequest);
|
{ // as last resort, retrieve memory by synchronised direct call
|
||||||
if (not storage)
|
alloc = globalPool_().requestAllocation (sizRequest);
|
||||||
throw err::State{_Fmt{"Unable to provide further %d bytes of buffer memory."} % sizRequest
|
if (not storage)
|
||||||
,LUMIERA_ERROR_BUFFER_MANAGEMENT};
|
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);
|
return std::make_tuple (storage, buffSiz, specifics);
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +199,7 @@ namespace mem {
|
||||||
friend PoolDiagnostic watch (LocalBufferStore const&);
|
friend PoolDiagnostic watch (LocalBufferStore const&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** entrance point to inspection for test */
|
/** entrance point to inspection for test */
|
||||||
inline PoolDiagnostic
|
inline PoolDiagnostic
|
||||||
watch (LocalBufferStore const& lstor)
|
watch (LocalBufferStore const& lstor)
|
||||||
|
|
|
||||||
|
|
@ -254,6 +254,20 @@ namespace mem {
|
||||||
AllocReceiver::supply (alloc);
|
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
|
* Return an used memory block back to the pool
|
||||||
* @param mem a chunk of memory previously handed out by \ref retrieve()
|
* @param mem a chunk of memory previously handed out by \ref retrieve()
|
||||||
|
|
@ -397,12 +411,7 @@ namespace mem {
|
||||||
void
|
void
|
||||||
ingest()
|
ingest()
|
||||||
{
|
{
|
||||||
inQueue_.consume_all ([this](Alloc alloc)
|
inQueue_.consume_all ([this](Alloc alloc){ supplyImmediately (move(alloc)); });
|
||||||
{
|
|
||||||
if (alloc.mem)
|
|
||||||
blocks_.emplace_front (move(alloc));
|
|
||||||
// otherwise: allocation not possible, do not add anything
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class PRED>
|
template<class PRED>
|
||||||
|
|
|
||||||
|
|
@ -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
|
void
|
||||||
verify_allocate()
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -145647,11 +145647,25 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
||||||
</richcontent>
|
</richcontent>
|
||||||
</node>
|
</node>
|
||||||
</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ündigung"/>
|
<node CREATED="1778969027419" ID="ID_1633706484" MODIFIED="1778969039237" TEXT="gemeint ist: eine direkte Allokation, ohne Ankündigung"/>
|
||||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1779640817389" ID="ID_223109084" MODIFIED="1779640846459" TEXT="auch hier muß Beobachtung bei noch laufendem Worker erfolgen">
|
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1779640817389" ID="ID_223109084" MODIFIED="1779640846459" TEXT="auch hier muß Beobachtung bei noch laufendem Worker erfolgen">
|
||||||
<icon BUILTIN="messagebox_warning"/>
|
<icon BUILTIN="messagebox_warning"/>
|
||||||
</node>
|
</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 übersehen">
|
||||||
|
<icon BUILTIN="clanbomber"/>
|
||||||
|
</node>
|
||||||
|
<node COLOR="#338800" CREATED="1779643623630" ID="ID_1926698633" MODIFIED="1779645568403" TEXT="muß den direkt geholten Block schon auch in die lokale Block-Liste einspeisen">
|
||||||
|
<icon BUILTIN="button_ok"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1778968918381" ID="ID_752345967" MODIFIED="1778968922655" TEXT="verify_release">
|
<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"/>
|
<node CREATED="1778969042432" ID="ID_1262962638" MODIFIED="1778969052166" TEXT="hier sollte auch ein clean-up provoziert werden"/>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue