michael@0: // Copyright (c) 2012 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #ifndef BASE_THREADING_THREAD_RESTRICTIONS_H_ michael@0: #define BASE_THREADING_THREAD_RESTRICTIONS_H_ michael@0: michael@0: #include "base/base_export.h" michael@0: #include "base/basictypes.h" michael@0: michael@0: // See comment at top of thread_checker.h michael@0: #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) michael@0: #define ENABLE_THREAD_RESTRICTIONS 1 michael@0: #else michael@0: #define ENABLE_THREAD_RESTRICTIONS 0 michael@0: #endif michael@0: michael@0: class AcceleratedPresenter; michael@0: class BrowserProcessImpl; michael@0: class HistogramSynchronizer; michael@0: class MetricsService; michael@0: class NativeBackendKWallet; michael@0: class ScopedAllowWaitForLegacyWebViewApi; michael@0: class TestingAutomationProvider; michael@0: michael@0: namespace browser_sync { michael@0: class NonFrontendDataTypeController; michael@0: class UIModelWorker; michael@0: } michael@0: namespace cc { michael@0: class CompletionEvent; michael@0: } michael@0: namespace chromeos { michael@0: class AudioMixerAlsa; michael@0: class BlockingMethodCaller; michael@0: namespace system { michael@0: class StatisticsProviderImpl; michael@0: } michael@0: } michael@0: namespace chrome_browser_net { michael@0: class Predictor; michael@0: } michael@0: namespace content { michael@0: class BrowserGpuChannelHostFactory; michael@0: class BrowserShutdownProfileDumper; michael@0: class BrowserTestBase; michael@0: class GLHelper; michael@0: class GpuChannelHost; michael@0: class NestedMessagePumpAndroid; michael@0: class RenderWidgetHelper; michael@0: class ScopedAllowWaitForAndroidLayoutTests; michael@0: class TextInputClientMac; michael@0: } michael@0: namespace dbus { michael@0: class Bus; michael@0: } michael@0: namespace disk_cache { michael@0: class BackendImpl; michael@0: class InFlightIO; michael@0: } michael@0: namespace media { michael@0: class AudioOutputController; michael@0: } michael@0: namespace net { michael@0: class FileStreamPosix; michael@0: class FileStreamWin; michael@0: namespace internal { michael@0: class AddressTrackerLinux; michael@0: } michael@0: } michael@0: michael@0: namespace remoting { michael@0: class AutoThread; michael@0: } michael@0: michael@0: namespace base { michael@0: michael@0: namespace android { michael@0: class JavaHandlerThread; michael@0: } michael@0: michael@0: class SequencedWorkerPool; michael@0: class SimpleThread; michael@0: class Thread; michael@0: class ThreadTestHelper; michael@0: michael@0: // Certain behavior is disallowed on certain threads. ThreadRestrictions helps michael@0: // enforce these rules. Examples of such rules: michael@0: // michael@0: // * Do not do blocking IO (makes the thread janky) michael@0: // * Do not access Singleton/LazyInstance (may lead to shutdown crashes) michael@0: // michael@0: // Here's more about how the protection works: michael@0: // michael@0: // 1) If a thread should not be allowed to make IO calls, mark it: michael@0: // base::ThreadRestrictions::SetIOAllowed(false); michael@0: // By default, threads *are* allowed to make IO calls. michael@0: // In Chrome browser code, IO calls should be proxied to the File thread. michael@0: // michael@0: // 2) If a function makes a call that will go out to disk, check whether the michael@0: // current thread is allowed: michael@0: // base::ThreadRestrictions::AssertIOAllowed(); michael@0: // michael@0: // michael@0: // Style tip: where should you put AssertIOAllowed checks? It's best michael@0: // if you put them as close to the disk access as possible, at the michael@0: // lowest level. This rule is simple to follow and helps catch all michael@0: // callers. For example, if your function GoDoSomeBlockingDiskCall() michael@0: // only calls other functions in Chrome and not fopen(), you should go michael@0: // add the AssertIOAllowed checks in the helper functions. michael@0: michael@0: class BASE_EXPORT ThreadRestrictions { michael@0: public: michael@0: // Constructing a ScopedAllowIO temporarily allows IO for the current michael@0: // thread. Doing this is almost certainly always incorrect. michael@0: class BASE_EXPORT ScopedAllowIO { michael@0: public: michael@0: ScopedAllowIO() { previous_value_ = SetIOAllowed(true); } michael@0: ~ScopedAllowIO() { SetIOAllowed(previous_value_); } michael@0: private: michael@0: // Whether IO is allowed when the ScopedAllowIO was constructed. michael@0: bool previous_value_; michael@0: michael@0: DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO); michael@0: }; michael@0: michael@0: // Constructing a ScopedAllowSingleton temporarily allows accessing for the michael@0: // current thread. Doing this is almost always incorrect. michael@0: class BASE_EXPORT ScopedAllowSingleton { michael@0: public: michael@0: ScopedAllowSingleton() { previous_value_ = SetSingletonAllowed(true); } michael@0: ~ScopedAllowSingleton() { SetSingletonAllowed(previous_value_); } michael@0: private: michael@0: // Whether singleton use is allowed when the ScopedAllowSingleton was michael@0: // constructed. michael@0: bool previous_value_; michael@0: michael@0: DISALLOW_COPY_AND_ASSIGN(ScopedAllowSingleton); michael@0: }; michael@0: michael@0: #if ENABLE_THREAD_RESTRICTIONS michael@0: // Set whether the current thread to make IO calls. michael@0: // Threads start out in the *allowed* state. michael@0: // Returns the previous value. michael@0: static bool SetIOAllowed(bool allowed); michael@0: michael@0: // Check whether the current thread is allowed to make IO calls, michael@0: // and DCHECK if not. See the block comment above the class for michael@0: // a discussion of where to add these checks. michael@0: static void AssertIOAllowed(); michael@0: michael@0: // Set whether the current thread can use singletons. Returns the previous michael@0: // value. michael@0: static bool SetSingletonAllowed(bool allowed); michael@0: michael@0: // Check whether the current thread is allowed to use singletons (Singleton / michael@0: // LazyInstance). DCHECKs if not. michael@0: static void AssertSingletonAllowed(); michael@0: michael@0: // Disable waiting on the current thread. Threads start out in the *allowed* michael@0: // state. Returns the previous value. michael@0: static void DisallowWaiting(); michael@0: michael@0: // Check whether the current thread is allowed to wait, and DCHECK if not. michael@0: static void AssertWaitAllowed(); michael@0: #else michael@0: // Inline the empty definitions of these functions so that they can be michael@0: // compiled out. michael@0: static bool SetIOAllowed(bool allowed) { return true; } michael@0: static void AssertIOAllowed() {} michael@0: static bool SetSingletonAllowed(bool allowed) { return true; } michael@0: static void AssertSingletonAllowed() {} michael@0: static void DisallowWaiting() {} michael@0: static void AssertWaitAllowed() {} michael@0: #endif michael@0: michael@0: private: michael@0: // DO NOT ADD ANY OTHER FRIEND STATEMENTS, talk to jam or brettw first. michael@0: // BEGIN ALLOWED USAGE. michael@0: friend class content::BrowserShutdownProfileDumper; michael@0: friend class content::BrowserTestBase; michael@0: friend class content::NestedMessagePumpAndroid; michael@0: friend class content::RenderWidgetHelper; michael@0: friend class content::ScopedAllowWaitForAndroidLayoutTests; michael@0: friend class ::HistogramSynchronizer; michael@0: friend class ::ScopedAllowWaitForLegacyWebViewApi; michael@0: friend class ::TestingAutomationProvider; michael@0: friend class cc::CompletionEvent; michael@0: friend class remoting::AutoThread; michael@0: friend class MessagePumpDefault; michael@0: friend class SequencedWorkerPool; michael@0: friend class SimpleThread; michael@0: friend class Thread; michael@0: friend class ThreadTestHelper; michael@0: friend class PlatformThread; michael@0: friend class android::JavaHandlerThread; michael@0: michael@0: // END ALLOWED USAGE. michael@0: // BEGIN USAGE THAT NEEDS TO BE FIXED. michael@0: friend class ::chromeos::AudioMixerAlsa; // http://crbug.com/125206 michael@0: friend class ::chromeos::BlockingMethodCaller; // http://crbug.com/125360 michael@0: friend class ::chromeos::system::StatisticsProviderImpl; // http://crbug.com/125385 michael@0: friend class browser_sync::NonFrontendDataTypeController; // http://crbug.com/19757 michael@0: friend class browser_sync::UIModelWorker; // http://crbug.com/19757 michael@0: friend class chrome_browser_net::Predictor; // http://crbug.com/78451 michael@0: friend class michael@0: content::BrowserGpuChannelHostFactory; // http://crbug.com/125248 michael@0: friend class content::GLHelper; // http://crbug.com/125415 michael@0: friend class content::GpuChannelHost; // http://crbug.com/125264 michael@0: friend class content::TextInputClientMac; // http://crbug.com/121917 michael@0: friend class dbus::Bus; // http://crbug.com/125222 michael@0: friend class disk_cache::BackendImpl; // http://crbug.com/74623 michael@0: friend class disk_cache::InFlightIO; // http://crbug.com/74623 michael@0: friend class media::AudioOutputController; // http://crbug.com/120973 michael@0: friend class net::FileStreamPosix; // http://crbug.com/115067 michael@0: friend class net::FileStreamWin; // http://crbug.com/115067 michael@0: friend class net::internal::AddressTrackerLinux; // http://crbug.com/125097 michael@0: friend class ::AcceleratedPresenter; // http://crbug.com/125391 michael@0: friend class ::BrowserProcessImpl; // http://crbug.com/125207 michael@0: friend class ::MetricsService; // http://crbug.com/124954 michael@0: friend class ::NativeBackendKWallet; // http://crbug.com/125331 michael@0: // END USAGE THAT NEEDS TO BE FIXED. michael@0: michael@0: #if ENABLE_THREAD_RESTRICTIONS michael@0: static bool SetWaitAllowed(bool allowed); michael@0: #else michael@0: static bool SetWaitAllowed(bool allowed) { return true; } michael@0: #endif michael@0: michael@0: // Constructing a ScopedAllowWait temporarily allows waiting on the current michael@0: // thread. Doing this is almost always incorrect, which is why we limit who michael@0: // can use this through friend. If you find yourself needing to use this, find michael@0: // another way. Talk to jam or brettw. michael@0: class BASE_EXPORT ScopedAllowWait { michael@0: public: michael@0: ScopedAllowWait() { previous_value_ = SetWaitAllowed(true); } michael@0: ~ScopedAllowWait() { SetWaitAllowed(previous_value_); } michael@0: private: michael@0: // Whether singleton use is allowed when the ScopedAllowWait was michael@0: // constructed. michael@0: bool previous_value_; michael@0: michael@0: DISALLOW_COPY_AND_ASSIGN(ScopedAllowWait); michael@0: }; michael@0: michael@0: DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions); michael@0: }; michael@0: michael@0: } // namespace base michael@0: michael@0: #endif // BASE_THREADING_THREAD_RESTRICTIONS_H_