Home | History | Annotate | Download | only in common
      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