123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- // 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 "butil/basictypes.h"
- #include "butil/logging.h"
- #include "butil/memory/scoped_ptr.h"
- #include "butil/threading/thread_checker.h"
- #include "butil/threading/simple_thread.h"
- #include <gtest/gtest.h>
- // Duplicated from butil/threading/thread_checker.h so that we can be
- // good citizens there and undef the macro.
- #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
- #define ENABLE_THREAD_CHECKER 1
- #else
- #define ENABLE_THREAD_CHECKER 0
- #endif
- namespace butil {
- namespace {
- // Simple class to exercise the basics of ThreadChecker.
- // Both the destructor and DoStuff should verify that they were
- // called on the same thread as the constructor.
- class ThreadCheckerClass : public ThreadChecker {
- public:
- ThreadCheckerClass() {}
- // Verifies that it was called on the same thread as the constructor.
- void DoStuff() {
- DCHECK(CalledOnValidThread());
- }
- void DetachFromThread() {
- ThreadChecker::DetachFromThread();
- }
- static void MethodOnDifferentThreadImpl();
- static void DetachThenCallFromDifferentThreadImpl();
- private:
- DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
- };
- // Calls ThreadCheckerClass::DoStuff on another thread.
- class CallDoStuffOnThread : public butil::SimpleThread {
- public:
- explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
- : SimpleThread("call_do_stuff_on_thread"),
- thread_checker_class_(thread_checker_class) {
- }
- virtual void Run() OVERRIDE {
- thread_checker_class_->DoStuff();
- }
- private:
- ThreadCheckerClass* thread_checker_class_;
- DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
- };
- // Deletes ThreadCheckerClass on a different thread.
- class DeleteThreadCheckerClassOnThread : public butil::SimpleThread {
- public:
- explicit DeleteThreadCheckerClassOnThread(
- ThreadCheckerClass* thread_checker_class)
- : SimpleThread("delete_thread_checker_class_on_thread"),
- thread_checker_class_(thread_checker_class) {
- }
- virtual void Run() OVERRIDE {
- thread_checker_class_.reset();
- }
- private:
- scoped_ptr<ThreadCheckerClass> thread_checker_class_;
- DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
- };
- } // namespace
- TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
- scoped_ptr<ThreadCheckerClass> thread_checker_class(
- new ThreadCheckerClass);
- // Verify that DoStuff doesn't assert.
- thread_checker_class->DoStuff();
- // Verify that the destructor doesn't assert.
- thread_checker_class.reset();
- }
- TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
- scoped_ptr<ThreadCheckerClass> thread_checker_class(
- new ThreadCheckerClass);
- // Verify that the destructor doesn't assert
- // when called on a different thread.
- DeleteThreadCheckerClassOnThread delete_on_thread(
- thread_checker_class.release());
- delete_on_thread.Start();
- delete_on_thread.Join();
- }
- TEST(ThreadCheckerTest, DetachFromThread) {
- scoped_ptr<ThreadCheckerClass> thread_checker_class(
- new ThreadCheckerClass);
- // Verify that DoStuff doesn't assert when called on a different thread after
- // a call to DetachFromThread.
- thread_checker_class->DetachFromThread();
- CallDoStuffOnThread call_on_thread(thread_checker_class.get());
- call_on_thread.Start();
- call_on_thread.Join();
- }
- #if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
- void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
- scoped_ptr<ThreadCheckerClass> thread_checker_class(
- new ThreadCheckerClass);
- // DoStuff should assert in debug builds only when called on a
- // different thread.
- CallDoStuffOnThread call_on_thread(thread_checker_class.get());
- call_on_thread.Start();
- call_on_thread.Join();
- }
- #if ENABLE_THREAD_CHECKER
- TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
- ASSERT_DEATH({
- ThreadCheckerClass::MethodOnDifferentThreadImpl();
- }, "");
- }
- #else
- TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
- ThreadCheckerClass::MethodOnDifferentThreadImpl();
- }
- #endif // ENABLE_THREAD_CHECKER
- void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
- scoped_ptr<ThreadCheckerClass> thread_checker_class(
- new ThreadCheckerClass);
- // DoStuff doesn't assert when called on a different thread
- // after a call to DetachFromThread.
- thread_checker_class->DetachFromThread();
- CallDoStuffOnThread call_on_thread(thread_checker_class.get());
- call_on_thread.Start();
- call_on_thread.Join();
- // DoStuff should assert in debug builds only after moving to
- // another thread.
- thread_checker_class->DoStuff();
- }
- #if ENABLE_THREAD_CHECKER
- TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
- ASSERT_DEATH({
- ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
- }, "");
- }
- #else
- TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
- ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
- }
- #endif // ENABLE_THREAD_CHECKER
- #endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
- // Just in case we ever get lumped together with other compilation units.
- #undef ENABLE_THREAD_CHECKER
- } // namespace butil
|