Ensure that BO handle is closed only once

When one process had exported and then opened IPC handle
of memory, then close function was called twice for the
same BO handle. It caused debugBreak() and aborted
an application.

This change allows multiple separate BOs to share one
handle. The last shared handle owner calls close() function.

Related-To: NEO-7200
Signed-off-by: Wrobel, Patryk <patryk.wrobel@intel.com>
This commit is contained in:
Wrobel, Patryk
2023-02-01 15:58:22 +00:00
committed by Compute-Runtime-Automation
parent 272427bb1c
commit 4c58eda90d
12 changed files with 488 additions and 41 deletions

View File

@@ -181,6 +181,35 @@ TEST_F(DrmBufferObjectTest, whenPrintBOCreateDestroyResultFlagIsSetAndCloseIsCal
EXPECT_EQ(expectedValue, idx);
}
TEST_F(DrmBufferObjectTest, whenPrintBOCreateDestroyResultFlagIsSetAndCloseIsCalledButHandleIsSharedThenDebugInfromationIsPrintedThatCloseIsSkipped) {
mock->ioctl_expected.total = 1;
DebugManagerStateRestore stateRestore;
DebugManager.flags.PrintBOCreateDestroyResult.set(true);
{
MockBufferObjectHandleWrapper sharedBoHandleWrapper = bo->acquireSharedOwnershipOfBoHandle();
EXPECT_TRUE(bo->isBoHandleShared());
testing::internal::CaptureStdout();
bool result = bo->close();
EXPECT_EQ(true, result);
std::string output = testing::internal::GetCapturedStdout();
size_t idx = output.find("Skipped closing BO-");
size_t expectedValue = 0u;
EXPECT_EQ(expectedValue, idx);
}
testing::internal::CaptureStdout();
bool result = bo->close();
EXPECT_EQ(true, result);
std::string output = testing::internal::GetCapturedStdout();
size_t idx = output.find("Calling gem close on handle: BO-");
size_t expectedValue = 0;
EXPECT_EQ(expectedValue, idx);
}
TEST_F(DrmBufferObjectTest, whenPrintExecutionBufferIsSetToTrueThenMessageFoundInStdStream) {
mock->ioctl_expected.total = 1;
DebugManagerStateRestore restore;
@@ -620,3 +649,140 @@ TEST_F(DrmBufferObjectTest, whenBoRequiresExplicitResidencyThenTheCorrespondingQ
EXPECT_EQ(required, bo.isExplicitResidencyRequired());
}
}
TEST(DrmBufferObjectHandleWrapperTest, GivenWrapperConstructedFromNonSharedHandleThenControlBlockIsNotCreatedAndInternalHandleIsStored) {
constexpr int boHandle{5};
MockBufferObjectHandleWrapper boHandleWrapper{boHandle};
EXPECT_EQ(nullptr, boHandleWrapper.controlBlock);
EXPECT_EQ(boHandle, boHandleWrapper.getBoHandle());
}
TEST(DrmBufferObjectHandleWrapperTest, GivenWrapperConstructedFromNonSharedHandleWhenAskingIfCanBeClosedThenReturnTrue) {
constexpr int boHandle{21};
MockBufferObjectHandleWrapper boHandleWrapper{boHandle};
EXPECT_TRUE(boHandleWrapper.canCloseBoHandle());
}
TEST(DrmBufferObjectHandleWrapperTest, GivenWrapperWhenSettingNewValueThenStoreIt) {
constexpr int boHandle{13};
MockBufferObjectHandleWrapper boHandleWrapper{boHandle};
boHandleWrapper.setBoHandle(-1);
EXPECT_EQ(-1, boHandleWrapper.getBoHandle());
}
TEST(DrmBufferObjectHandleWrapperTest, GivenWrapperConstructedFromNonSharedHandleWhenMakingItSharedThenControlBlockIsCreatedAndReferenceCounterIsValid) {
constexpr int boHandle{85};
MockBufferObjectHandleWrapper firstBoHandleWrapper{boHandle};
MockBufferObjectHandleWrapper secondBoHandleWrapper = firstBoHandleWrapper.acquireSharedOwnership();
ASSERT_NE(nullptr, firstBoHandleWrapper.controlBlock);
ASSERT_NE(nullptr, secondBoHandleWrapper.controlBlock);
EXPECT_EQ(firstBoHandleWrapper.controlBlock, secondBoHandleWrapper.controlBlock);
EXPECT_EQ(firstBoHandleWrapper.boHandle, secondBoHandleWrapper.boHandle);
EXPECT_EQ(2, firstBoHandleWrapper.controlBlock->refCount);
}
TEST(DrmBufferObjectHandleWrapperTest, GivenMoreThanOneSharedHandleWrapperWhenAskingIfHandleCanBeClosedThenReturnFalse) {
constexpr int boHandle{121};
MockBufferObjectHandleWrapper firstBoHandleWrapper{boHandle};
MockBufferObjectHandleWrapper secondBoHandleWrapper = firstBoHandleWrapper.acquireSharedOwnership();
EXPECT_FALSE(firstBoHandleWrapper.canCloseBoHandle());
EXPECT_FALSE(secondBoHandleWrapper.canCloseBoHandle());
}
TEST(DrmBufferObjectHandleWrapperTest, GivenControlBlockCreatedWhenOnlyOneReferenceLeftThenHandleCanBeClosed) {
constexpr int boHandle{121};
MockBufferObjectHandleWrapper firstBoHandleWrapper{boHandle};
{
MockBufferObjectHandleWrapper secondBoHandleWrapper = firstBoHandleWrapper.acquireSharedOwnership();
ASSERT_NE(nullptr, firstBoHandleWrapper.controlBlock);
ASSERT_NE(nullptr, secondBoHandleWrapper.controlBlock);
EXPECT_EQ(firstBoHandleWrapper.controlBlock, secondBoHandleWrapper.controlBlock);
EXPECT_EQ(2, firstBoHandleWrapper.controlBlock->refCount);
}
EXPECT_TRUE(firstBoHandleWrapper.canCloseBoHandle());
}
TEST(DrmBufferObjectHandleWrapperTest, GivenControlBlockCreatedWhenOnlyWeakReferencesLeftThenItIsNotDestroyed) {
constexpr int boHandle{777};
auto firstBoHandleWrapper = std::make_unique<MockBufferObjectHandleWrapper>(boHandle);
MockBufferObjectHandleWrapper weakHandleWrapper = firstBoHandleWrapper->acquireWeakOwnership();
ASSERT_NE(nullptr, firstBoHandleWrapper->controlBlock);
ASSERT_NE(nullptr, weakHandleWrapper.controlBlock);
EXPECT_EQ(firstBoHandleWrapper->controlBlock, weakHandleWrapper.controlBlock);
firstBoHandleWrapper.reset();
EXPECT_EQ(0, weakHandleWrapper.controlBlock->refCount);
EXPECT_EQ(1, weakHandleWrapper.controlBlock->weakRefCount);
}
TEST(DrmBufferObjectHandleWrapperTest, GivenControlBlockCreatedWhenWeakReferencesLeftAndOnlyOneStrongReferenceLeftThenHandleCanBeClosed) {
constexpr int boHandle{353};
MockBufferObjectHandleWrapper firstBoHandleWrapper{boHandle};
MockBufferObjectHandleWrapper firstWeakHandleWrapper = firstBoHandleWrapper.acquireWeakOwnership();
MockBufferObjectHandleWrapper secondWeakHandleWrapper = firstBoHandleWrapper.acquireWeakOwnership();
ASSERT_NE(nullptr, firstBoHandleWrapper.controlBlock);
ASSERT_NE(nullptr, firstWeakHandleWrapper.controlBlock);
ASSERT_NE(nullptr, secondWeakHandleWrapper.controlBlock);
EXPECT_EQ(firstBoHandleWrapper.controlBlock, firstWeakHandleWrapper.controlBlock);
EXPECT_EQ(firstBoHandleWrapper.controlBlock, secondWeakHandleWrapper.controlBlock);
EXPECT_EQ(1, firstBoHandleWrapper.controlBlock->refCount);
EXPECT_EQ(2, firstBoHandleWrapper.controlBlock->weakRefCount);
EXPECT_TRUE(firstBoHandleWrapper.canCloseBoHandle());
}
TEST(DrmBufferObjectHandleWrapperTest, GivenWrapperWhenConstructingMoreThanTwoSharedResourcesControlBlockRemainsTheSameAndReferenceCounterIsUpdatedOnCreationAndDestruction) {
constexpr int boHandle{85};
MockBufferObjectHandleWrapper firstBoHandleWrapper{boHandle};
MockBufferObjectHandleWrapper secondBoHandleWrapper = firstBoHandleWrapper.acquireSharedOwnership();
ASSERT_EQ(firstBoHandleWrapper.controlBlock, secondBoHandleWrapper.controlBlock);
auto controlBlock = firstBoHandleWrapper.controlBlock;
ASSERT_NE(nullptr, controlBlock);
EXPECT_EQ(2, controlBlock->refCount);
{
MockBufferObjectHandleWrapper thirdBoHandleWrapper = firstBoHandleWrapper.acquireSharedOwnership();
EXPECT_EQ(firstBoHandleWrapper.boHandle, thirdBoHandleWrapper.boHandle);
ASSERT_EQ(controlBlock, thirdBoHandleWrapper.controlBlock);
EXPECT_EQ(3, controlBlock->refCount);
}
EXPECT_EQ(2, controlBlock->refCount);
}
TEST(DrmBufferObjectHandleWrapperTest, GivenWrapperWhenMoveConstructingAnotherObjectThenInternalDataIsCleared) {
constexpr int boHandle{27};
MockBufferObjectHandleWrapper firstBoHandleWrapper{boHandle};
MockBufferObjectHandleWrapper secondBoHandleWrapper = firstBoHandleWrapper.acquireSharedOwnership();
auto oldControlBlock = firstBoHandleWrapper.controlBlock;
auto oldBoHandle = firstBoHandleWrapper.boHandle;
MockBufferObjectHandleWrapper anotherWrapper{std::move(firstBoHandleWrapper)};
EXPECT_EQ(oldControlBlock, anotherWrapper.controlBlock);
EXPECT_EQ(oldBoHandle, anotherWrapper.boHandle);
EXPECT_EQ(nullptr, firstBoHandleWrapper.controlBlock);
EXPECT_EQ(-1, firstBoHandleWrapper.boHandle);
EXPECT_EQ(2, secondBoHandleWrapper.controlBlock->refCount);
}

View File

@@ -839,6 +839,66 @@ TEST_F(DrmMemoryManagerTest, GivenAllocationWhenClosingSharedHandleThenSucceeds)
memoryManager->freeGraphicsMemory(graphicsAllocation);
}
TEST_F(DrmMemoryManagerTest, GivenNullptrDrmAllocationWhenTryingToRegisterItThenRegisterSharedBoHandleAllocationDoesNothing) {
ASSERT_TRUE(memoryManager->sharedBoHandles.empty());
memoryManager->registerSharedBoHandleAllocation(nullptr);
EXPECT_TRUE(memoryManager->sharedBoHandles.empty());
}
TEST_F(DrmMemoryManagerTest, GivenAllocationWhenTryingToRegisterIpcExportedThenItsBoIsMarkedAsSharedHandleAndHandleIsStored) {
mock->ioctl_expected.gemUserptr = 1;
mock->ioctl_expected.gemWait = 1;
mock->ioctl_expected.gemClose = 1;
ASSERT_TRUE(memoryManager->sharedBoHandles.empty());
auto alloc = static_cast<DrmAllocation *>(memoryManager->allocateGraphicsMemoryWithProperties(MockAllocationProperties{rootDeviceIndex, MemoryConstants::pageSize}));
ASSERT_NE(nullptr, alloc);
EXPECT_NE(nullptr, alloc->getBO());
memoryManager->registerIpcExportedAllocation(alloc);
EXPECT_FALSE(memoryManager->sharedBoHandles.empty());
auto &bos = alloc->getBOs();
for (auto *bo : bos) {
if (bo) {
EXPECT_TRUE(bo->isBoHandleShared());
EXPECT_EQ(1u, memoryManager->sharedBoHandles.count(bo->getHandle()));
}
}
memoryManager->freeGraphicsMemory(alloc);
EXPECT_TRUE(memoryManager->sharedBoHandles.empty());
}
TEST_F(DrmMemoryManagerTest, GivenEmptySharedBoHandlesContainerWhenTryingToGetSharedOwnershipOfNonregisteredHandleThenCreateNewWrapper) {
ASSERT_TRUE(memoryManager->sharedBoHandles.empty());
const int someNonregisteredHandle{123};
auto boHandleWrapper = memoryManager->tryToGetBoHandleWrapperWithSharedOwnership(someNonregisteredHandle);
EXPECT_EQ(someNonregisteredHandle, boHandleWrapper.getBoHandle());
EXPECT_TRUE(memoryManager->sharedBoHandles.empty());
}
TEST_F(DrmMemoryManagerTest, GivenWrapperInBoHandlesContainerWhenTryingToGetSharedOwnershipOfWrappedHandleThenGetSharedOwnership) {
const int boHandle{27};
BufferObjectHandleWrapper boHandleWrapper{boHandle};
memoryManager->sharedBoHandles.emplace(boHandle, boHandleWrapper.acquireWeakOwnership());
ASSERT_EQ(1u, memoryManager->sharedBoHandles.count(boHandle));
{
auto newBoHandleWrapper = memoryManager->tryToGetBoHandleWrapperWithSharedOwnership(boHandle);
EXPECT_EQ(boHandle, newBoHandleWrapper.getBoHandle());
EXPECT_EQ(1u, memoryManager->sharedBoHandles.count(boHandle));
EXPECT_FALSE(newBoHandleWrapper.canCloseBoHandle());
}
EXPECT_EQ(1u, memoryManager->sharedBoHandles.count(boHandle));
EXPECT_TRUE(boHandleWrapper.canCloseBoHandle());
}
TEST_F(DrmMemoryManagerTest, GivenDeviceSharedAllocationWhichRequiresHostMapThenCorrectAlignmentReturned) {
mock->ioctl_expected.primeFdToHandle = 1;
mock->ioctl_expected.gemWait = 1;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2022 Intel Corporation
* Copyright (C) 2019-2023 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -34,7 +34,7 @@ TEST(FileLogger, GivenLogAllocationMemoryPoolFlagThenLogsCorrectInfo) {
allocation.setCpuPtrAndGpuAddress(&allocation, canonizedGpuAddress);
MockBufferObject bo(&drm);
bo.handle = 4;
bo.handle.setBoHandle(4);
allocation.bufferObjects[0] = &bo;
@@ -85,7 +85,7 @@ TEST(FileLogger, givenLogAllocationStdoutWhenLogAllocationThenLogToStdoutInstead
allocation.setCpuPtrAndGpuAddress(&allocation, canonizedGpuAddress);
MockBufferObject bo(&drm);
bo.handle = 4;
bo.handle.setBoHandle(4);
allocation.bufferObjects[0] = &bo;