Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/at_exit.h"
      6 #include "base/atomic_sequence_num.h"
      7 #include "base/lazy_instance.h"
      8 #include "base/memory/aligned_memory.h"
      9 #include "base/threading/simple_thread.h"
     10 #include "testing/gtest/include/gtest/gtest.h"
     11 
     12 namespace {
     13 
     14 base::StaticAtomicSequenceNumber constructed_seq_;
     15 base::StaticAtomicSequenceNumber destructed_seq_;
     16 
     17 class ConstructAndDestructLogger {
     18  public:
     19   ConstructAndDestructLogger() {
     20     constructed_seq_.GetNext();
     21   }
     22   ~ConstructAndDestructLogger() {
     23     destructed_seq_.GetNext();
     24   }
     25 };
     26 
     27 class SlowConstructor {
     28  public:
     29   SlowConstructor() : some_int_(0) {
     30     // Sleep for 1 second to try to cause a race.
     31     base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
     32     ++constructed;
     33     some_int_ = 12;
     34   }
     35   int some_int() const { return some_int_; }
     36 
     37   static int constructed;
     38  private:
     39   int some_int_;
     40 };
     41 
     42 int SlowConstructor::constructed = 0;
     43 
     44 class SlowDelegate : public base::DelegateSimpleThread::Delegate {
     45  public:
     46   explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy)
     47       : lazy_(lazy) {}
     48 
     49   virtual void Run() OVERRIDE {
     50     EXPECT_EQ(12, lazy_->Get().some_int());
     51     EXPECT_EQ(12, lazy_->Pointer()->some_int());
     52   }
     53 
     54  private:
     55   base::LazyInstance<SlowConstructor>* lazy_;
     56 };
     57 
     58 }  // namespace
     59 
     60 static base::LazyInstance<ConstructAndDestructLogger> lazy_logger =
     61     LAZY_INSTANCE_INITIALIZER;
     62 
     63 TEST(LazyInstanceTest, Basic) {
     64   {
     65     base::ShadowingAtExitManager shadow;
     66 
     67     EXPECT_EQ(0, constructed_seq_.GetNext());
     68     EXPECT_EQ(0, destructed_seq_.GetNext());
     69 
     70     lazy_logger.Get();
     71     EXPECT_EQ(2, constructed_seq_.GetNext());
     72     EXPECT_EQ(1, destructed_seq_.GetNext());
     73 
     74     lazy_logger.Pointer();
     75     EXPECT_EQ(3, constructed_seq_.GetNext());
     76     EXPECT_EQ(2, destructed_seq_.GetNext());
     77   }
     78   EXPECT_EQ(4, constructed_seq_.GetNext());
     79   EXPECT_EQ(4, destructed_seq_.GetNext());
     80 }
     81 
     82 static base::LazyInstance<SlowConstructor> lazy_slow =
     83     LAZY_INSTANCE_INITIALIZER;
     84 
     85 TEST(LazyInstanceTest, ConstructorThreadSafety) {
     86   {
     87     base::ShadowingAtExitManager shadow;
     88 
     89     SlowDelegate delegate(&lazy_slow);
     90     EXPECT_EQ(0, SlowConstructor::constructed);
     91 
     92     base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
     93     pool.AddWork(&delegate, 20);
     94     EXPECT_EQ(0, SlowConstructor::constructed);
     95 
     96     pool.Start();
     97     pool.JoinAll();
     98     EXPECT_EQ(1, SlowConstructor::constructed);
     99   }
    100 }
    101 
    102 namespace {
    103 
    104 // DeleteLogger is an object which sets a flag when it's destroyed.
    105 // It accepts a bool* and sets the bool to true when the dtor runs.
    106 class DeleteLogger {
    107  public:
    108   DeleteLogger() : deleted_(NULL) {}
    109   ~DeleteLogger() { *deleted_ = true; }
    110 
    111   void SetDeletedPtr(bool* deleted) {
    112     deleted_ = deleted;
    113   }
    114 
    115  private:
    116   bool* deleted_;
    117 };
    118 
    119 }  // anonymous namespace
    120 
    121 TEST(LazyInstanceTest, LeakyLazyInstance) {
    122   // Check that using a plain LazyInstance causes the dtor to run
    123   // when the AtExitManager finishes.
    124   bool deleted1 = false;
    125   {
    126     base::ShadowingAtExitManager shadow;
    127     static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER;
    128     test.Get().SetDeletedPtr(&deleted1);
    129   }
    130   EXPECT_TRUE(deleted1);
    131 
    132   // Check that using a *leaky* LazyInstance makes the dtor not run
    133   // when the AtExitManager finishes.
    134   bool deleted2 = false;
    135   {
    136     base::ShadowingAtExitManager shadow;
    137     static base::LazyInstance<DeleteLogger>::Leaky
    138         test = LAZY_INSTANCE_INITIALIZER;
    139     test.Get().SetDeletedPtr(&deleted2);
    140   }
    141   EXPECT_FALSE(deleted2);
    142 }
    143 
    144 namespace {
    145 
    146 template <size_t alignment>
    147 class AlignedData {
    148  public:
    149   AlignedData() {}
    150   ~AlignedData() {}
    151   base::AlignedMemory<alignment, alignment> data_;
    152 };
    153 
    154 }  // anonymous namespace
    155 
    156 #define EXPECT_ALIGNED(ptr, align) \
    157     EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
    158 
    159 TEST(LazyInstanceTest, Alignment) {
    160   using base::LazyInstance;
    161 
    162   // Create some static instances with increasing sizes and alignment
    163   // requirements. By ordering this way, the linker will need to do some work to
    164   // ensure proper alignment of the static data.
    165   static LazyInstance<AlignedData<4> > align4 = LAZY_INSTANCE_INITIALIZER;
    166   static LazyInstance<AlignedData<32> > align32 = LAZY_INSTANCE_INITIALIZER;
    167   static LazyInstance<AlignedData<4096> > align4096 = LAZY_INSTANCE_INITIALIZER;
    168 
    169   EXPECT_ALIGNED(align4.Pointer(), 4);
    170   EXPECT_ALIGNED(align32.Pointer(), 32);
    171   EXPECT_ALIGNED(align4096.Pointer(), 4096);
    172 }
    173