lazy_instance_unittest.cc 4.5 KB

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