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
12namespace {
13
14base::StaticAtomicSequenceNumber constructed_seq_;
15base::StaticAtomicSequenceNumber destructed_seq_;
16
17class ConstructAndDestructLogger {
18 public:
19  ConstructAndDestructLogger() {
20    constructed_seq_.GetNext();
21  }
22  ~ConstructAndDestructLogger() {
23    destructed_seq_.GetNext();
24  }
25};
26
27class 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
42int SlowConstructor::constructed = 0;
43
44class 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
60static base::LazyInstance<ConstructAndDestructLogger> lazy_logger =
61    LAZY_INSTANCE_INITIALIZER;
62
63TEST(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
82static base::LazyInstance<SlowConstructor> lazy_slow =
83    LAZY_INSTANCE_INITIALIZER;
84
85TEST(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
102namespace {
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.
106class 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
121TEST(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
144namespace {
145
146template <size_t alignment>
147class 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
159TEST(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