15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/at_exit.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/atomic_sequence_num.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/aligned_memory.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/simple_thread.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::StaticAtomicSequenceNumber constructed_seq_;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::StaticAtomicSequenceNumber destructed_seq_;
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ConstructAndDestructLogger {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConstructAndDestructLogger() {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    constructed_seq_.GetNext();
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~ConstructAndDestructLogger() {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    destructed_seq_.GetNext();
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SlowConstructor {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SlowConstructor() : some_int_(0) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sleep for 1 second to try to cause a race.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++constructed;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    some_int_ = 12;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int some_int() const { return some_int_; }
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int constructed;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int some_int_;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SlowConstructor::constructed = 0;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SlowDelegate : public base::DelegateSimpleThread::Delegate {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : lazy_(lazy) {}
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Run() OVERRIDE {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(12, lazy_->Get().some_int());
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(12, lazy_->Pointer()->some_int());
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::LazyInstance<SlowConstructor>* lazy_;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<ConstructAndDestructLogger> lazy_logger =
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(LazyInstanceTest, Basic) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ShadowingAtExitManager shadow;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(0, constructed_seq_.GetNext());
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(0, destructed_seq_.GetNext());
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    lazy_logger.Get();
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(2, constructed_seq_.GetNext());
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(1, destructed_seq_.GetNext());
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    lazy_logger.Pointer();
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(3, constructed_seq_.GetNext());
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(2, destructed_seq_.GetNext());
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(4, constructed_seq_.GetNext());
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(4, destructed_seq_.GetNext());
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<SlowConstructor> lazy_slow =
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(LazyInstanceTest, ConstructorThreadSafety) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ShadowingAtExitManager shadow;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SlowDelegate delegate(&lazy_slow);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(0, SlowConstructor::constructed);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pool.AddWork(&delegate, 20);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(0, SlowConstructor::constructed);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pool.Start();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pool.JoinAll();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(1, SlowConstructor::constructed);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DeleteLogger is an object which sets a flag when it's destroyed.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It accepts a bool* and sets the bool to true when the dtor runs.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DeleteLogger {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteLogger() : deleted_(NULL) {}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~DeleteLogger() { *deleted_ = true; }
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetDeletedPtr(bool* deleted) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    deleted_ = deleted;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool* deleted_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // anonymous namespace
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(LazyInstanceTest, LeakyLazyInstance) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that using a plain LazyInstance causes the dtor to run
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when the AtExitManager finishes.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool deleted1 = false;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ShadowingAtExitManager shadow;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    test.Get().SetDeletedPtr(&deleted1);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(deleted1);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that using a *leaky* LazyInstance makes the dtor not run
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when the AtExitManager finishes.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool deleted2 = false;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ShadowingAtExitManager shadow;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static base::LazyInstance<DeleteLogger>::Leaky
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        test = LAZY_INSTANCE_INITIALIZER;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    test.Get().SetDeletedPtr(&deleted2);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(deleted2);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <size_t alignment>
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class AlignedData {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AlignedData() {}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~AlignedData() {}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AlignedMemory<alignment, alignment> data_;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // anonymous namespace
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define EXPECT_ALIGNED(ptr, align) \
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(LazyInstanceTest, Alignment) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  using base::LazyInstance;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create some static instances with increasing sizes and alignment
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // requirements. By ordering this way, the linker will need to do some work to
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ensure proper alignment of the static data.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static LazyInstance<AlignedData<4> > align4 = LAZY_INSTANCE_INITIALIZER;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static LazyInstance<AlignedData<32> > align32 = LAZY_INSTANCE_INITIALIZER;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static LazyInstance<AlignedData<4096> > align4096 = LAZY_INSTANCE_INITIALIZER;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_ALIGNED(align4.Pointer(), 4);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_ALIGNED(align32.Pointer(), 32);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_ALIGNED(align4096.Pointer(), 4096);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
173