1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be 3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file. 4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 5cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include <stddef.h> 6cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko 7b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/at_exit.h" 8b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/atomic_sequence_num.h" 9b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/lazy_instance.h" 10b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/memory/aligned_memory.h" 11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/threading/simple_thread.h" 12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "testing/gtest/include/gtest/gtest.h" 13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace { 15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbase::StaticAtomicSequenceNumber constructed_seq_; 17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbase::StaticAtomicSequenceNumber destructed_seq_; 18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass ConstructAndDestructLogger { 20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public: 21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ConstructAndDestructLogger() { 22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat constructed_seq_.GetNext(); 23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ~ConstructAndDestructLogger() { 25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat destructed_seq_.GetNext(); 26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}; 28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass SlowConstructor { 30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public: 31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat SlowConstructor() : some_int_(0) { 32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Sleep for 1 second to try to cause a race. 33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); 34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ++constructed; 35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat some_int_ = 12; 36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int some_int() const { return some_int_; } 38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 39b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat static int constructed; 40b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private: 41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int some_int_; 42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}; 43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 44b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratint SlowConstructor::constructed = 0; 45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass SlowDelegate : public base::DelegateSimpleThread::Delegate { 47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public: 48b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy) 49b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat : lazy_(lazy) {} 50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void Run() override { 52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(12, lazy_->Get().some_int()); 53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(12, lazy_->Pointer()->some_int()); 54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 55b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 56b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private: 57b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::LazyInstance<SlowConstructor>* lazy_; 58b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}; 59b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 60b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace 61b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratstatic base::LazyInstance<ConstructAndDestructLogger> lazy_logger = 63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat LAZY_INSTANCE_INITIALIZER; 64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 65b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTEST(LazyInstanceTest, Basic) { 66b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat { 67b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::ShadowingAtExitManager shadow; 68b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 69b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(0, constructed_seq_.GetNext()); 70b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(0, destructed_seq_.GetNext()); 71b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 72b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat lazy_logger.Get(); 73b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(2, constructed_seq_.GetNext()); 74b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(1, destructed_seq_.GetNext()); 75b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 76b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat lazy_logger.Pointer(); 77b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(3, constructed_seq_.GetNext()); 78b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(2, destructed_seq_.GetNext()); 79b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 80b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(4, constructed_seq_.GetNext()); 81b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(4, destructed_seq_.GetNext()); 82b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 83b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 84b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratstatic base::LazyInstance<SlowConstructor> lazy_slow = 85b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat LAZY_INSTANCE_INITIALIZER; 86b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 87b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTEST(LazyInstanceTest, ConstructorThreadSafety) { 88b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat { 89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::ShadowingAtExitManager shadow; 90b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat SlowDelegate delegate(&lazy_slow); 92b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(0, SlowConstructor::constructed); 93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5); 95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pool.AddWork(&delegate, 20); 96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(0, SlowConstructor::constructed); 97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 98b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pool.Start(); 99b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pool.JoinAll(); 100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(1, SlowConstructor::constructed); 101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 102b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 103b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace { 105b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// DeleteLogger is an object which sets a flag when it's destroyed. 107b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// It accepts a bool* and sets the bool to true when the dtor runs. 108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass DeleteLogger { 109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public: 110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DeleteLogger() : deleted_(NULL) {} 111b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ~DeleteLogger() { *deleted_ = true; } 112b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 113b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void SetDeletedPtr(bool* deleted) { 114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat deleted_ = deleted; 115b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 117b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private: 118b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat bool* deleted_; 119b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}; 120b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 121b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // anonymous namespace 122b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 123b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTEST(LazyInstanceTest, LeakyLazyInstance) { 124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Check that using a plain LazyInstance causes the dtor to run 125b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // when the AtExitManager finishes. 126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat bool deleted1 = false; 127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat { 128b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::ShadowingAtExitManager shadow; 129b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER; 130b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat test.Get().SetDeletedPtr(&deleted1); 131b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 132b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_TRUE(deleted1); 133b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 134b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Check that using a *leaky* LazyInstance makes the dtor not run 135b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // when the AtExitManager finishes. 136b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat bool deleted2 = false; 137b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat { 138b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::ShadowingAtExitManager shadow; 139b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat static base::LazyInstance<DeleteLogger>::Leaky 140b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat test = LAZY_INSTANCE_INITIALIZER; 141b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat test.Get().SetDeletedPtr(&deleted2); 142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 143b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_FALSE(deleted2); 144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 145b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 146b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace { 147b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erattemplate <size_t alignment> 149b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass AlignedData { 150b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public: 151b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AlignedData() {} 152b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ~AlignedData() {} 153b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::AlignedMemory<alignment, alignment> data_; 154b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}; 155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 156b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // anonymous namespace 157b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 158b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#define EXPECT_ALIGNED(ptr, align) \ 159b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1)) 160b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 161b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTEST(LazyInstanceTest, Alignment) { 162b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat using base::LazyInstance; 163b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 164b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Create some static instances with increasing sizes and alignment 165b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // requirements. By ordering this way, the linker will need to do some work to 166b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // ensure proper alignment of the static data. 167b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat static LazyInstance<AlignedData<4> > align4 = LAZY_INSTANCE_INITIALIZER; 168b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat static LazyInstance<AlignedData<32> > align32 = LAZY_INSTANCE_INITIALIZER; 169b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat static LazyInstance<AlignedData<4096> > align4096 = LAZY_INSTANCE_INITIALIZER; 170b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 171b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_ALIGNED(align4.Pointer(), 4); 172b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_ALIGNED(align32.Pointer(), 32); 173b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_ALIGNED(align4096.Pointer(), 4096); 174b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 175