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