Fix multithreading issue in allocation cleanup.

Resolves: NEO-3582

Change-Id: I269fbe8b17cdafa198ed0c89e4b55c15acbc5126
Signed-off-by: Zdunowski, Piotr <piotr.zdunowski@intel.com>
This commit is contained in:
Zdunowski, Piotr 2019-09-17 17:11:10 +02:00 committed by sys_ocldev
parent 072048105d
commit 41ef3d6ebc
3 changed files with 60 additions and 0 deletions

View File

@ -8,6 +8,8 @@
#pragma once
#include "core/memory_manager/graphics_allocation.h"
#include <mutex>
namespace NEO {
class CommandStreamReceiver;
@ -15,7 +17,10 @@ class AllocationsList : public IDList<GraphicsAllocation, true, true> {
public:
std::unique_ptr<GraphicsAllocation> detachAllocation(size_t requiredMinimalSize, CommandStreamReceiver &commandStreamReceiver, GraphicsAllocation::AllocationType allocationType);
std::unique_lock<std::mutex> obtainUniqueOwnership();
private:
GraphicsAllocation *detachAllocationImpl(GraphicsAllocation *, void *);
std::mutex mutex;
};
} // namespace NEO

View File

@ -39,6 +39,7 @@ void InternalAllocationStorage::cleanAllocationList(uint32_t waitTaskCount, uint
}
void InternalAllocationStorage::freeAllocationsList(uint32_t waitTaskCount, AllocationsList &allocationsList) {
auto lock = allocationsList.obtainUniqueOwnership();
auto memoryManager = commandStreamReceiver.getMemoryManager();
GraphicsAllocation *curr = allocationsList.detachNodes();
@ -96,4 +97,8 @@ GraphicsAllocation *AllocationsList::detachAllocationImpl(GraphicsAllocation *,
return nullptr;
}
std::unique_lock<std::mutex> AllocationsList::obtainUniqueOwnership() {
return std::unique_lock<std::mutex>(mutex);
}
} // namespace NEO

View File

@ -12,6 +12,7 @@
#include "test.h"
#include "unit_tests/fixtures/memory_allocator_fixture.h"
#include "unit_tests/mocks/mock_allocation_properties.h"
#include "unit_tests/mocks/mock_graphics_allocation.h"
struct InternalAllocationStorageTest : public MemoryAllocatorFixture,
public ::testing::Test {
@ -192,3 +193,52 @@ TEST_F(InternalAllocationStorageTest, givenAllocationWhenItIsPutOnReusableListWh
auto internalAllocation = storage->obtainReusableAllocation(1, GraphicsAllocation::AllocationType::INTERNAL_HEAP);
EXPECT_EQ(nullptr, internalAllocation);
}
class WaitAtDeletionAllocation : public MockGraphicsAllocation {
public:
WaitAtDeletionAllocation(void *buffer, size_t sizeIn)
: MockGraphicsAllocation(buffer, sizeIn) {
inDestructor = false;
}
std::mutex mutex;
std::atomic<bool> inDestructor;
~WaitAtDeletionAllocation() {
inDestructor = true;
std::lock_guard<std::mutex> lock(mutex);
}
};
TEST_F(InternalAllocationStorageTest, givenAllocationListWhenTwoThreadsCleanConcurrentlyThenBothThreadsCanAccessTheList) {
auto allocation1 = new WaitAtDeletionAllocation(nullptr, 0);
allocation1->updateTaskCount(1, csr->getOsContext().getContextId());
storage->storeAllocation(std::unique_ptr<GraphicsAllocation>(allocation1), TEMPORARY_ALLOCATION);
std::unique_lock<std::mutex> allocationDeletionLock(allocation1->mutex);
auto allocation2 = memoryManager->allocateGraphicsMemoryWithProperties(MockAllocationProperties{MemoryConstants::pageSize});
allocation2->updateTaskCount(2, csr->getOsContext().getContextId());
storage->storeAllocation(std::unique_ptr<GraphicsAllocation>(allocation2), TEMPORARY_ALLOCATION);
std::mutex mutex;
std::unique_lock<std::mutex> lock(mutex);
std::thread thread1([&] {
storage->cleanAllocationList(1, TEMPORARY_ALLOCATION);
});
std::thread thread2([&] {
std::lock_guard<std::mutex> lock(mutex);
storage->cleanAllocationList(2, TEMPORARY_ALLOCATION);
});
while (!allocation1->inDestructor)
;
lock.unlock();
allocationDeletionLock.unlock();
thread1.join();
thread2.join();
EXPECT_TRUE(csr->getTemporaryAllocations().peekIsEmpty());
}