Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2008 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/threading/simple_thread.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 
     11 namespace {
     12 
     13 base::AtomicSequenceNumber constructed_seq_(base::LINKER_INITIALIZED);
     14 base::AtomicSequenceNumber destructed_seq_(base::LINKER_INITIALIZED);
     15 
     16 class ConstructAndDestructLogger {
     17  public:
     18   ConstructAndDestructLogger() {
     19     constructed_seq_.GetNext();
     20   }
     21   ~ConstructAndDestructLogger() {
     22     destructed_seq_.GetNext();
     23   }
     24 };
     25 
     26 class SlowConstructor {
     27  public:
     28   SlowConstructor() : some_int_(0) {
     29     // Sleep for 1 second to try to cause a race.
     30     base::PlatformThread::Sleep(1000);
     31     ++constructed;
     32     some_int_ = 12;
     33   }
     34   int some_int() const { return some_int_; }
     35 
     36   static int constructed;
     37  private:
     38   int some_int_;
     39 };
     40 
     41 int SlowConstructor::constructed = 0;
     42 
     43 class SlowDelegate : public base::DelegateSimpleThread::Delegate {
     44  public:
     45   explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy)
     46       : lazy_(lazy) {}
     47 
     48   virtual void Run() {
     49     EXPECT_EQ(12, lazy_->Get().some_int());
     50     EXPECT_EQ(12, lazy_->Pointer()->some_int());
     51   }
     52 
     53  private:
     54   base::LazyInstance<SlowConstructor>* lazy_;
     55 };
     56 
     57 }  // namespace
     58 
     59 static base::LazyInstance<ConstructAndDestructLogger> lazy_logger(
     60     base::LINKER_INITIALIZED);
     61 
     62 TEST(LazyInstanceTest, Basic) {
     63   {
     64     base::ShadowingAtExitManager shadow;
     65 
     66     EXPECT_EQ(0, constructed_seq_.GetNext());
     67     EXPECT_EQ(0, destructed_seq_.GetNext());
     68 
     69     lazy_logger.Get();
     70     EXPECT_EQ(2, constructed_seq_.GetNext());
     71     EXPECT_EQ(1, destructed_seq_.GetNext());
     72 
     73     lazy_logger.Pointer();
     74     EXPECT_EQ(3, constructed_seq_.GetNext());
     75     EXPECT_EQ(2, destructed_seq_.GetNext());
     76   }
     77   EXPECT_EQ(4, constructed_seq_.GetNext());
     78   EXPECT_EQ(4, destructed_seq_.GetNext());
     79 }
     80 
     81 static base::LazyInstance<SlowConstructor> lazy_slow(base::LINKER_INITIALIZED);
     82 
     83 TEST(LazyInstanceTest, ConstructorThreadSafety) {
     84   {
     85     base::ShadowingAtExitManager shadow;
     86 
     87     SlowDelegate delegate(&lazy_slow);
     88     EXPECT_EQ(0, SlowConstructor::constructed);
     89 
     90     base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
     91     pool.AddWork(&delegate, 20);
     92     EXPECT_EQ(0, SlowConstructor::constructed);
     93 
     94     pool.Start();
     95     pool.JoinAll();
     96     EXPECT_EQ(1, SlowConstructor::constructed);
     97   }
     98 }
     99 
    100 namespace {
    101 
    102 // DeleteLogger is an object which sets a flag when it's destroyed.
    103 // It accepts a bool* and sets the bool to true when the dtor runs.
    104 class DeleteLogger {
    105  public:
    106   DeleteLogger() : deleted_(NULL) {}
    107   ~DeleteLogger() { *deleted_ = true; }
    108 
    109   void SetDeletedPtr(bool* deleted) {
    110     deleted_ = deleted;
    111   }
    112 
    113  private:
    114   bool* deleted_;
    115 };
    116 
    117 }  // anonymous namespace
    118 
    119 TEST(LazyInstanceTest, LeakyLazyInstance) {
    120   // Check that using a plain LazyInstance causes the dtor to run
    121   // when the AtExitManager finishes.
    122   bool deleted1 = false;
    123   {
    124     base::ShadowingAtExitManager shadow;
    125     static base::LazyInstance<DeleteLogger> test(base::LINKER_INITIALIZED);
    126     test.Get().SetDeletedPtr(&deleted1);
    127   }
    128   EXPECT_TRUE(deleted1);
    129 
    130   // Check that using a *leaky* LazyInstance makes the dtor not run
    131   // when the AtExitManager finishes.
    132   bool deleted2 = false;
    133   {
    134     base::ShadowingAtExitManager shadow;
    135     static base::LazyInstance<DeleteLogger,
    136                               base::LeakyLazyInstanceTraits<DeleteLogger> >
    137         test(base::LINKER_INITIALIZED);
    138     test.Get().SetDeletedPtr(&deleted2);
    139   }
    140   EXPECT_FALSE(deleted2);
    141 }
    142