diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-01 04:48:49 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-01 04:48:49 +0000 |
commit | c91775096768e4a75b23a910ddc1e33d9412a3be (patch) | |
tree | cb807f9b28d88b4950e41d32fbe73a5c81a94c40 /base/threading | |
parent | e0eb450f398ae888aa0fbdb7fd3abc072d5846a2 (diff) | |
download | chromium_src-c91775096768e4a75b23a910ddc1e33d9412a3be.zip chromium_src-c91775096768e4a75b23a910ddc1e33d9412a3be.tar.gz chromium_src-c91775096768e4a75b23a910ddc1e33d9412a3be.tar.bz2 |
Move non_thread_safe from base to base/threading and into the base namespace.
TEST=it compiles
BUG=none
Review URL: http://codereview.chromium.org/6005010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70351 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/threading')
-rw-r--r-- | base/threading/non_thread_safe.cc | 28 | ||||
-rw-r--r-- | base/threading/non_thread_safe.h | 64 | ||||
-rw-r--r-- | base/threading/non_thread_safe_unittest.cc | 130 |
3 files changed, 222 insertions, 0 deletions
diff --git a/base/threading/non_thread_safe.cc b/base/threading/non_thread_safe.cc new file mode 100644 index 0000000..8b41bc0 --- /dev/null +++ b/base/threading/non_thread_safe.cc @@ -0,0 +1,28 @@ +// Copyright (c) 2010 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 "base/threading/non_thread_safe.h" + +// These checks are only done in debug builds. +#ifndef NDEBUG + +#include "base/logging.h" + +namespace base { + +NonThreadSafe::~NonThreadSafe() { + DCHECK(CalledOnValidThread()); +} + +bool NonThreadSafe::CalledOnValidThread() const { + return thread_checker_.CalledOnValidThread(); +} + +void NonThreadSafe::DetachFromThread() { + thread_checker_.DetachFromThread(); +} + +} // namespace base + +#endif // NDEBUG diff --git a/base/threading/non_thread_safe.h b/base/threading/non_thread_safe.h new file mode 100644 index 0000000..868a031 --- /dev/null +++ b/base/threading/non_thread_safe.h @@ -0,0 +1,64 @@ +// Copyright (c) 2010 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. + +#ifndef BASE_THREADING_NON_THREAD_SAFE_H_ +#define BASE_THREADING_NON_THREAD_SAFE_H_ +#pragma once + +#include "base/threading/thread_checker.h" + +namespace base { + +// A helper class used to help verify that methods of a class are +// called from the same thread. One can inherit from this class and use +// CalledOnValidThread() to verify. +// +// This is intended to be used with classes that appear to be thread safe, but +// aren't. For example, a service or a singleton like the preferences system. +// +// Example: +// class MyClass : public base::NonThreadSafe { +// public: +// void Foo() { +// DCHECK(CalledOnValidThread()); +// ... (do stuff) ... +// } +// } +// +// In Release mode, CalledOnValidThread will always return true. +// +#ifndef NDEBUG +class NonThreadSafe { + public: + ~NonThreadSafe(); + + bool CalledOnValidThread() const; + + protected: + // Changes the thread that is checked for in CalledOnValidThread. The next + // call to CalledOnValidThread will attach this class to a new thread. It is + // up to the NonThreadSafe derived class to decide to expose this or not. + // This may be useful when an object may be created on one thread and then + // used exclusively on another thread. + void DetachFromThread(); + + private: + ThreadChecker thread_checker_; +}; +#else +// Do nothing in release mode. +class NonThreadSafe { + public: + bool CalledOnValidThread() const { + return true; + } + + protected: + void DetachFromThread() {} +}; +#endif // NDEBUG + +} // namespace base + +#endif // BASE_NON_THREAD_SAFE_H_ diff --git a/base/threading/non_thread_safe_unittest.cc b/base/threading/non_thread_safe_unittest.cc new file mode 100644 index 0000000..7d158cf --- /dev/null +++ b/base/threading/non_thread_safe_unittest.cc @@ -0,0 +1,130 @@ +// Copyright (c) 2010 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 "base/basictypes.h" +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/threading/non_thread_safe.h" +#include "base/threading/simple_thread.h" +#include "testing/gtest/include/gtest/gtest.h" + +#ifndef NDEBUG + +namespace base { + +// Simple class to exersice the basics of NonThreadSafe. +// Both the destructor and DoStuff should verify that they were +// called on the same thread as the constructor. +class NonThreadSafeClass : public NonThreadSafe { + public: + NonThreadSafeClass() {} + + // Verifies that it was called on the same thread as the constructor. + void DoStuff() { + DCHECK(CalledOnValidThread()); + } + + void DetachFromThread() { + NonThreadSafe::DetachFromThread(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(NonThreadSafeClass); +}; + +// Calls NonThreadSafeClass::DoStuff on another thread. +class CallDoStuffOnThread : public SimpleThread { + public: + CallDoStuffOnThread(NonThreadSafeClass* non_thread_safe_class) + : SimpleThread("call_do_stuff_on_thread"), + non_thread_safe_class_(non_thread_safe_class) { + } + + virtual void Run() { + non_thread_safe_class_->DoStuff(); + } + + private: + NonThreadSafeClass* non_thread_safe_class_; + + DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread); +}; + +// Deletes NonThreadSafeClass on a different thread. +class DeleteNonThreadSafeClassOnThread : public SimpleThread { + public: + DeleteNonThreadSafeClassOnThread(NonThreadSafeClass* non_thread_safe_class) + : SimpleThread("delete_non_thread_safe_class_on_thread"), + non_thread_safe_class_(non_thread_safe_class) { + } + + virtual void Run() { + non_thread_safe_class_.reset(); + } + + private: + scoped_ptr<NonThreadSafeClass> non_thread_safe_class_; + + DISALLOW_COPY_AND_ASSIGN(DeleteNonThreadSafeClassOnThread); +}; + +TEST(NonThreadSafeTest, CallsAllowedOnSameThread) { + scoped_ptr<NonThreadSafeClass> non_thread_safe_class( + new NonThreadSafeClass); + + // Verify that DoStuff doesn't assert. + non_thread_safe_class->DoStuff(); + + // Verify that the destructor doesn't assert. + non_thread_safe_class.reset(); +} + +TEST(NonThreadSafeTest, DetachThenDestructOnDifferentThread) { + scoped_ptr<NonThreadSafeClass> non_thread_safe_class( + new NonThreadSafeClass); + + // Verify that the destructor doesn't assert when called on a different thread + // after a detach. + non_thread_safe_class->DetachFromThread(); + DeleteNonThreadSafeClassOnThread delete_on_thread( + non_thread_safe_class.release()); + + delete_on_thread.Start(); + delete_on_thread.Join(); +} + +#if GTEST_HAS_DEATH_TEST + +TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThread) { + ASSERT_DEBUG_DEATH({ + scoped_ptr<NonThreadSafeClass> non_thread_safe_class( + new NonThreadSafeClass); + + // Verify that DoStuff asserts when called on a different thread. + CallDoStuffOnThread call_on_thread(non_thread_safe_class.get()); + + call_on_thread.Start(); + call_on_thread.Join(); + }, ""); +} + +TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThread) { + ASSERT_DEBUG_DEATH({ + scoped_ptr<NonThreadSafeClass> non_thread_safe_class( + new NonThreadSafeClass); + + // Verify that the destructor asserts when called on a different thread. + DeleteNonThreadSafeClassOnThread delete_on_thread( + non_thread_safe_class.release()); + + delete_on_thread.Start(); + delete_on_thread.Join(); + }, ""); +} + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace base + +#endif // NDEBUG |