diff --git a/runtime/memory_manager/allocations_list.h b/runtime/memory_manager/allocations_list.h index 3c21246b55..afd1eb3c77 100644 --- a/runtime/memory_manager/allocations_list.h +++ b/runtime/memory_manager/allocations_list.h @@ -8,6 +8,8 @@ #pragma once #include "core/memory_manager/graphics_allocation.h" +#include + namespace NEO { class CommandStreamReceiver; @@ -15,7 +17,10 @@ class AllocationsList : public IDList { public: std::unique_ptr detachAllocation(size_t requiredMinimalSize, CommandStreamReceiver &commandStreamReceiver, GraphicsAllocation::AllocationType allocationType); + std::unique_lock obtainUniqueOwnership(); + private: GraphicsAllocation *detachAllocationImpl(GraphicsAllocation *, void *); + std::mutex mutex; }; } // namespace NEO diff --git a/runtime/memory_manager/internal_allocation_storage.cpp b/runtime/memory_manager/internal_allocation_storage.cpp index ae667f16fe..eebb45c9d2 100644 --- a/runtime/memory_manager/internal_allocation_storage.cpp +++ b/runtime/memory_manager/internal_allocation_storage.cpp @@ -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 AllocationsList::obtainUniqueOwnership() { + return std::unique_lock(mutex); +} + } // namespace NEO diff --git a/unit_tests/memory_manager/internal_allocation_storage_tests.cpp b/unit_tests/memory_manager/internal_allocation_storage_tests.cpp index 69ba2170b5..6fe04cbf23 100644 --- a/unit_tests/memory_manager/internal_allocation_storage_tests.cpp +++ b/unit_tests/memory_manager/internal_allocation_storage_tests.cpp @@ -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 inDestructor; + ~WaitAtDeletionAllocation() { + inDestructor = true; + std::lock_guard lock(mutex); + } +}; + +TEST_F(InternalAllocationStorageTest, givenAllocationListWhenTwoThreadsCleanConcurrentlyThenBothThreadsCanAccessTheList) { + auto allocation1 = new WaitAtDeletionAllocation(nullptr, 0); + allocation1->updateTaskCount(1, csr->getOsContext().getContextId()); + storage->storeAllocation(std::unique_ptr(allocation1), TEMPORARY_ALLOCATION); + + std::unique_lock allocationDeletionLock(allocation1->mutex); + + auto allocation2 = memoryManager->allocateGraphicsMemoryWithProperties(MockAllocationProperties{MemoryConstants::pageSize}); + allocation2->updateTaskCount(2, csr->getOsContext().getContextId()); + storage->storeAllocation(std::unique_ptr(allocation2), TEMPORARY_ALLOCATION); + + std::mutex mutex; + std::unique_lock lock(mutex); + + std::thread thread1([&] { + storage->cleanAllocationList(1, TEMPORARY_ALLOCATION); + }); + + std::thread thread2([&] { + std::lock_guard lock(mutex); + storage->cleanAllocationList(2, TEMPORARY_ALLOCATION); + }); + + while (!allocation1->inDestructor) + ; + lock.unlock(); + allocationDeletionLock.unlock(); + + thread1.join(); + thread2.join(); + + EXPECT_TRUE(csr->getTemporaryAllocations().peekIsEmpty()); +}