| // 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. | 
 |  | 
 | #ifndef BASE_THREADING_THREAD_RESTRICTIONS_H_ | 
 | #define BASE_THREADING_THREAD_RESTRICTIONS_H_ | 
 |  | 
 | #include "base/base_export.h" | 
 | #include "base/gtest_prod_util.h" | 
 | #include "base/logging.h" | 
 | #include "base/macros.h" | 
 |  | 
 | class BrowserProcessImpl; | 
 | class HistogramSynchronizer; | 
 | class NativeBackendKWallet; | 
 | class KeyStorageLinux; | 
 |  | 
 | namespace android_webview { | 
 | class AwFormDatabaseService; | 
 | class CookieManager; | 
 | class ScopedAllowInitGLBindings; | 
 | } | 
 |  | 
 | namespace cc { | 
 | class CompletionEvent; | 
 | class SingleThreadTaskGraphRunner; | 
 | } | 
 | namespace chromeos { | 
 | class BlockingMethodCaller; | 
 | namespace system { | 
 | class StatisticsProviderImpl; | 
 | } | 
 | } | 
 | namespace chrome_browser_net { | 
 | class Predictor; | 
 | } | 
 | namespace content { | 
 | class BrowserGpuChannelHostFactory; | 
 | class BrowserGpuMemoryBufferManager; | 
 | class BrowserMainLoop; | 
 | class BrowserShutdownProfileDumper; | 
 | class BrowserSurfaceViewManager; | 
 | class BrowserTestBase; | 
 | class CategorizedWorkerPool; | 
 | class NestedMessagePumpAndroid; | 
 | class ScopedAllowWaitForAndroidLayoutTests; | 
 | class ScopedAllowWaitForDebugURL; | 
 | class SessionStorageDatabase; | 
 | class SoftwareOutputDeviceMus; | 
 | class SynchronousCompositor; | 
 | class SynchronousCompositorHost; | 
 | class SynchronousCompositorSyncCallBridge; | 
 | class TextInputClientMac; | 
 | }  // namespace content | 
 | namespace cronet { | 
 | class CronetPrefsManager; | 
 | class CronetURLRequestContext; | 
 | }  // namespace cronet | 
 | namespace dbus { | 
 | class Bus; | 
 | } | 
 | namespace disk_cache { | 
 | class BackendImpl; | 
 | class InFlightIO; | 
 | } | 
 | namespace functions { | 
 | class ExecScriptScopedAllowBaseSyncPrimitives; | 
 | } | 
 | namespace gpu { | 
 | class GpuChannelHost; | 
 | } | 
 | namespace leveldb { | 
 | class LevelDBMojoProxy; | 
 | } | 
 | namespace media { | 
 | class BlockingUrlProtocol; | 
 | } | 
 | namespace midi { | 
 | class TaskService;  // https://crbug.com/796830 | 
 | } | 
 | namespace mojo { | 
 | class SyncCallRestrictions; | 
 | namespace edk { | 
 | class ScopedIPCSupport; | 
 | } | 
 | } | 
 | namespace rlz_lib { | 
 | class FinancialPing; | 
 | } | 
 | namespace ui { | 
 | class CommandBufferClientImpl; | 
 | class CommandBufferLocal; | 
 | class GpuState; | 
 | } | 
 | namespace net { | 
 | class MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives; | 
 | class NetworkChangeNotifierMac; | 
 | namespace internal { | 
 | class AddressTrackerLinux; | 
 | } | 
 | } | 
 |  | 
 | namespace remoting { | 
 | class AutoThread; | 
 | } | 
 |  | 
 | namespace resource_coordinator { | 
 | class TabManagerDelegate; | 
 | } | 
 |  | 
 | namespace shell_integration { | 
 | class LaunchXdgUtilityScopedAllowBaseSyncPrimitives; | 
 | } | 
 |  | 
 | namespace ui { | 
 | class WindowResizeHelperMac; | 
 | } | 
 |  | 
 | namespace views { | 
 | class ScreenMus; | 
 | } | 
 |  | 
 | namespace viz { | 
 | class ServerGpuMemoryBufferManager; | 
 | } | 
 |  | 
 | namespace webrtc { | 
 | class DesktopConfigurationMonitor; | 
 | } | 
 |  | 
 | namespace base { | 
 |  | 
 | namespace android { | 
 | class JavaHandlerThread; | 
 | } | 
 |  | 
 | namespace internal { | 
 | class TaskTracker; | 
 | } | 
 |  | 
 | class GetAppOutputScopedAllowBaseSyncPrimitives; | 
 | class SimpleThread; | 
 | class StackSamplingProfiler; | 
 | class Thread; | 
 | class ThreadTestHelper; | 
 |  | 
 | #if DCHECK_IS_ON() | 
 | #define INLINE_IF_DCHECK_IS_OFF BASE_EXPORT | 
 | #define EMPTY_BODY_IF_DCHECK_IS_OFF | 
 | #else | 
 | #define INLINE_IF_DCHECK_IS_OFF inline | 
 | #define EMPTY_BODY_IF_DCHECK_IS_OFF \ | 
 |   {} | 
 | #endif | 
 |  | 
 | // A "blocking call" refers to any call that causes the calling thread to wait | 
 | // off-CPU. It includes but is not limited to calls that wait on synchronous | 
 | // file I/O operations: read or write a file from disk, interact with a pipe or | 
 | // a socket, rename or delete a file, enumerate files in a directory, etc. | 
 | // Acquiring a low contention lock is not considered a blocking call. | 
 |  | 
 | // Asserts that blocking calls are allowed in the current scope. | 
 | // | 
 | // Style tip: It's best if you put AssertBlockingAllowed() checks as close to | 
 | // the blocking call as possible. For example: | 
 | // | 
 | // void ReadFile() { | 
 | //   PreWork(); | 
 | // | 
 | //   base::AssertBlockingAllowed(); | 
 | //   fopen(...); | 
 | // | 
 | //   PostWork(); | 
 | // } | 
 | // | 
 | // void Bar() { | 
 | //   ReadFile(); | 
 | // } | 
 | // | 
 | // void Foo() { | 
 | //   Bar(); | 
 | // } | 
 | INLINE_IF_DCHECK_IS_OFF void AssertBlockingAllowed() | 
 |     EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |  | 
 | // Disallows blocking on the current thread. | 
 | INLINE_IF_DCHECK_IS_OFF void DisallowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |  | 
 | // Disallows blocking calls within its scope. | 
 | class BASE_EXPORT ScopedDisallowBlocking { | 
 |  public: | 
 |   ScopedDisallowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |   ~ScopedDisallowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |  | 
 |  private: | 
 | #if DCHECK_IS_ON() | 
 |   const bool was_disallowed_; | 
 | #endif | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(ScopedDisallowBlocking); | 
 | }; | 
 |  | 
 | // ScopedAllowBlocking(ForTesting) allow blocking calls within a scope where | 
 | // they are normally disallowed. | 
 | // | 
 | // Avoid using this. Prefer making blocking calls from tasks posted to | 
 | // base::TaskScheduler with base::MayBlock(). | 
 | class BASE_EXPORT ScopedAllowBlocking { | 
 |  private: | 
 |   // This can only be instantiated by friends. Use ScopedAllowBlockingForTesting | 
 |   // in unit tests to avoid the friend requirement. | 
 |   FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest, ScopedAllowBlocking); | 
 |   friend class android_webview::ScopedAllowInitGLBindings; | 
 |   friend class cronet::CronetPrefsManager; | 
 |   friend class cronet::CronetURLRequestContext; | 
 |   friend class resource_coordinator::TabManagerDelegate;  // crbug.com/778703 | 
 |   friend class ScopedAllowBlockingForTesting; | 
 |   friend class StackSamplingProfiler; | 
 |  | 
 |   ScopedAllowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |   ~ScopedAllowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |  | 
 | #if DCHECK_IS_ON() | 
 |   const bool was_disallowed_; | 
 | #endif | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(ScopedAllowBlocking); | 
 | }; | 
 |  | 
 | class ScopedAllowBlockingForTesting { | 
 |  public: | 
 |   ScopedAllowBlockingForTesting() {} | 
 |   ~ScopedAllowBlockingForTesting() {} | 
 |  | 
 |  private: | 
 | #if DCHECK_IS_ON() | 
 |   ScopedAllowBlocking scoped_allow_blocking_; | 
 | #endif | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(ScopedAllowBlockingForTesting); | 
 | }; | 
 |  | 
 | // "Waiting on a //base sync primitive" refers to calling one of these methods: | 
 | // - base::WaitableEvent::*Wait* | 
 | // - base::ConditionVariable::*Wait* | 
 | // - base::Process::WaitForExit* | 
 |  | 
 | // Disallows waiting on a //base sync primitive on the current thread. | 
 | INLINE_IF_DCHECK_IS_OFF void DisallowBaseSyncPrimitives() | 
 |     EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |  | 
 | // ScopedAllowBaseSyncPrimitives(ForTesting)(OutsideBlockingScope) allow waiting | 
 | // on a //base sync primitive within a scope where this is normally disallowed. | 
 | // | 
 | // Avoid using this. | 
 | // | 
 | // Instead of waiting on a WaitableEvent or a ConditionVariable, put the work | 
 | // that should happen after the wait in a callback and post that callback from | 
 | // where the WaitableEvent or ConditionVariable would have been signaled. If | 
 | // something needs to be scheduled after many tasks have executed, use | 
 | // base::BarrierClosure. | 
 | // | 
 | // On Windows, join processes asynchronously using base::win::ObjectWatcher. | 
 |  | 
 | // This can only be used in a scope where blocking is allowed. | 
 | class BASE_EXPORT ScopedAllowBaseSyncPrimitives { | 
 |  private: | 
 |   // This can only be instantiated by friends. Use | 
 |   // ScopedAllowBaseSyncPrimitivesForTesting in unit tests to avoid the friend | 
 |   // requirement. | 
 |   FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest, | 
 |                            ScopedAllowBaseSyncPrimitives); | 
 |   FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest, | 
 |                            ScopedAllowBaseSyncPrimitivesResetsState); | 
 |   FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest, | 
 |                            ScopedAllowBaseSyncPrimitivesWithBlockingDisallowed); | 
 |   friend class base::GetAppOutputScopedAllowBaseSyncPrimitives; | 
 |   friend class content::SessionStorageDatabase; | 
 |   friend class functions::ExecScriptScopedAllowBaseSyncPrimitives; | 
 |   friend class leveldb::LevelDBMojoProxy; | 
 |   friend class media::BlockingUrlProtocol; | 
 |   friend class net::MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives; | 
 |   friend class rlz_lib::FinancialPing; | 
 |   friend class shell_integration::LaunchXdgUtilityScopedAllowBaseSyncPrimitives; | 
 |   friend class webrtc::DesktopConfigurationMonitor; | 
 |  | 
 |   ScopedAllowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |   ~ScopedAllowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |  | 
 | #if DCHECK_IS_ON() | 
 |   const bool was_disallowed_; | 
 | #endif | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(ScopedAllowBaseSyncPrimitives); | 
 | }; | 
 |  | 
 | // This can be used in a scope where blocking is disallowed. | 
 | class BASE_EXPORT ScopedAllowBaseSyncPrimitivesOutsideBlockingScope { | 
 |  private: | 
 |   // This can only be instantiated by friends. Use | 
 |   // ScopedAllowBaseSyncPrimitivesForTesting in unit tests to avoid the friend | 
 |   // requirement. | 
 |   FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest, | 
 |                            ScopedAllowBaseSyncPrimitivesOutsideBlockingScope); | 
 |   FRIEND_TEST_ALL_PREFIXES( | 
 |       ThreadRestrictionsTest, | 
 |       ScopedAllowBaseSyncPrimitivesOutsideBlockingScopeResetsState); | 
 |   friend class ::KeyStorageLinux; | 
 |   friend class content::SynchronousCompositor; | 
 |   friend class content::SynchronousCompositorHost; | 
 |   friend class content::SynchronousCompositorSyncCallBridge; | 
 |   friend class midi::TaskService;  // https://crbug.com/796830 | 
 |  | 
 |   ScopedAllowBaseSyncPrimitivesOutsideBlockingScope() | 
 |       EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |   ~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope() | 
 |       EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |  | 
 | #if DCHECK_IS_ON() | 
 |   const bool was_disallowed_; | 
 | #endif | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(ScopedAllowBaseSyncPrimitivesOutsideBlockingScope); | 
 | }; | 
 |  | 
 | // This can be used in tests without being a friend of | 
 | // ScopedAllowBaseSyncPrimitives(OutsideBlockingScope). | 
 | class BASE_EXPORT ScopedAllowBaseSyncPrimitivesForTesting { | 
 |  public: | 
 |   ScopedAllowBaseSyncPrimitivesForTesting() EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |   ~ScopedAllowBaseSyncPrimitivesForTesting() EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |  | 
 |  private: | 
 | #if DCHECK_IS_ON() | 
 |   const bool was_disallowed_; | 
 | #endif | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(ScopedAllowBaseSyncPrimitivesForTesting); | 
 | }; | 
 |  | 
 | namespace internal { | 
 |  | 
 | // Asserts that waiting on a //base sync primitive is allowed in the current | 
 | // scope. | 
 | INLINE_IF_DCHECK_IS_OFF void AssertBaseSyncPrimitivesAllowed() | 
 |     EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |  | 
 | // Resets all thread restrictions on the current thread. | 
 | INLINE_IF_DCHECK_IS_OFF void ResetThreadRestrictionsForTesting() | 
 |     EMPTY_BODY_IF_DCHECK_IS_OFF; | 
 |  | 
 | }  // namespace internal | 
 |  | 
 | class BASE_EXPORT ThreadRestrictions { | 
 |  public: | 
 |   // Constructing a ScopedAllowIO temporarily allows IO for the current | 
 |   // thread.  Doing this is almost certainly always incorrect. | 
 |   // | 
 |   // DEPRECATED. Use ScopedAllowBlocking(ForTesting). | 
 |   class BASE_EXPORT ScopedAllowIO { | 
 |    public: | 
 |     ScopedAllowIO() { previous_value_ = SetIOAllowed(true); } | 
 |     ~ScopedAllowIO() { SetIOAllowed(previous_value_); } | 
 |    private: | 
 |     // Whether IO is allowed when the ScopedAllowIO was constructed. | 
 |     bool previous_value_; | 
 |  | 
 |     DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO); | 
 |   }; | 
 |  | 
 | #if DCHECK_IS_ON() | 
 |   // Set whether the current thread to make IO calls. | 
 |   // Threads start out in the *allowed* state. | 
 |   // Returns the previous value. | 
 |   // | 
 |   // DEPRECATED. Use ScopedAllowBlocking(ForTesting) or ScopedDisallowBlocking. | 
 |   static bool SetIOAllowed(bool allowed); | 
 |  | 
 |   // Set whether the current thread can use singletons.  Returns the previous | 
 |   // value. | 
 |   static bool SetSingletonAllowed(bool allowed); | 
 |  | 
 |   // Check whether the current thread is allowed to use singletons (Singleton / | 
 |   // LazyInstance).  DCHECKs if not. | 
 |   static void AssertSingletonAllowed(); | 
 |  | 
 |   // Disable waiting on the current thread. Threads start out in the *allowed* | 
 |   // state. Returns the previous value. | 
 |   // | 
 |   // DEPRECATED. Use DisallowBaseSyncPrimitives. | 
 |   static void DisallowWaiting(); | 
 | #else | 
 |   // Inline the empty definitions of these functions so that they can be | 
 |   // compiled out. | 
 |   static bool SetIOAllowed(bool allowed) { return true; } | 
 |   static bool SetSingletonAllowed(bool allowed) { return true; } | 
 |   static void AssertSingletonAllowed() {} | 
 |   static void DisallowWaiting() {} | 
 | #endif | 
 |  | 
 |  private: | 
 |   // DO NOT ADD ANY OTHER FRIEND STATEMENTS, talk to jam or brettw first. | 
 |   // BEGIN ALLOWED USAGE. | 
 |   friend class android_webview::AwFormDatabaseService; | 
 |   friend class android_webview::CookieManager; | 
 |   friend class base::StackSamplingProfiler; | 
 |   friend class content::BrowserMainLoop; | 
 |   friend class content::BrowserShutdownProfileDumper; | 
 |   friend class content::BrowserSurfaceViewManager; | 
 |   friend class content::BrowserTestBase; | 
 |   friend class content::NestedMessagePumpAndroid; | 
 |   friend class content::ScopedAllowWaitForAndroidLayoutTests; | 
 |   friend class content::ScopedAllowWaitForDebugURL; | 
 |   friend class ::HistogramSynchronizer; | 
 |   friend class internal::TaskTracker; | 
 |   friend class cc::CompletionEvent; | 
 |   friend class cc::SingleThreadTaskGraphRunner; | 
 |   friend class content::CategorizedWorkerPool; | 
 |   friend class remoting::AutoThread; | 
 |   friend class ui::WindowResizeHelperMac; | 
 |   friend class MessagePumpDefault; | 
 |   friend class SimpleThread; | 
 |   friend class Thread; | 
 |   friend class ThreadTestHelper; | 
 |   friend class PlatformThread; | 
 |   friend class android::JavaHandlerThread; | 
 |   friend class mojo::SyncCallRestrictions; | 
 |   friend class mojo::edk::ScopedIPCSupport; | 
 |   friend class ui::CommandBufferClientImpl; | 
 |   friend class ui::CommandBufferLocal; | 
 |   friend class ui::GpuState; | 
 |  | 
 |   // END ALLOWED USAGE. | 
 |   // BEGIN USAGE THAT NEEDS TO BE FIXED. | 
 |   friend class ::chromeos::BlockingMethodCaller;  // http://crbug.com/125360 | 
 |   friend class ::chromeos::system::StatisticsProviderImpl;  // http://crbug.com/125385 | 
 |   friend class chrome_browser_net::Predictor;     // http://crbug.com/78451 | 
 |   friend class | 
 |       content::BrowserGpuChannelHostFactory;      // http://crbug.com/125248 | 
 |   friend class | 
 |       content::BrowserGpuMemoryBufferManager;     // http://crbug.com/420368 | 
 |   friend class content::TextInputClientMac;       // http://crbug.com/121917 | 
 |   friend class dbus::Bus;                         // http://crbug.com/125222 | 
 |   friend class disk_cache::BackendImpl;           // http://crbug.com/74623 | 
 |   friend class disk_cache::InFlightIO;            // http://crbug.com/74623 | 
 |   friend class gpu::GpuChannelHost;               // http://crbug.com/125264 | 
 |   friend class net::internal::AddressTrackerLinux;  // http://crbug.com/125097 | 
 |   friend class net::NetworkChangeNotifierMac;     // http://crbug.com/125097 | 
 |   friend class ::BrowserProcessImpl;              // http://crbug.com/125207 | 
 |   friend class ::NativeBackendKWallet;            // http://crbug.com/125331 | 
 | #if !defined(OFFICIAL_BUILD) | 
 |   friend class content::SoftwareOutputDeviceMus;  // Interim non-production code | 
 | #endif | 
 |   friend class views::ScreenMus; | 
 |   friend class viz::ServerGpuMemoryBufferManager; | 
 | // END USAGE THAT NEEDS TO BE FIXED. | 
 |  | 
 | #if DCHECK_IS_ON() | 
 |   // DEPRECATED. Use ScopedAllowBaseSyncPrimitives. | 
 |   static bool SetWaitAllowed(bool allowed); | 
 | #else | 
 |   static bool SetWaitAllowed(bool allowed) { return true; } | 
 | #endif | 
 |  | 
 |   // Constructing a ScopedAllowWait temporarily allows waiting on the current | 
 |   // thread.  Doing this is almost always incorrect, which is why we limit who | 
 |   // can use this through friend. If you find yourself needing to use this, find | 
 |   // another way. Talk to jam or brettw. | 
 |   // | 
 |   // DEPRECATED. Use ScopedAllowBaseSyncPrimitives. | 
 |   class BASE_EXPORT ScopedAllowWait { | 
 |    public: | 
 |     ScopedAllowWait() { previous_value_ = SetWaitAllowed(true); } | 
 |     ~ScopedAllowWait() { SetWaitAllowed(previous_value_); } | 
 |    private: | 
 |     // Whether singleton use is allowed when the ScopedAllowWait was | 
 |     // constructed. | 
 |     bool previous_value_; | 
 |  | 
 |     DISALLOW_COPY_AND_ASSIGN(ScopedAllowWait); | 
 |   }; | 
 |  | 
 |   DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions); | 
 | }; | 
 |  | 
 | }  // namespace base | 
 |  | 
 | #endif  // BASE_THREADING_THREAD_RESTRICTIONS_H_ |