diff options
author | Daniel Erat <derat@google.com> | 2015-07-06 13:18:13 -0600 |
---|---|---|
committer | Daniel Erat <derat@google.com> | 2015-07-07 08:49:02 -0600 |
commit | b8cf94937c52feb53b55c39e3f82094d27de464c (patch) | |
tree | 20cd8f9867dfe9c0c2510899346c744605425b75 /base/lazy_instance_unittest.cc | |
parent | 5bb0a2e04cf1346d5a2819f277381c0415549600 (diff) | |
download | libchrome-b8cf94937c52feb53b55c39e3f82094d27de464c.tar.gz |
Add upstream code as of Chromium r334380.
Copy the unchanged source from
https://chromium.googlesource.com/chromium/src/base/ as of
r334380 (really r334285 a.k.a. 23911a0c in the base/
subtree).
Also add MODULE_LICENSE_BSD and copy Chromium's current
LICENSE file to NOTICE.
Bug: 22317122
Change-Id: I89863bfeca67b3a1ff05e6078f2f9ee4e31c5c99
Diffstat (limited to 'base/lazy_instance_unittest.cc')
-rw-r--r-- | base/lazy_instance_unittest.cc | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/base/lazy_instance_unittest.cc b/base/lazy_instance_unittest.cc new file mode 100644 index 0000000000..ec9ef26732 --- /dev/null +++ b/base/lazy_instance_unittest.cc @@ -0,0 +1,172 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/at_exit.h" +#include "base/atomic_sequence_num.h" +#include "base/lazy_instance.h" +#include "base/memory/aligned_memory.h" +#include "base/threading/simple_thread.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +base::StaticAtomicSequenceNumber constructed_seq_; +base::StaticAtomicSequenceNumber destructed_seq_; + +class ConstructAndDestructLogger { + public: + ConstructAndDestructLogger() { + constructed_seq_.GetNext(); + } + ~ConstructAndDestructLogger() { + destructed_seq_.GetNext(); + } +}; + +class SlowConstructor { + public: + SlowConstructor() : some_int_(0) { + // Sleep for 1 second to try to cause a race. + base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); + ++constructed; + some_int_ = 12; + } + int some_int() const { return some_int_; } + + static int constructed; + private: + int some_int_; +}; + +int SlowConstructor::constructed = 0; + +class SlowDelegate : public base::DelegateSimpleThread::Delegate { + public: + explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy) + : lazy_(lazy) {} + + void Run() override { + EXPECT_EQ(12, lazy_->Get().some_int()); + EXPECT_EQ(12, lazy_->Pointer()->some_int()); + } + + private: + base::LazyInstance<SlowConstructor>* lazy_; +}; + +} // namespace + +static base::LazyInstance<ConstructAndDestructLogger> lazy_logger = + LAZY_INSTANCE_INITIALIZER; + +TEST(LazyInstanceTest, Basic) { + { + base::ShadowingAtExitManager shadow; + + EXPECT_EQ(0, constructed_seq_.GetNext()); + EXPECT_EQ(0, destructed_seq_.GetNext()); + + lazy_logger.Get(); + EXPECT_EQ(2, constructed_seq_.GetNext()); + EXPECT_EQ(1, destructed_seq_.GetNext()); + + lazy_logger.Pointer(); + EXPECT_EQ(3, constructed_seq_.GetNext()); + EXPECT_EQ(2, destructed_seq_.GetNext()); + } + EXPECT_EQ(4, constructed_seq_.GetNext()); + EXPECT_EQ(4, destructed_seq_.GetNext()); +} + +static base::LazyInstance<SlowConstructor> lazy_slow = + LAZY_INSTANCE_INITIALIZER; + +TEST(LazyInstanceTest, ConstructorThreadSafety) { + { + base::ShadowingAtExitManager shadow; + + SlowDelegate delegate(&lazy_slow); + EXPECT_EQ(0, SlowConstructor::constructed); + + base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5); + pool.AddWork(&delegate, 20); + EXPECT_EQ(0, SlowConstructor::constructed); + + pool.Start(); + pool.JoinAll(); + EXPECT_EQ(1, SlowConstructor::constructed); + } +} + +namespace { + +// DeleteLogger is an object which sets a flag when it's destroyed. +// It accepts a bool* and sets the bool to true when the dtor runs. +class DeleteLogger { + public: + DeleteLogger() : deleted_(NULL) {} + ~DeleteLogger() { *deleted_ = true; } + + void SetDeletedPtr(bool* deleted) { + deleted_ = deleted; + } + + private: + bool* deleted_; +}; + +} // anonymous namespace + +TEST(LazyInstanceTest, LeakyLazyInstance) { + // Check that using a plain LazyInstance causes the dtor to run + // when the AtExitManager finishes. + bool deleted1 = false; + { + base::ShadowingAtExitManager shadow; + static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER; + test.Get().SetDeletedPtr(&deleted1); + } + EXPECT_TRUE(deleted1); + + // Check that using a *leaky* LazyInstance makes the dtor not run + // when the AtExitManager finishes. + bool deleted2 = false; + { + base::ShadowingAtExitManager shadow; + static base::LazyInstance<DeleteLogger>::Leaky + test = LAZY_INSTANCE_INITIALIZER; + test.Get().SetDeletedPtr(&deleted2); + } + EXPECT_FALSE(deleted2); +} + +namespace { + +template <size_t alignment> +class AlignedData { + public: + AlignedData() {} + ~AlignedData() {} + base::AlignedMemory<alignment, alignment> data_; +}; + +} // anonymous namespace + +#define EXPECT_ALIGNED(ptr, align) \ + EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1)) + +TEST(LazyInstanceTest, Alignment) { + using base::LazyInstance; + + // Create some static instances with increasing sizes and alignment + // requirements. By ordering this way, the linker will need to do some work to + // ensure proper alignment of the static data. + static LazyInstance<AlignedData<4> > align4 = LAZY_INSTANCE_INITIALIZER; + static LazyInstance<AlignedData<32> > align32 = LAZY_INSTANCE_INITIALIZER; + static LazyInstance<AlignedData<4096> > align4096 = LAZY_INSTANCE_INITIALIZER; + + EXPECT_ALIGNED(align4.Pointer(), 4); + EXPECT_ALIGNED(align32.Pointer(), 32); + EXPECT_ALIGNED(align4096.Pointer(), 4096); +} |