threadSafeRefCountTest.cpp
Engine/source/platform/threads/test/threadSafeRefCountTest.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2014 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#ifdef TORQUE_TESTS_ENABLED 25#include "testing/unitTesting.h" 26#include "platform/threads/threadSafeRefCount.h" 27#include "platform/threads/thread.h" 28#include "core/util/tVector.h" 29#include "console/console.h" 30 31FIXTURE(ThreadSafeRefCount) 32{ 33public: 34 struct TestObjectDtor : public ThreadSafeRefCount<TestObjectDtor> 35 { 36 bool &flag; 37 TestObjectDtor(bool &f) : flag(f) 38 { 39 flag = false; 40 } 41 ~TestObjectDtor() 42 { 43 flag = true; 44 } 45 }; 46 typedef ThreadSafeRef<TestObjectDtor> TestObjectDtorRef; 47 48 enum 49 { 50 NUM_ADD_REFS_PER_THREAD = 10, 51 NUM_EXTRA_REFS_PER_THREAD = 10, 52 NUM_THREADS = 10 53 }; 54 55 class TestObject : public ThreadSafeRefCount<TestObject> {}; 56 typedef ThreadSafeRef<TestObject> TestObjectRef; 57 58 class TestThread : public Thread 59 { 60 public: 61 TestObjectRef mRef; 62 Vector<TestObjectRef> mExtraRefs; 63 64 TestThread(TestObjectRef ref) : mRef(ref) {} 65 66 void run(void* arg) 67 { 68 if (!arg) 69 { 70 // Create references. 71 for (U32 i = 0; i < NUM_ADD_REFS_PER_THREAD; i++) 72 mRef->addRef(); 73 74 mExtraRefs.setSize(NUM_EXTRA_REFS_PER_THREAD); 75 for (U32 i = 0; i < NUM_EXTRA_REFS_PER_THREAD; i++) 76 mExtraRefs[i] = mRef; 77 } 78 else 79 { 80 // Clear references. 81 mExtraRefs.clear(); 82 for (U32 i = 0; i < NUM_ADD_REFS_PER_THREAD; i++) 83 mRef->release(); 84 } 85 } 86 }; 87 88}; 89 90TEST_FIX(ThreadSafeRefCount, Serial) 91{ 92 bool deleted = false; 93 TestObjectDtorRef ref1 = new TestObjectDtor(deleted); 94 ASSERT_FALSE(deleted); 95 EXPECT_FALSE(ref1->isShared()); 96 EXPECT_TRUE(ref1 != NULL); 97 98 TestObjectDtorRef ref2 = ref1; 99 EXPECT_TRUE(ref1->isShared()); 100 EXPECT_TRUE(ref2->isShared()); 101 EXPECT_EQ(ref1, ref2); 102 103 ref1 = NULL; 104 EXPECT_FALSE(ref2->isShared()); 105 106 ref2 = NULL; 107 ASSERT_TRUE(deleted); 108} 109 110TEST_FIX(ThreadSafeRefCount, Concurrent) 111{ 112 TestObjectRef mRef = new TestObject; 113 EXPECT_EQ(2, mRef->getRefCount()); // increments of 2 114 115 Vector<TestThread*> threads; 116 threads.setSize(NUM_THREADS); 117 118 // Create threads. 119 for (U32 i = 0; i < NUM_THREADS; i++) 120 threads[i] = new TestThread(mRef); 121 122 // Run phase 1: create references. 123 for (U32 i = 0; i < NUM_THREADS; i++) 124 threads[i]->start(NULL); 125 126 // Wait for completion. 127 for (U32 i = 0; i < NUM_THREADS; i++) 128 threads[i]->join(); 129 130 EXPECT_EQ(2 + ((1 + NUM_ADD_REFS_PER_THREAD + NUM_EXTRA_REFS_PER_THREAD) * NUM_THREADS * 2), 131 mRef->getRefCount()); 132 133 // Run phase 2: release references. 134 for (U32 i = 0; i < NUM_THREADS; i++) 135 threads[i]->start((void*) 1); 136 137 // Wait for completion. 138 for (U32 i = 0; i < NUM_THREADS; i++) 139 { 140 threads[i]->join(); 141 delete threads[i]; 142 } 143 144 EXPECT_EQ(2, mRef->getRefCount()); // increments of two 145 146 mRef = NULL; 147} 148 149TEST_FIX(ThreadSafeRefCount, Tagging) 150{ 151 TestObjectRef ref; 152 EXPECT_FALSE(ref.isTagged()); 153 EXPECT_FALSE(bool(ref)); 154 EXPECT_FALSE(bool(ref.ptr())); 155 156 EXPECT_TRUE(ref.trySetFromTo(ref, NULL)); 157 EXPECT_FALSE(ref.isTagged()); 158 159 EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_Set)); 160 EXPECT_TRUE(ref.isTagged()); 161 EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_Set)); 162 EXPECT_TRUE(ref.isTagged()); 163 164 EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_Unset)); 165 EXPECT_FALSE(ref.isTagged()); 166 EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_Unset)); 167 EXPECT_FALSE(ref.isTagged()); 168 169 EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_SetOrFail)); 170 EXPECT_TRUE(ref.isTagged()); 171 EXPECT_FALSE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_SetOrFail)); 172 EXPECT_TRUE(ref.isTagged()); 173 EXPECT_FALSE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_FailIfSet)); 174 175 EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_UnsetOrFail)); 176 EXPECT_FALSE(ref.isTagged()); 177 EXPECT_FALSE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_UnsetOrFail)); 178 EXPECT_FALSE(ref.isTagged()); 179 EXPECT_FALSE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_FailIfUnset)); 180 181 TestObjectRef objectA = new TestObject; 182 TestObjectRef objectB = new TestObject; 183 184 EXPECT_FALSE(objectA->isShared()); 185 EXPECT_FALSE(objectB->isShared()); 186 187 ref = objectA; 188 EXPECT_FALSE(ref.isTagged()); 189 EXPECT_TRUE(ref == objectA); 190 EXPECT_TRUE(ref == objectA.ptr()); 191 EXPECT_TRUE(objectA->isShared()); 192 193 EXPECT_TRUE(ref.trySetFromTo(objectA, objectB, TestObjectRef::TAG_Set)); 194 EXPECT_TRUE(ref.isTagged()); 195 EXPECT_EQ(ref, objectB); 196 EXPECT_EQ(ref, objectB.ptr()); 197 EXPECT_TRUE(objectB->isShared()); 198 EXPECT_FALSE(objectA->isShared()); 199 200 EXPECT_TRUE(ref.trySetFromTo(ref, objectA)); 201 EXPECT_TRUE(ref.isTagged()); 202 EXPECT_EQ(ref, objectA); 203 EXPECT_EQ(ref, objectA.ptr()); 204} 205 206#endif 207