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...?
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -145647,11 +145647,25 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> 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ündigung"/>
|
||||
<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"/>
|
||||
</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 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"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue