diff options
Diffstat (limited to 'Tests/TestApp/src/SmartPointerTest.cpp')
| -rw-r--r-- | Tests/TestApp/src/SmartPointerTest.cpp | 797 |
1 files changed, 0 insertions, 797 deletions
diff --git a/Tests/TestApp/src/SmartPointerTest.cpp b/Tests/TestApp/src/SmartPointerTest.cpp deleted file mode 100644 index 850ca99..0000000 --- a/Tests/TestApp/src/SmartPointerTest.cpp +++ /dev/null @@ -1,797 +0,0 @@ -/* Copyright 2019 Diligent Graphics LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -// EngineSandbox.cpp : Defines the entry point for the application. -// - -#include "pch.h" -#include <thread> -#include "SmartPointerTest.h" -#include "Errors.h" -#include "DefaultRawMemoryAllocator.h" - -using namespace Diligent; - -template<typename Type> -Type* MakeNewObj() -{ - return MakeNewRCObj<Type>().operator()(); -} - -void SmartPointerTest::CreateObject(Object **ppObj) -{ - *ppObj = MakeNewObj<Object>(); - (*ppObj)->AddRef(); -} - -void SmartPointerTest::WaitForThreadStart(int VarId) -{ - std::unique_lock<std::mutex> lk(m_Mtx); - m_CondVar.wait(lk, [&]{return m_bThreadStart[VarId] || m_bStopThreads;}); -} - -void SmartPointerTest::StartThreadsAndWait(int VarId, size_t NumThreads) -{ - { - std::unique_lock<std::mutex> lk(m_Mtx); - m_bThreadStart[VarId] = true; - m_NumThreadsCompleted = 0; - } - m_CondVar.notify_all(); - - while((size_t)m_NumThreadsCompleted < NumThreads) - std::this_thread::yield(); - m_bThreadStart[VarId] = false; - VERIFY_EXPR(m_NumThreadsCompleted == NumThreads); -} - -void SmartPointerTest::WorkerThreadFunc(SmartPointerTest *This, size_t ThreadNum) -{ - while(!This->m_bStopThreads) - { - for(int i =0; i < NumThreadInterations; ++i) - { - // Wait until main() sends data - This->WaitForThreadStart(0); - if(This->m_bStopThreads) - { - This->m_NumThreadsCompleted++; - return; - } - - { - auto *pObject = This->m_pSharedObject; - for(int j=0; j < 100; ++j) - { - //LOG_INFO_MESSAGE("t",std::this_thread::get_id(), ": AddRef" ); - pObject->m_Value++; - pObject->AddRef(); - } - This->m_NumThreadsCompleted++; - - This->WaitForThreadStart(1); - for(int j=0; j < 100; ++j) - { - //LOG_INFO_MESSAGE("t",std::this_thread::get_id(), ": Release" ); - pObject->m_Value--; - pObject->Release(); - } - This->m_NumThreadsCompleted++; - } - - { - This->WaitForThreadStart(0); - auto *pObject = This->m_pSharedObject; - auto *pRefCounters = pObject->GetReferenceCounters(); - if (ThreadNum % 3 == 0) - { - pObject->m_Value++; - pObject->AddRef(); - } - else - pRefCounters->AddWeakRef(); - This->m_NumThreadsCompleted++; - - This->WaitForThreadStart(1); - if (ThreadNum % 3 == 0) - { - pObject->m_Value--; - pObject->Release(); - } - else - pRefCounters->ReleaseWeakRef(); - This->m_NumThreadsCompleted++; - } - - { - // Test interferences of ReleaseStrongRef() and GetObject() - - // Goal: catch scenario when GetObject() runs between - // AtomicDecrement() and acquiring the lock in ReleaseStrongRef(): - - // m_lNumStrongReferences == 1 - // - - // Scenario I - // - // Thread 1 | Thread 2 | Thread 3 - // | | - // | | - // | | - // | 1. Acquire the lock | - // | 2. Increment m_lNumStrongReferences | - // 1. Decrement m_lNumStrongReferences | 3. Read StrongRefCnt > 1 | - // 2. Test RefCount!=0 | 4. Return the reference to object | - // 3. DO NOT destroy the object | | - // 4. Wait for the lock | | - - - // Scenario I - // - // Thread 1 | Thread 2 | Thread 3 - // | | - // | | - // 1. Decrement m_lNumStrongReferences | | - // | 1. Acquire the lock | - // 2. Test RefCount==0 | 2. Increment m_lNumStrongReferences | - // 3. Start destroying the object | 3. Read StrongRefCnt == 1 | - // 4. Wait for the lock | 4. DO NOT create the object | - // | 5. Decrement m_lNumStrongReferences | - // | | 1. Acquire the lock - // | | 2. Increment m_lNumStrongReferences - // | | 3. Read StrongRefCnt == 1 - // | | 4. DO NOT create the object - // | | 5. Decrement m_lNumStrongReferences - // 5. Acquire the lock | - // 6. DESTROY the object | - - This->WaitForThreadStart(0); - auto *pObject = This->m_pSharedObject; - RefCntWeakPtr<Object> weakPtr(pObject); - RefCntAutoPtr<Object> strongPtr, strongPtr2; - if (ThreadNum < 2) - { - strongPtr = pObject; - strongPtr->m_Value++; - } - else - weakPtr = WeakPtr(pObject); - This->m_NumThreadsCompleted++; - - This->WaitForThreadStart(1); - if (ThreadNum == 0) - { - strongPtr->m_Value--; - strongPtr.Release(); - } - else - { - strongPtr2 = weakPtr.Lock(); - if(strongPtr2) - strongPtr2->m_Value++; - weakPtr.Release(); - } - This->m_NumThreadsCompleted++; - } - - - { - This->WaitForThreadStart(0); - auto *pObject = This->m_pSharedObject; - RefCntWeakPtr<Object> weakPtr; - RefCntAutoPtr<Object> strongPtr; - if (ThreadNum % 4 == 0) - { - strongPtr = pObject; - strongPtr->m_Value++; - } - else - weakPtr = WeakPtr(pObject); - This->m_NumThreadsCompleted++; - - This->WaitForThreadStart(1); - if (ThreadNum % 4 == 0) - { - strongPtr->m_Value--; - strongPtr.Release(); - } - else - { - auto Ptr = weakPtr.Lock(); - if(Ptr) - Ptr->m_Value++; - Ptr.Release(); - } - This->m_NumThreadsCompleted++; - } - } - } -} - -void SmartPointerTest::StartConcurrencyTest() -{ - auto numCores = std::thread::hardware_concurrency(); - m_Threads.resize(numCores); - for(auto &t : m_Threads) - t = std::thread(WorkerThreadFunc, this, &t-m_Threads.data()); -} - -SmartPointerTest::~SmartPointerTest() -{ - m_bStopThreads = true; - StartThreadsAndWait(0, m_Threads.size()); - - for(auto &t : m_Threads) - t.join(); - - auto NumIterations = NumThreadInterations; - std::stringstream infoss; - infoss << "Performed " << m_NumTestsPerformed << " concurrency tests with " << NumIterations << " iterations on " << m_Threads.size() << " threads"; - SetStatus(TestResult::Succeeded, infoss.str().c_str()); -} - -void SmartPointerTest::RunConcurrencyTest() -{ - for(int i=0;i<NumThreadInterations; ++i) - { - m_pSharedObject = MakeNewObj<Object>(); - - StartThreadsAndWait(0, m_Threads.size()); - - StartThreadsAndWait(1, m_Threads.size()); - - m_pSharedObject = MakeNewObj<Object>(); - - StartThreadsAndWait(0, m_Threads.size()); - - StartThreadsAndWait(1, m_Threads.size()); - - m_pSharedObject = MakeNewObj<Object>(); - - StartThreadsAndWait(0, m_Threads.size()); - - StartThreadsAndWait(1, m_Threads.size()); - - m_pSharedObject = MakeNewObj<Object>(); - - StartThreadsAndWait(0, m_Threads.size()); - - StartThreadsAndWait(1, m_Threads.size()); - } - ++m_NumTestsPerformed; -} - - -SmartPointerTest::SmartPointerTest() : - UnitTestBase("Smart pointer test"), - m_pSharedObject(nullptr), - m_NumThreadsCompleted(0) -{ - // Test constructors of RefCntAutoPtr - { - SmartPtr SP0; - SmartPtr SP1(nullptr); - auto *pRawPtr = MakeNewObj<Object>(); - SmartPtr SP2(pRawPtr); - SmartPtr SP2_1(pRawPtr); - - SmartPtr SP3(SP0); - SmartPtr SP4(SP2); - SmartPtr SP5(std::move(SP3)); - VERIFY_EXPR(!SP3); - SmartPtr SP6(std::move(SP4)); - VERIFY_EXPR(!SP4); - - RefCntAutoPtr<DerivedObject> DerivedSP(MakeNewObj<DerivedObject>()); - SmartPtr SP7(DerivedSP); - SmartPtr SP8(std::move(DerivedSP)); - VERIFY_EXPR(!DerivedSP); - } - - // Test Attach/Detach - { - { - SmartPtr SP0; - auto *pRawPtr = MakeNewObj<Object>(); - SP0.Attach(nullptr); - SP0.Attach(pRawPtr); - pRawPtr->AddRef(); - } - - { - SmartPtr SP0; - auto *pRawPtr = MakeNewObj<Object>(); - pRawPtr->AddRef(); - SP0.Attach(pRawPtr); - SP0.Attach(nullptr); - } - - { - SmartPtr SP0(MakeNewObj<Object>()); - auto *pRawPtr = MakeNewObj<Object>(); - SP0.Attach(pRawPtr); - pRawPtr->AddRef(); - } - - { - SmartPtr SP0(MakeNewObj<Object>()); - auto *pRawPtr = MakeNewObj<Object>(); - pRawPtr->AddRef(); - SP0.Attach(pRawPtr); - auto *pRawPtr2 = SP0.Detach(); - pRawPtr2->Release(); - - auto *pRawPtr3 = SmartPtr().Detach(); - (void)pRawPtr3; - auto *pRawPtr4 = SmartPtr(MakeNewObj<Object>()).Detach(); - (void)pRawPtr4; - pRawPtr4->Release(); - } - } - - // Test operator = - { - SmartPtr SP0; - auto pRawPtr1 = MakeNewObj<Object>(); - SmartPtr SP1(pRawPtr1); - SmartPtr SP2(pRawPtr1); - SP0 = SP0; - SP0 = std::move(SP0); - SP0 = nullptr; - assert(SP0 == nullptr); - - SP1 = pRawPtr1; - SP1 = SP1; - SP1 = std::move(SP1); - assert(SP1 == pRawPtr1); - - SP1 = SP2; - SP1 = std::move(SP2); - assert(SP1 == pRawPtr1); - - auto pRawPtr2 = MakeNewObj<Object>(); - SmartPtr SP3(pRawPtr2); - - SP0 = pRawPtr2; - SmartPtr SP4; - SP4 = SP3; - SmartPtr SP5; - SP5 = std::move(SP4); - VERIFY_EXPR(!SP4); - - SP1 = pRawPtr2; - SP1 = nullptr; - SP1 = std::move(SP5); - VERIFY_EXPR(!SP5); - - RefCntAutoPtr<DerivedObject> DerivedSP(MakeNewObj<DerivedObject>()); - SP1 = DerivedSP; - SP2 = std::move(DerivedSP); - VERIFY_EXPR(!DerivedSP); - } - - // Test logical operators - { - auto pRawPtr1 = MakeNewObj<Object>(); - auto pRawPtr2 = MakeNewObj<Object>(); - SmartPtr SP0, SP1(pRawPtr1), SP2(pRawPtr1), SP3(pRawPtr2); - assert( !SP0 ); - bool b1 = SP0.operator bool(); - assert( !b1 ); (void)b1; - if(SP0) - assert( false ); - - assert( !(!SP1) ); - assert( SP1 ); - assert( SP0 != SP1 ); - assert( SP0 == SP0 ); - assert( SP1 == SP1 ); - assert( SP1 == SP2 ); - assert( SP1 != SP3 ); - assert( SP0 < SP3 ); - assert( (SP1 < SP3) == (pRawPtr1<pRawPtr2) ); - } - - // Test operator & - { - SmartPtr SP0, SP1(MakeNewObj<Object>()), SP2, SP3, SP4(MakeNewObj<Object>()); - auto *pRawPtr = MakeNewObj<Object>(); - pRawPtr->AddRef(); - - *static_cast<Object**>(&SP0) = pRawPtr; - SP0.Detach(); - *&SP2 = pRawPtr; - SP2.Detach(); - - CreateObject(&SP3); - - CreateObject(&SP1); - *static_cast<Object**>(&SP4) = pRawPtr; - - { - SmartPtr SP5(MakeNewObj<Object>()); - auto pDblPtr = &SP5; - *pDblPtr = MakeNewObj<Object>(); - (*pDblPtr)->AddRef(); - auto pDblPtr2 = &SP5; - CreateObject(pDblPtr2); - } - - SmartPtr SP6(MakeNewObj<Object>()); - // This will not work: - // Object **pDblPtr3 = &SP6; - // *pDblPtr3 = new Object; - } - - // Test constructors of RefCntWeakPtr - { - SmartPtr SP0, SP1(MakeNewObj<Object>()); - WeakPtr WP0; - WeakPtr WP1(WP0); - WeakPtr WP2(SP0); - WeakPtr WP3(SP1); - WeakPtr WP4(WP3); - WeakPtr WP5(std::move(WP0)); - WeakPtr WP6(std::move(WP4)); - - auto *pRawPtr = MakeNewObj<Object>(); - pRawPtr->AddRef(); - WeakPtr WP7(pRawPtr); - pRawPtr->Release(); - } - - // Test operator = - { - auto *pRawPtr = MakeNewObj<Object>(); - SmartPtr SP0, SP1(pRawPtr); - WeakPtr WP0, WP1(SP1), WP2(SP1); - WP0 = WP0; - WP0 = std::move(WP0); - WP1 = WP1; - WP1 = std::move(WP1); - WP1 = WP2; - WP1 = std::move(WP2); - WP1 = pRawPtr; - WP0 = pRawPtr; - WP0.Release(); - WP0 = WP2; - - WP1 = WP0; - WP0 = SP1; - WP2 = std::move(WP1); - } - - // Test logical operators - { - SmartPtr SP0, SP1(MakeNewObj<Object>()); - WeakPtr WP0, WP1(SP0), WP2(SP1), WP3(SP1); - assert( WP0 == WP1 ); - assert( WP0 != WP2 ); - assert( WP2 == WP3 ); - SP1.Release(); - assert( WP2 == WP3 ); - } - - // Test Lock() - { - SmartPtr SP0, SP1(MakeNewObj<Object>()); - WeakPtr WP0, WP1(SP0), WP2(SP1); - WeakPtr WP3(WP2); - auto L1 = WP0.Lock(); - assert( !L1 ); - L1 = WP1.Lock(); - assert( !L1 ); - L1 = WP2.Lock(); - assert( L1 ); - L1 = WP3.Lock(); - assert( L1 ); - auto pRawPtr = SP1.Detach(); - L1.Release(); - - L1 = WP3.Lock(); - assert( L1 ); - L1.Release(); - - pRawPtr->Release(); - - L1 = WP3.Lock(); - assert( !L1 ); - } - - { - class OwnerTest : public RefCountedObject<IObject> - { - public: - OwnerTest(IReferenceCounters *pRefCounters) : - RefCountedObject<IObject>(pRefCounters), - Obj( NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", Object, this)()) - { - } - - virtual void QueryInterface( const INTERFACE_ID &IID, IObject **ppInterface ){} - ~OwnerTest() - { - Obj->~Object(); - DefaultRawMemoryAllocator::GetAllocator().Free(Obj); - } - private: - Object *Obj; - }; - - OwnerTest *pOwnerObject = MakeNewObj<OwnerTest>(); - pOwnerObject->AddRef(); - pOwnerObject->Release(); - } - - { - class SelfRefTest : public RefCountedObject<IObject> - { - public: - SelfRefTest(IReferenceCounters *pRefCounters) : - RefCountedObject<IObject>(pRefCounters), - wpSelf( this ) - {} - - virtual void QueryInterface( const INTERFACE_ID &IID, IObject **ppInterface ){} - private: - RefCntWeakPtr<SelfRefTest> wpSelf; - }; - - SelfRefTest *pSelfRefTest = MakeNewObj<SelfRefTest>(); - pSelfRefTest->AddRef(); - pSelfRefTest->Release(); - } - - { - class ExceptionTest1 : public RefCountedObject<IObject> - { - public: - ExceptionTest1(IReferenceCounters *pRefCounters) : - RefCountedObject<IObject>(pRefCounters), - wpSelf(this) - { - throw std::runtime_error("test exception"); - } - - virtual void QueryInterface( const INTERFACE_ID &IID, IObject **ppInterface ){} - private: - RefCntWeakPtr<ExceptionTest1> wpSelf; - }; - - try - { - auto *pExceptionTest = MakeNewObj<ExceptionTest1>(); - (void)pExceptionTest; - } - catch(std::runtime_error &) - { - - } - } - - { - class ExceptionTest2 : public RefCountedObject<IObject> - { - public: - ExceptionTest2(IReferenceCounters *pRefCounters) : - RefCountedObject<IObject>(pRefCounters), - wpSelf(this) - { - throw std::runtime_error("test exception"); - } - - virtual void QueryInterface( const INTERFACE_ID &IID, IObject **ppInterface ){} - private: - RefCntWeakPtr<ExceptionTest2> wpSelf; - }; - - try - { - auto *pExceptionTest = NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", ExceptionTest2)(); - (void)pExceptionTest; - } - catch(std::runtime_error &) - { - - } - } - - { - class ExceptionTest3 : public RefCountedObject<IObject> - { - public: - ExceptionTest3(IReferenceCounters *pRefCounters) : - RefCountedObject<IObject>(pRefCounters), - m_Member(*this) - { - } - - class Subclass - { - public: - Subclass(ExceptionTest3 &parent) : - wpSelf(&parent) - { - throw std::runtime_error("test exception"); - } - private: - RefCntWeakPtr<ExceptionTest3> wpSelf; - }; - virtual void QueryInterface( const INTERFACE_ID &IID, IObject **ppInterface ){} - private: - Subclass m_Member; - }; - - try - { - auto *pExceptionTest = NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", ExceptionTest3)(); - (void)pExceptionTest; - } - catch(std::runtime_error &) - { - - } - } - - { - class OwnerObject : public RefCountedObject<IObject> - { - public: - OwnerObject(IReferenceCounters *pRefCounters) : - RefCountedObject<IObject>(pRefCounters) - {} - - void CreateMember() - { - try - { - m_pMember = NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", ExceptionTest4, this)(*this); - } - catch (...) - { - - } - } - virtual void QueryInterface( const INTERFACE_ID &IID, IObject **ppInterface ){} - - class ExceptionTest4 : public RefCountedObject<IObject> - { - public: - ExceptionTest4(IReferenceCounters *pRefCounters, OwnerObject &owner) : - RefCountedObject<IObject>(pRefCounters), - m_Member(owner, *this) - { - } - - class Subclass - { - public: - Subclass(OwnerObject &owner, ExceptionTest4 &parent) : - wpParent(&parent), - wpOwner(&owner) - { - throw std::runtime_error("test exception"); - } - private: - RefCntWeakPtr<ExceptionTest4> wpParent; - RefCntWeakPtr<OwnerObject> wpOwner; - }; - virtual void QueryInterface( const INTERFACE_ID &IID, IObject **ppInterface ){} - private: - Subclass m_Member; - }; - - RefCntAutoPtr<ExceptionTest4> m_pMember; - }; - - RefCntAutoPtr<OwnerObject> pOwner( NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", OwnerObject)() ); - pOwner->CreateMember(); - } - - - { - class OwnerObject : public RefCountedObject<IObject> - { - public: - OwnerObject(IReferenceCounters *pRefCounters) : - RefCountedObject<IObject>(pRefCounters) - { - m_pMember = NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", ExceptionTest4, this)(*this); - } - - virtual void QueryInterface( const INTERFACE_ID &IID, IObject **ppInterface ){} - - class ExceptionTest4 : public RefCountedObject<IObject> - { - public: - ExceptionTest4(IReferenceCounters *pRefCounters, OwnerObject &owner) : - RefCountedObject<IObject>(pRefCounters), - m_Member(owner, *this) - { - } - - class Subclass - { - public: - Subclass(OwnerObject &owner, ExceptionTest4 &parent) : - wpParent(&parent), - wpOwner(&owner) - { - throw std::runtime_error("test exception"); - } - private: - RefCntWeakPtr<ExceptionTest4> wpParent; - RefCntWeakPtr<OwnerObject> wpOwner; - }; - virtual void QueryInterface( const INTERFACE_ID &IID, IObject **ppInterface ){} - private: - Subclass m_Member; - }; - - RefCntAutoPtr<ExceptionTest4> m_pMember; - }; - - try - { - RefCntAutoPtr<OwnerObject> pOwner( NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", OwnerObject)() ); - } - catch (...) - { - - } - } - - { - class TestObject : public RefCountedObject<IObject> - { - public: - TestObject(IReferenceCounters *pRefCounters) : - RefCountedObject<IObject>(pRefCounters) - { - } - - virtual void QueryInterface( const INTERFACE_ID &IID, IObject **ppInterface )override final{} - - inline virtual Atomics::Long Release()override final - { - return RefCountedObject<IObject>::Release( - [&]() - { - ppWeakPtr->Release(); - } - ); - } - RefCntWeakPtr<TestObject>* ppWeakPtr = nullptr; - }; - - RefCntAutoPtr<TestObject> pObj( NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", TestObject)() ); - RefCntWeakPtr<TestObject> pWeakPtr(pObj); - - pObj->ppWeakPtr = &pWeakPtr; - pObj.Release(); - } - - StartConcurrencyTest(); - RunConcurrencyTest(); -} - |
