blob: 1bd3ab4a7a7a57b3087f5173841ac084f5826f02 [file] [log] [blame]
[email protected]9fc44162012-01-23 22:56:411// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]30039e62008-09-08 14:11:132// 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"
[email protected]ac9ba8fe2010-12-30 18:08:368#include "base/threading/simple_thread.h"
[email protected]30039e62008-09-08 14:11:139#include "testing/gtest/include/gtest/gtest.h"
10
11namespace {
12
[email protected]30039e62008-09-08 14:11:1313base::AtomicSequenceNumber constructed_seq_(base::LINKER_INITIALIZED);
14base::AtomicSequenceNumber destructed_seq_(base::LINKER_INITIALIZED);
15
16class ConstructAndDestructLogger {
17 public:
18 ConstructAndDestructLogger() {
19 constructed_seq_.GetNext();
20 }
21 ~ConstructAndDestructLogger() {
22 destructed_seq_.GetNext();
23 }
24};
25
26class SlowConstructor {
27 public:
28 SlowConstructor() : some_int_(0) {
[email protected]ce072a72010-12-31 20:02:1629 // Sleep for 1 second to try to cause a race.
[email protected]a1b75b942011-12-31 22:53:5130 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
[email protected]30039e62008-09-08 14:11:1331 ++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
41int SlowConstructor::constructed = 0;
42
43class SlowDelegate : public base::DelegateSimpleThread::Delegate {
44 public:
[email protected]2fdc86a2010-01-26 23:08:0245 explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy)
46 : lazy_(lazy) {}
47
[email protected]30039e62008-09-08 14:11:1348 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
[email protected]6de0fd1d2011-11-15 13:31:4959static base::LazyInstance<ConstructAndDestructLogger> lazy_logger =
60 LAZY_INSTANCE_INITIALIZER;
[email protected]30039e62008-09-08 14:11:1361
62TEST(LazyInstanceTest, Basic) {
63 {
[email protected]4ea927b2009-11-19 09:11:3964 base::ShadowingAtExitManager shadow;
[email protected]30039e62008-09-08 14:11:1365
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());
[email protected]52a261f2009-03-03 15:01:1276 }
[email protected]30039e62008-09-08 14:11:1377 EXPECT_EQ(4, constructed_seq_.GetNext());
78 EXPECT_EQ(4, destructed_seq_.GetNext());
79}
80
[email protected]6de0fd1d2011-11-15 13:31:4981static base::LazyInstance<SlowConstructor> lazy_slow =
82 LAZY_INSTANCE_INITIALIZER;
[email protected]30039e62008-09-08 14:11:1383
84TEST(LazyInstanceTest, ConstructorThreadSafety) {
85 {
[email protected]4ea927b2009-11-19 09:11:3986 base::ShadowingAtExitManager shadow;
[email protected]30039e62008-09-08 14:11:1387
88 SlowDelegate delegate(&lazy_slow);
89 EXPECT_EQ(0, SlowConstructor::constructed);
90
91 base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
92 pool.AddWork(&delegate, 20);
93 EXPECT_EQ(0, SlowConstructor::constructed);
94
95 pool.Start();
96 pool.JoinAll();
97 EXPECT_EQ(1, SlowConstructor::constructed);
98 }
99}
[email protected]dcc69332010-10-21 20:41:47100
101namespace {
102
103// DeleteLogger is an object which sets a flag when it's destroyed.
104// It accepts a bool* and sets the bool to true when the dtor runs.
105class DeleteLogger {
106 public:
107 DeleteLogger() : deleted_(NULL) {}
108 ~DeleteLogger() { *deleted_ = true; }
109
110 void SetDeletedPtr(bool* deleted) {
111 deleted_ = deleted;
112 }
113
114 private:
115 bool* deleted_;
116};
117
118} // anonymous namespace
119
120TEST(LazyInstanceTest, LeakyLazyInstance) {
121 // Check that using a plain LazyInstance causes the dtor to run
122 // when the AtExitManager finishes.
123 bool deleted1 = false;
124 {
125 base::ShadowingAtExitManager shadow;
[email protected]6de0fd1d2011-11-15 13:31:49126 static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER;
[email protected]dcc69332010-10-21 20:41:47127 test.Get().SetDeletedPtr(&deleted1);
128 }
129 EXPECT_TRUE(deleted1);
130
131 // Check that using a *leaky* LazyInstance makes the dtor not run
132 // when the AtExitManager finishes.
133 bool deleted2 = false;
134 {
135 base::ShadowingAtExitManager shadow;
[email protected]9fc44162012-01-23 22:56:41136 static base::LazyInstance<DeleteLogger>::Leaky
[email protected]6de0fd1d2011-11-15 13:31:49137 test = LAZY_INSTANCE_INITIALIZER;
[email protected]dcc69332010-10-21 20:41:47138 test.Get().SetDeletedPtr(&deleted2);
139 }
140 EXPECT_FALSE(deleted2);
141}