1 // Copyright (C) 2014 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "emugl/common/lazy_instance.h" 16 17 #include "emugl/common/mutex.h" 18 #include "emugl/common/testing/test_thread.h" 19 20 #include <gtest/gtest.h> 21 22 namespace emugl { 23 24 namespace { 25 26 class Foo { 27 public: 28 Foo() : mValue(42) {} 29 int get() const { return mValue; } 30 void set(int value) { mValue = value; } 31 ~Foo() { mValue = 13; } 32 private: 33 int mValue; 34 }; 35 36 class StaticCounter { 37 public: 38 StaticCounter() { 39 Mutex::AutoLock lock(mMutex); 40 mCounter++; 41 } 42 43 int getValue() const { 44 Mutex::AutoLock lock(mMutex); 45 return mCounter; 46 } 47 48 private: 49 static Mutex mMutex; 50 static int mCounter; 51 }; 52 53 // NOTE: This introduces a static C++ constructor for this object file, 54 // but that's ok because a LazyInstance<Mutex> should not be used to 55 // test the behaviour of LazyInstance :-) 56 Mutex StaticCounter::mMutex; 57 int StaticCounter::mCounter = 0; 58 59 } // namespace 60 61 TEST(LazyInstance, HasInstance) { 62 LazyInstance<Foo> foo_instance = LAZY_INSTANCE_INIT; 63 EXPECT_FALSE(foo_instance.hasInstance()); 64 EXPECT_FALSE(foo_instance.hasInstance()); 65 foo_instance.ptr(); 66 EXPECT_TRUE(foo_instance.hasInstance()); 67 } 68 69 TEST(LazyInstance, Simple) { 70 LazyInstance<Foo> foo_instance = LAZY_INSTANCE_INIT; 71 Foo* foo1 = foo_instance.ptr(); 72 EXPECT_TRUE(foo1); 73 EXPECT_EQ(42, foo_instance->get()); 74 foo1->set(10); 75 EXPECT_EQ(10, foo_instance->get()); 76 EXPECT_EQ(foo1, foo_instance.ptr()); 77 } 78 79 // For the following test, launch 1000 threads that each try to get 80 // the instance pointer of a lazy instance. Then verify that they're all 81 // the same value. 82 // 83 // The lazy instance has a special constructor that will increment a 84 // global counter. This allows us to ensure that it is only called once. 85 // 86 87 namespace { 88 89 // The following is the shared structure between all threads. 90 struct MultiState { 91 MultiState(LazyInstance<StaticCounter>* staticCounter) : 92 mMutex(), mStaticCounter(staticCounter), mCount(0) {} 93 94 enum { 95 kMaxThreads = 1000, 96 }; 97 98 Mutex mMutex; 99 LazyInstance<StaticCounter>* mStaticCounter; 100 size_t mCount; 101 void* mValues[kMaxThreads]; 102 TestThread* mThreads[kMaxThreads]; 103 }; 104 105 // The thread function for the test below. 106 static void* threadFunc(void* param) { 107 MultiState* state = static_cast<MultiState*>(param); 108 Mutex::AutoLock lock(state->mMutex); 109 if (state->mCount < MultiState::kMaxThreads) { 110 state->mValues[state->mCount++] = state->mStaticCounter->ptr(); 111 } 112 return NULL; 113 } 114 115 } // namespace 116 117 TEST(LazyInstance, MultipleThreads) { 118 LazyInstance<StaticCounter> counter_instance = LAZY_INSTANCE_INIT; 119 MultiState state(&counter_instance); 120 const size_t kNumThreads = MultiState::kMaxThreads; 121 122 // Create all threads. 123 for (size_t n = 0; n < kNumThreads; ++n) { 124 state.mThreads[n] = new TestThread(threadFunc, &state); 125 } 126 127 // Wait for their completion. 128 for (size_t n = 0; n < kNumThreads; ++n) { 129 state.mThreads[n]->join(); 130 } 131 132 // Now check that the constructor was only called once. 133 EXPECT_EQ(1, counter_instance->getValue()); 134 135 // Now compare all the store values, they should be the same. 136 StaticCounter* expectedValue = counter_instance.ptr(); 137 for (size_t n = 0; n < kNumThreads; ++n) { 138 EXPECT_EQ(expectedValue, state.mValues[n]) << "For thread " << n; 139 } 140 141 for (size_t n = 0; n < kNumThreads; ++n) { 142 delete state.mThreads[n]; 143 } 144 } 145 146 } // namespace emugl 147