blob: e25366e228f5948e39bea955204cada3eb4775f9 [file] [log] [blame]
fischman@chromium.org998561e2012-01-24 07:56:41 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
deanm@google.coma6deb002008-09-08 23:11:13 +09002// 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"
jbates@chromium.orgdde8e302012-02-24 02:52:20 +09008#include "base/memory/aligned_memory.h"
brettw@chromium.org34f964f2010-12-31 03:08:36 +09009#include "base/threading/simple_thread.h"
deanm@google.coma6deb002008-09-08 23:11:13 +090010#include "testing/gtest/include/gtest/gtest.h"
11
12namespace {
13
pliard@chromium.orgac1f41d2012-03-13 21:07:19 +090014base::StaticAtomicSequenceNumber constructed_seq_;
15base::StaticAtomicSequenceNumber destructed_seq_;
deanm@google.coma6deb002008-09-08 23:11:13 +090016
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) {
brettw@chromium.org61391822011-01-01 05:02:16 +090030 // Sleep for 1 second to try to cause a race.
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +090031 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
deanm@google.coma6deb002008-09-08 23:11:13 +090032 ++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:
erg@google.combf6ce9f2010-01-27 08:08:02 +090046 explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy)
47 : lazy_(lazy) {}
48
rsleevi@chromium.orgde3a6cf2012-04-06 12:53:02 +090049 virtual void Run() OVERRIDE {
deanm@google.coma6deb002008-09-08 23:11:13 +090050 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
joth@chromium.orgb24883c2011-11-15 22:31:49 +090060static base::LazyInstance<ConstructAndDestructLogger> lazy_logger =
61 LAZY_INSTANCE_INITIALIZER;
deanm@google.coma6deb002008-09-08 23:11:13 +090062
63TEST(LazyInstanceTest, Basic) {
64 {
phajdan.jr@chromium.orge7f133a2009-11-19 18:11:39 +090065 base::ShadowingAtExitManager shadow;
deanm@google.coma6deb002008-09-08 23:11:13 +090066
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());
maruel@chromium.org8fe7adc2009-03-04 00:01:12 +090077 }
deanm@google.coma6deb002008-09-08 23:11:13 +090078 EXPECT_EQ(4, constructed_seq_.GetNext());
79 EXPECT_EQ(4, destructed_seq_.GetNext());
80}
81
joth@chromium.orgb24883c2011-11-15 22:31:49 +090082static base::LazyInstance<SlowConstructor> lazy_slow =
83 LAZY_INSTANCE_INITIALIZER;
deanm@google.coma6deb002008-09-08 23:11:13 +090084
85TEST(LazyInstanceTest, ConstructorThreadSafety) {
86 {
phajdan.jr@chromium.orge7f133a2009-11-19 18:11:39 +090087 base::ShadowingAtExitManager shadow;
deanm@google.coma6deb002008-09-08 23:11:13 +090088
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}
evan@chromium.orga04f70c2010-10-22 05:41:47 +0900101
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;
joth@chromium.orgb24883c2011-11-15 22:31:49 +0900127 static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER;
evan@chromium.orga04f70c2010-10-22 05:41:47 +0900128 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;
fischman@chromium.org998561e2012-01-24 07:56:41 +0900137 static base::LazyInstance<DeleteLogger>::Leaky
joth@chromium.orgb24883c2011-11-15 22:31:49 +0900138 test = LAZY_INSTANCE_INITIALIZER;
evan@chromium.orga04f70c2010-10-22 05:41:47 +0900139 test.Get().SetDeletedPtr(&deleted2);
140 }
141 EXPECT_FALSE(deleted2);
142}
jbates@chromium.orgdde8e302012-02-24 02:52:20 +0900143
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}