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