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:
Foo()28     Foo() : mValue(42) {}
get() const29     int get() const { return mValue; }
set(int value)30     void set(int value) { mValue = value; }
~Foo()31     ~Foo() { mValue = 13; }
32 private:
33     int mValue;
34 };
35 
36 class StaticCounter {
37 public:
StaticCounter()38     StaticCounter() {
39         Mutex::AutoLock lock(mMutex);
40         mCounter++;
41     }
42 
getValue() const43     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 
TEST(LazyInstance,HasInstance)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 
TEST(LazyInstance,Simple)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 {
MultiStateemugl::__anone42ca5470211::MultiState91     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.
threadFunc(void * param)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 
TEST(LazyInstance,MultipleThreads)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