thread_checker_unittest.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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/basictypes.h"
  5. #include "butil/logging.h"
  6. #include "butil/memory/scoped_ptr.h"
  7. #include "butil/threading/thread_checker.h"
  8. #include "butil/threading/simple_thread.h"
  9. #include <gtest/gtest.h>
  10. // Duplicated from butil/threading/thread_checker.h so that we can be
  11. // good citizens there and undef the macro.
  12. #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
  13. #define ENABLE_THREAD_CHECKER 1
  14. #else
  15. #define ENABLE_THREAD_CHECKER 0
  16. #endif
  17. namespace butil {
  18. namespace {
  19. // Simple class to exercise the basics of ThreadChecker.
  20. // Both the destructor and DoStuff should verify that they were
  21. // called on the same thread as the constructor.
  22. class ThreadCheckerClass : public ThreadChecker {
  23. public:
  24. ThreadCheckerClass() {}
  25. // Verifies that it was called on the same thread as the constructor.
  26. void DoStuff() {
  27. DCHECK(CalledOnValidThread());
  28. }
  29. void DetachFromThread() {
  30. ThreadChecker::DetachFromThread();
  31. }
  32. static void MethodOnDifferentThreadImpl();
  33. static void DetachThenCallFromDifferentThreadImpl();
  34. private:
  35. DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
  36. };
  37. // Calls ThreadCheckerClass::DoStuff on another thread.
  38. class CallDoStuffOnThread : public butil::SimpleThread {
  39. public:
  40. explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
  41. : SimpleThread("call_do_stuff_on_thread"),
  42. thread_checker_class_(thread_checker_class) {
  43. }
  44. virtual void Run() OVERRIDE {
  45. thread_checker_class_->DoStuff();
  46. }
  47. private:
  48. ThreadCheckerClass* thread_checker_class_;
  49. DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
  50. };
  51. // Deletes ThreadCheckerClass on a different thread.
  52. class DeleteThreadCheckerClassOnThread : public butil::SimpleThread {
  53. public:
  54. explicit DeleteThreadCheckerClassOnThread(
  55. ThreadCheckerClass* thread_checker_class)
  56. : SimpleThread("delete_thread_checker_class_on_thread"),
  57. thread_checker_class_(thread_checker_class) {
  58. }
  59. virtual void Run() OVERRIDE {
  60. thread_checker_class_.reset();
  61. }
  62. private:
  63. scoped_ptr<ThreadCheckerClass> thread_checker_class_;
  64. DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
  65. };
  66. } // namespace
  67. TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
  68. scoped_ptr<ThreadCheckerClass> thread_checker_class(
  69. new ThreadCheckerClass);
  70. // Verify that DoStuff doesn't assert.
  71. thread_checker_class->DoStuff();
  72. // Verify that the destructor doesn't assert.
  73. thread_checker_class.reset();
  74. }
  75. TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
  76. scoped_ptr<ThreadCheckerClass> thread_checker_class(
  77. new ThreadCheckerClass);
  78. // Verify that the destructor doesn't assert
  79. // when called on a different thread.
  80. DeleteThreadCheckerClassOnThread delete_on_thread(
  81. thread_checker_class.release());
  82. delete_on_thread.Start();
  83. delete_on_thread.Join();
  84. }
  85. TEST(ThreadCheckerTest, DetachFromThread) {
  86. scoped_ptr<ThreadCheckerClass> thread_checker_class(
  87. new ThreadCheckerClass);
  88. // Verify that DoStuff doesn't assert when called on a different thread after
  89. // a call to DetachFromThread.
  90. thread_checker_class->DetachFromThread();
  91. CallDoStuffOnThread call_on_thread(thread_checker_class.get());
  92. call_on_thread.Start();
  93. call_on_thread.Join();
  94. }
  95. #if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
  96. void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
  97. scoped_ptr<ThreadCheckerClass> thread_checker_class(
  98. new ThreadCheckerClass);
  99. // DoStuff should assert in debug builds only when called on a
  100. // different thread.
  101. CallDoStuffOnThread call_on_thread(thread_checker_class.get());
  102. call_on_thread.Start();
  103. call_on_thread.Join();
  104. }
  105. #if ENABLE_THREAD_CHECKER
  106. TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
  107. ASSERT_DEATH({
  108. ThreadCheckerClass::MethodOnDifferentThreadImpl();
  109. }, "");
  110. }
  111. #else
  112. TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
  113. ThreadCheckerClass::MethodOnDifferentThreadImpl();
  114. }
  115. #endif // ENABLE_THREAD_CHECKER
  116. void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
  117. scoped_ptr<ThreadCheckerClass> thread_checker_class(
  118. new ThreadCheckerClass);
  119. // DoStuff doesn't assert when called on a different thread
  120. // after a call to DetachFromThread.
  121. thread_checker_class->DetachFromThread();
  122. CallDoStuffOnThread call_on_thread(thread_checker_class.get());
  123. call_on_thread.Start();
  124. call_on_thread.Join();
  125. // DoStuff should assert in debug builds only after moving to
  126. // another thread.
  127. thread_checker_class->DoStuff();
  128. }
  129. #if ENABLE_THREAD_CHECKER
  130. TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
  131. ASSERT_DEATH({
  132. ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
  133. }, "");
  134. }
  135. #else
  136. TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
  137. ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
  138. }
  139. #endif // ENABLE_THREAD_CHECKER
  140. #endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
  141. // Just in case we ever get lumped together with other compilation units.
  142. #undef ENABLE_THREAD_CHECKER
  143. } // namespace butil