Torque3D Documentation / _generateds / threadSafeRefCountTest.cpp

threadSafeRefCountTest.cpp

Engine/source/platform/threads/test/threadSafeRefCountTest.cpp

More...

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