| // 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 audio { | |
| class OutputDevice; | |
| } | |
| namespace blink { | |
| class VideoFrameResourceProvider; | |
| } | |
| 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 BrowserMainLoop; | |
| class BrowserProcessSubThread; | |
| class BrowserShutdownProfileDumper; | |
| class BrowserTestBase; | |
| class CategorizedWorkerPool; | |
| class GpuProcessTransportFactory; | |
| class NestedMessagePumpAndroid; | |
| class ScopedAllowWaitForAndroidLayoutTests; | |
| class ScopedAllowWaitForDebugURL; | |
| class SessionStorageDatabase; | |
| class SoftwareOutputDeviceMus; | |
| class ServiceWorkerSubresourceLoader; | |
| 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 AudioInputDevice; | |
| class BlockingUrlProtocol; | |
| } | |
| namespace midi { | |
| class TaskService; // https://crbug.com/796830 | |
| } | |
| namespace mojo { | |
| class CoreLibraryInitializer; | |
| class SyncCallRestrictions; | |
| namespace core { | |
| class ScopedIPCSupport; | |
| } | |
| } | |
| namespace rlz_lib { | |
| class FinancialPing; | |
| } | |
| namespace ui { | |
| class CommandBufferClientImpl; | |
| class CommandBufferLocal; | |
| class GpuState; | |
| class MaterialDesignController; | |
| } | |
| namespace net { | |
| class MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives; | |
| class NetworkChangeNotifierMac; | |
| namespace internal { | |
| class AddressTrackerLinux; | |
| } | |
| } | |
| namespace remoting { | |
| class AutoThread; | |
| } | |
| namespace resource_coordinator { | |
| class TabManagerDelegate; | |
| } | |
| namespace service_manager { | |
| class ServiceProcessLauncher; | |
| } | |
| namespace shell_integration_linux { | |
| class LaunchXdgUtilityScopedAllowBaseSyncPrimitives; | |
| } | |
| namespace ui { | |
| class WindowResizeHelperMac; | |
| } | |
| namespace viz { | |
| class HostGpuMemoryBufferManager; | |
| } | |
| namespace webrtc { | |
| class DesktopConfigurationMonitor; | |
| } | |
| namespace base { | |
| namespace android { | |
| class JavaHandlerThread; | |
| } | |
| namespace internal { | |
| class TaskTracker; | |
| } | |
| class AdjustOOMScoreHelper; | |
| 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. Prefer using | |
| // ScopedBlockingCall instead, which also serves as a precise annotation of the | |
| // scope that may/will block. | |
| // | |
| // 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(). | |
| // | |
| // Where unavoidable, put ScopedAllow* instances in the narrowest scope possible | |
| // in the caller making the blocking call but no further down. That is: if a | |
| // Cleanup() method needs to do a blocking call, document Cleanup() as blocking | |
| // and add a ScopedAllowBlocking instance in callers that can't avoid making | |
| // this call from a context where blocking is banned, as such: | |
| // void Client::MyMethod() { | |
| // (...) | |
| // { | |
| // // Blocking is okay here because XYZ. | |
| // ScopedAllowBlocking allow_blocking; | |
| // my_foo_->Cleanup(); | |
| // } | |
| // (...) | |
| // } | |
| // | |
| // // This method can block. | |
| // void Foo::Cleanup() { | |
| // // Do NOT add the ScopedAllowBlocking in Cleanup() directly as that hides | |
| // // its blocking nature from unknowing callers and defeats the purpose of | |
| // // these checks. | |
| // FlushStateToDisk(); | |
| // } | |
| // | |
| // Note: In rare situations where the blocking call is an implementation detail | |
| // (i.e. the impl makes a call that invokes AssertBlockingAllowed() but it | |
| // somehow knows that in practice this will not block), it might be okay to hide | |
| // the ScopedAllowBlocking instance in the impl with a comment explaining why | |
| // that's okay. | |
| 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 AdjustOOMScoreHelper; | |
| friend class android_webview::ScopedAllowInitGLBindings; | |
| friend class audio::OutputDevice; | |
| friend class content::BrowserProcessSubThread; | |
| friend class content::GpuProcessTransportFactory; | |
| friend class cronet::CronetPrefsManager; | |
| friend class cronet::CronetURLRequestContext; | |
| friend class media::AudioInputDevice; | |
| friend class mojo::CoreLibraryInitializer; | |
| friend class resource_coordinator::TabManagerDelegate; // crbug.com/778703 | |
| friend class ui::MaterialDesignController; | |
| 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::BrowserProcessSubThread; | |
| friend class content::SessionStorageDatabase; | |
| friend class functions::ExecScriptScopedAllowBaseSyncPrimitives; | |
| friend class leveldb::LevelDBMojoProxy; | |
| friend class media::BlockingUrlProtocol; | |
| friend class mojo::core::ScopedIPCSupport; | |
| friend class net::MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives; | |
| friend class rlz_lib::FinancialPing; | |
| friend class shell_integration_linux:: | |
| LaunchXdgUtilityScopedAllowBaseSyncPrimitives; | |
| friend class webrtc::DesktopConfigurationMonitor; | |
| friend class content::ServiceWorkerSubresourceLoader; | |
| friend class blink::VideoFrameResourceProvider; | |
| 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 | |
| // Not used in production yet, https://crbug.com/844078. | |
| friend class service_manager::ServiceProcessLauncher; | |
| friend class viz::HostGpuMemoryBufferManager; | |
| 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 | |
| // "Long CPU" work refers to any code that takes more than 100 ms to | |
| // run when there is no CPU contention and no hard page faults and therefore, | |
| // is not suitable to run on a thread required to keep the browser responsive | |
| // (where jank could be visible to the user). | |
| // Asserts that running long CPU work is allowed in the current scope. | |
| INLINE_IF_DCHECK_IS_OFF void AssertLongCPUWorkAllowed() | |
| EMPTY_BODY_IF_DCHECK_IS_OFF; | |
| // Disallows all tasks that may be unresponsive on the current thread. This | |
| // disallows blocking calls, waiting on a //base sync primitive and long CPU | |
| // work. | |
| INLINE_IF_DCHECK_IS_OFF void DisallowUnresponsiveTasks() | |
| EMPTY_BODY_IF_DCHECK_IS_OFF; | |
| 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() EMPTY_BODY_IF_DCHECK_IS_OFF; | |
| ~ScopedAllowIO() EMPTY_BODY_IF_DCHECK_IS_OFF; | |
| private: | |
| #if DCHECK_IS_ON() | |
| const bool was_allowed_; | |
| #endif | |
| 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(); | |
| #if defined(STARBOARD) | |
| // Get whether the current thread can use singletons. | |
| static bool GetSingletonAllowed(); | |
| #endif // defined(STARBOARD) | |
| #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() {} | |
| #if defined(STARBOARD) | |
| // Get whether the current thread can use singletons. | |
| static bool GetSingletonAllowed() {return true;} | |
| #endif // defined(STARBOARD) | |
| #endif | |
| private: | |
| // DO NOT ADD ANY OTHER FRIEND STATEMENTS. | |
| // 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::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 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::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 | |
| // 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. | |
| // | |
| // DEPRECATED. Use ScopedAllowBaseSyncPrimitives. | |
| class BASE_EXPORT ScopedAllowWait { | |
| public: | |
| ScopedAllowWait() EMPTY_BODY_IF_DCHECK_IS_OFF; | |
| ~ScopedAllowWait() EMPTY_BODY_IF_DCHECK_IS_OFF; | |
| private: | |
| #if DCHECK_IS_ON() | |
| const bool was_allowed_; | |
| #endif | |
| DISALLOW_COPY_AND_ASSIGN(ScopedAllowWait); | |
| }; | |
| DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions); | |
| }; | |
| } // namespace base | |
| #endif // BASE_THREADING_THREAD_RESTRICTIONS_H_ |