text: // 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 <memory>
  
  #include "base/base_export.h"
  #include "base/check_op.h"
  #include "base/compiler_specific.h"
  #include "base/dcheck_is_on.h"
  #include "base/gtest_prod_util.h"
  #include "base/location.h"
  #include "base/macros.h"
  #include "build/build_config.h"
  
  // -----------------------------------------------------------------------------
  // Usage documentation
  // -----------------------------------------------------------------------------
  //
  // Overview:
  // This file exposes functions to ban and allow certain slow operations
  // on a per-thread basis. To annotate *usage* of such slow operations, refer to
  // scoped_blocking_call.h instead.
  //
  // Specific allowances that can be controlled in this file are:
  // - 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.
  //
  // - Waiting on a //base sync primitive: Refers to calling one of these methods:
  //   - base::WaitableEvent::*Wait*
  //   - base::ConditionVariable::*Wait*
  //   - base::Process::WaitForExit*
  //
  // - Accessing singletons: Accessing global state (Singleton / LazyInstance) is
  //   problematic on threads whom aren't joined on shutdown as they can be using
  //   the state as it becomes invalid during tear down. base::NoDestructor is the
  //   preferred alternative for global state and doesn't have this restriction.
  //
  // - 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).
  //
  // The following disallowance functions are offered:
  //  - DisallowBlocking(): Disallows blocking calls on the current thread.
  //  - DisallowBaseSyncPrimitives(): Disallows waiting on a //base sync primitive
  //    on the current thread.
  //  - DisallowSingleton(): Disallows using singletons on the current thread.
  //  - DisallowUnresponsiveTasks() Disallows blocking calls, waiting on a //base
  //    sync primitive, and long CPU work on the current thread.
  //
  // In addition, scoped-allowance mechanisms are offered to make an exception
  // within a scope for a behavior that is normally disallowed.
  //  - ScopedAllowBlocking(ForTesting): Allows blocking calls.
  //  - ScopedAllowBaseSyncPrimitives(ForTesting)(OutsideBlockingScope): Allow
  //    waiting on a //base sync primitive. The OutsideBlockingScope suffix allows
  //    uses in a scope where blocking is also disallowed.
  //
  // Avoid using allowances outside of unit tests. In unit tests, use allowances
  // with the suffix "ForTesting".
  //
  // Prefer making blocking calls from tasks posted to base::ThreadPoolInstance
  // with base::MayBlock().
  //
  // Instead of waiting on a WaitableEvent or a ConditionVariable, prefer putting
  // the work that should happen after the wait in a continuation callback and
  // post it 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.
  //
  // Where unavoidable, put ScopedAllow* instances in the narrowest scope possible
  // in the caller making the blocking call but no further down. For example: 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 BrowserProcessImpl;
  class ChromeNSSCryptoModuleDelegate;
  class KeyStorageLinux;
  class NativeBackendKWallet;
  class NativeDesktopMediaList;
  class Profile;
  class StartupTabProviderImpl;
  class GaiaConfig;
  class WebEngineBrowserMainParts;
  
  Profile* GetLastProfileMac();
  
  namespace android_webview {
  class AwFormDatabaseService;
  class CookieManager;
  class ScopedAllowInitGLBindings;
  class VizCompositorThreadRunnerWebView;
  }
  namespace ash {
  class MojoUtils;
  class BrowserDataMigrator;
  }
  namespace audio {
  class OutputDevice;
  }
  namespace blink {
  class DiskDataAllocator;
  class RTCVideoDecoderAdapter;
  class RTCVideoEncoder;
  class SourceStream;
  class VideoFrameResourceProvider;
  class WebRtcVideoFrameAdapter;
  class LegacyWebRtcVideoFrameAdapter;
  class WorkerThread;
  namespace scheduler {
  class WorkerThread;
  }
  }  // namespace blink
  namespace cc {
  class CompletionEvent;
  class TileTaskManagerImpl;
  }
  namespace chromecast {
  class CrashUtil;
  }
  namespace chromeos {
  class BlockingMethodCaller;
  namespace system {
  class StatisticsProviderImpl;
  bool IsCoreSchedulingAvailable();
  int NumberOfPhysicalCores();
  }
  }
  namespace chrome_cleaner {
  class ResetShortcutsComponent;
  class SystemReportComponent;
  }
  namespace content {
  class BrowserGpuChannelHostFactory;
  class BrowserMainLoop;
  class BrowserProcessIOThread;
  class BrowserTestBase;
  class CategorizedWorkerPool;
  class DesktopCaptureDevice;
  class EmergencyTraceFinalisationCoordinator;
  class InProcessUtilityThread;
  class NestedMessagePumpAndroid;
  class NetworkServiceInstancePrivate;
  class PepperPrintSettingsManagerImpl;
  class RenderProcessHostImpl;
  class RenderWidgetHostViewMac;
  class RTCVideoDecoder;
  class SandboxHostLinux;
  class ScopedAllowWaitForDebugURL;
  class ServiceWorkerContextClient;
  class ShellPathProvider;
  class SynchronousCompositor;
  class SynchronousCompositorHost;
  class SynchronousCompositorSyncCallBridge;
  class TextInputClientMac;
  class WaitForProcessesToDumpProfilingInfo;
  class WebContentsViewMac;
  }  // namespace content
  namespace cronet {
  class CronetPrefsManager;
  class CronetURLRequestContext;
  }  // namespace cronet
  namespace crosapi {
  class LacrosThreadPriorityDelegate;
  }  // namespace crosapi
  namespace dbus {
  class Bus;
  }
  namespace device {
  class UsbContext;
  }
  namespace disk_cache {
  class BackendImpl;
  class InFlightIO;
  }
  namespace functions {
  class ExecScriptScopedAllowBaseSyncPrimitives;
  }
  namespace history_report {
  class HistoryReportJniBridge;
  }
  namespace ios_web_view {
  class WebViewBrowserState;
  }
  namespace leveldb_env {
  class DBTracker;
  }
  namespace location {
  namespace nearby {
  namespace chrome {
  class ScheduledExecutor;
  class SubmittableExecutor;
  }  // namespace chrome
  }  // namespace nearby
  }  // namespace location
  namespace media {
  class AudioInputDevice;
  class AudioOutputDevice;
  class BlockingUrlProtocol;
  class FileVideoCaptureDeviceFactory;
  class PaintCanvasVideoRenderer;
  }
  namespace memory_instrumentation {
  class OSMetrics;
  }
  namespace metrics {
  class AndroidMetricsServiceClient;
  class CleanExitBeacon;
  }
  namespace midi {
  class TaskService;  // https://crbug.com/796830
  }
  namespace module_installer {
  class ScopedAllowModulePakLoad;
  }
  namespace mojo {
  class CoreLibraryInitializer;
  class SyncCallRestrictions;
  namespace core {
  class ScopedIPCSupport;
  }
  }
  namespace nacl {
  namespace nonsfi {
  class PluginMainDelegate;
  }
  }  // namespace nacl
  namespace printing {
  class LocalPrinterHandlerDefault;
  #if defined(OS_MAC)
  class PrintBackendServiceImpl;
  #endif
  class PrintBackendServiceManager;
  class PrintJobWorker;
  class PrinterQuery;
  }
  namespace rlz_lib {
  class FinancialPing;
  }
  namespace syncer {
  class GetLocalChangesRequest;
  class HttpBridge;
  }
  namespace ui {
  class DrmThreadProxy;
  }
  namespace weblayer {
  class BrowserContextImpl;
  class ContentBrowserClientImpl;
  class ProfileImpl;
  class WebLayerPathProvider;
  }
  namespace net {
  class MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives;
  class MultiThreadedProxyResolverScopedAllowJoinOnIO;
  class NetworkChangeNotifierMac;
  class NetworkConfigWatcherMacThread;
  namespace internal {
  class AddressTrackerLinux;
  }
  }
  
  namespace proxy_resolver {
  class ScopedAllowThreadJoinForProxyResolverV8Tracing;
  }
  
  namespace remote_cocoa {
  class DroppedScreenShotCopierMac;
  }  // namespace remote_cocoa
  
  namespace remoting {
  class AutoThread;
  class ScopedBypassIOThreadRestrictions;
  namespace protocol {
  class ScopedAllowSyncPrimitivesForWebRtcTransport;
  class ScopedAllowThreadJoinForWebRtcTransport;
  }
  }
  
  namespace service_manager {
  class ServiceProcessLauncher;
  }
  
  namespace shell_integration_linux {
  class LaunchXdgUtilityScopedAllowBaseSyncPrimitives;
  }
  
  namespace ui {
  class WindowResizeHelperMac;
  }
  
  namespace viz {
  class HostGpuMemoryBufferManager;
  }
  
  namespace vr {
  class VrShell;
  }
  
  namespace web {
  class WebMainLoop;
  class WebSubThread;
  }
  
  namespace webrtc {
  class DesktopConfigurationMonitor;
  }
  
  namespace base {
  class Environment;
  }
  
  bool HasWaylandDisplay(base::Environment* env);
  
  namespace base {
  
  namespace sequence_manager {
  namespace internal {
  class TaskQueueImpl;
  }
  }  // namespace sequence_manager
  
  namespace android {
  class JavaHandlerThread;
  }
  
  namespace internal {
  class GetAppOutputScopedAllowBaseSyncPrimitives;
  class JobTaskSource;
  class TaskTracker;
  }
  
  class AdjustOOMScoreHelper;
  class FileDescriptorWatcher;
  class FilePath;
  class ScopedAllowThreadRecallForStackSamplingProfiler;
  class StackSamplingProfiler;
  class TestCustomDisallow;
  class SimpleThread;
  class Thread;
  
  class BooleanWithStack;
  
  bool PathProviderWin(int, FilePath*);
  
  #if DCHECK_IS_ON()
  // NOT_TAIL_CALLED if dcheck-is-on so it's always evident who irrevocably
  // altered the allowance (dcheck-builds will provide the setter's stack on
  // assertion) or who made a failing Assert*() call.
  #define INLINE_OR_NOT_TAIL_CALLED BASE_EXPORT NOT_TAIL_CALLED
  #define EMPTY_BODY_IF_DCHECK_IS_OFF
  #else
  // inline if dcheck-is-off so it's no overhead
  #define INLINE_OR_NOT_TAIL_CALLED inline
  
  // The static_assert() eats follow-on semicolons. `= default` would work
  // too, but it makes clang realize that all the Scoped classes are no-ops in
  // non-dcheck builds and it starts emitting many -Wunused-variable warnings.
  #define EMPTY_BODY_IF_DCHECK_IS_OFF \
    {}                                \
    static_assert(true, "")
  #endif  // DCHECK_IS_ON()
  
  namespace internal {
  
  // Asserts that blocking calls are allowed in the current scope. This is an
  // internal call, external code should use ScopedBlockingCall instead, which
  // serves as a precise annotation of the scope that may/will block.
  INLINE_OR_NOT_TAIL_CALLED void AssertBlockingAllowed()
      EMPTY_BODY_IF_DCHECK_IS_OFF;
  INLINE_OR_NOT_TAIL_CALLED void AssertBlockingDisallowedForTesting()
      EMPTY_BODY_IF_DCHECK_IS_OFF;
  
  }  // namespace internal
  
  // Disallows blocking on the current thread.
  INLINE_OR_NOT_TAIL_CALLED 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(const ScopedDisallowBlocking&) = delete;
    ScopedDisallowBlocking& operator=(const ScopedDisallowBlocking&) = delete;
  
    ~ScopedDisallowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
  
   private:
  #if DCHECK_IS_ON()
    std::unique_ptr<BooleanWithStack> was_disallowed_;
  #endif
  };
  
  class BASE_EXPORT ScopedAllowBlocking {
   private:
    FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest,
                             NestedAllowRestoresPreviousStack);
    FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest, ScopedAllowBlocking);
    friend class ScopedAllowBlockingForTesting;
  
    // This can only be instantiated by friends. Use ScopedAllowBlockingForTesting
    // in unit tests to avoid the friend requirement.
    friend class ::GaiaConfig;
    friend class ::StartupTabProviderImpl;
    friend class android_webview::ScopedAllowInitGLBindings;
    friend class ash::MojoUtils;  // http://crbug.com/1055467
    friend class ash::BrowserDataMigrator;
    friend class base::AdjustOOMScoreHelper;
    friend class base::StackSamplingProfiler;
    friend class blink::DiskDataAllocator;
    friend class chromecast::CrashUtil;
    friend class content::BrowserProcessIOThread;
    friend class content::NetworkServiceInstancePrivate;
    friend class content::PepperPrintSettingsManagerImpl;
    friend class content::RenderProcessHostImpl;
    friend class content::RenderWidgetHostViewMac;  // http://crbug.com/121917
    friend class content::ShellPathProvider;
    friend class content::WebContentsViewMac;
    friend class cronet::CronetPrefsManager;
    friend class cronet::CronetURLRequestContext;
    friend class crosapi::LacrosThreadPriorityDelegate;
    friend class ios_web_view::WebViewBrowserState;
    friend class media::FileVideoCaptureDeviceFactory;
    friend class memory_instrumentation::OSMetrics;
    friend class metrics::AndroidMetricsServiceClient;
    friend class metrics::CleanExitBeacon;
    friend class module_installer::ScopedAllowModulePakLoad;
    friend class mojo::CoreLibraryInitializer;
    friend class printing::LocalPrinterHandlerDefault;
  #if defined(OS_MAC)
    friend class printing::PrintBackendServiceImpl;
  #endif
    friend class printing::PrintBackendServiceManager;
    friend class printing::PrintJobWorker;
    friend class remote_cocoa::
        DroppedScreenShotCopierMac;  // https://crbug.com/1148078
    friend class remoting::ScopedBypassIOThreadRestrictions;  // crbug.com/1144161
    friend class web::WebSubThread;
    friend class ::WebEngineBrowserMainParts;
    friend class weblayer::BrowserContextImpl;
    friend class weblayer::ContentBrowserClientImpl;
    friend class weblayer::ProfileImpl;
    friend class weblayer::WebLayerPathProvider;
  
    friend Profile* ::GetLastProfileMac();  // crbug.com/1176734
    friend bool PathProviderWin(int, FilePath*);
    friend bool chromeos::system::IsCoreSchedulingAvailable();
    friend int chromeos::system::NumberOfPhysicalCores();
    friend bool ::HasWaylandDisplay(Environment* env);  // crbug.com/1246928
  
    ScopedAllowBlocking(const Location& from_here = Location::Current());
    ~ScopedAllowBlocking();
  
  #if DCHECK_IS_ON()
    std::unique_ptr<BooleanWithStack> was_disallowed_;
  #endif
  
    DISALLOW_COPY_AND_ASSIGN(ScopedAllowBlocking);
  };
  
  class ScopedAllowBlockingForTesting {
   public:
    ScopedAllowBlockingForTesting() {}
  
    ScopedAllowBlockingForTesting(const ScopedAllowBlockingForTesting&) = delete;
    ScopedAllowBlockingForTesting& operator=(
        const ScopedAllowBlockingForTesting&) = delete;
  
    ~ScopedAllowBlockingForTesting() {}
  
   private:
  #if DCHECK_IS_ON()
    ScopedAllowBlocking scoped_allow_blocking_;
  #endif
  };
  
  INLINE_OR_NOT_TAIL_CALLED void DisallowBaseSyncPrimitives()
      EMPTY_BODY_IF_DCHECK_IS_OFF;
  
  // Disallows singletons within its scope.
  class BASE_EXPORT ScopedDisallowBaseSyncPrimitives {
   public:
    ScopedDisallowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF;
  
    ScopedDisallowBaseSyncPrimitives(const ScopedDisallowBaseSyncPrimitives&) =
        delete;
    ScopedDisallowBaseSyncPrimitives& operator=(
        const ScopedDisallowBaseSyncPrimitives&) = delete;
  
    ~ScopedDisallowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF;
  
   private:
  #if DCHECK_IS_ON()
    std::unique_ptr<BooleanWithStack> was_disallowed_;
  #endif
  };
  
  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);
  
    // Allowed usage:
    friend class ::ChromeNSSCryptoModuleDelegate;
    friend class base::internal::GetAppOutputScopedAllowBaseSyncPrimitives;
    friend class base::SimpleThread;
    friend class blink::SourceStream;
    friend class blink::WorkerThread;
    friend class blink::scheduler::WorkerThread;
    friend class chrome_cleaner::ResetShortcutsComponent;
    friend class chrome_cleaner::SystemReportComponent;
    friend class content::BrowserMainLoop;
    friend class content::BrowserProcessIOThread;
    friend class content::ServiceWorkerContextClient;
    friend class device::UsbContext;
    friend class functions::ExecScriptScopedAllowBaseSyncPrimitives;
    friend class history_report::HistoryReportJniBridge;
    friend class internal::TaskTracker;
    friend class leveldb_env::DBTracker;
    friend class location::nearby::chrome::ScheduledExecutor;
    friend class location::nearby::chrome::SubmittableExecutor;
    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 syncer::HttpBridge;
    friend class syncer::GetLocalChangesRequest;
    friend class webrtc::DesktopConfigurationMonitor;
  
    // Usage that should be fixed:
    friend class ::NativeBackendKWallet;            // http://crbug.com/125331
    friend class ::chromeos::system::
        StatisticsProviderImpl;                      // http://crbug.com/125385
    friend class blink::VideoFrameResourceProvider;  // http://crbug.com/878070
  
    ScopedAllowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF;
    ~ScopedAllowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF;
  
  #if DCHECK_IS_ON()
    std::unique_ptr<BooleanWithStack> was_disallowed_;
  #endif
  
    DISALLOW_COPY_AND_ASSIGN(ScopedAllowBaseSyncPrimitives);
  };
  
  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);
  
    // Allowed usage:
    friend class ::BrowserProcessImpl;  // http://crbug.com/125207
    friend class ::KeyStorageLinux;
    friend class ::NativeDesktopMediaList;
    friend class android::JavaHandlerThread;
    friend class android_webview::
        AwFormDatabaseService;  // http://crbug.com/904431
    friend class android_webview::CookieManager;
    friend class android_webview::VizCompositorThreadRunnerWebView;
    friend class audio::OutputDevice;
    friend class base::sequence_manager::internal::TaskQueueImpl;
    friend class base::FileDescriptorWatcher;
    friend class base::internal::JobTaskSource;
    friend class base::ScopedAllowThreadRecallForStackSamplingProfiler;
    friend class base::StackSamplingProfiler;
    friend class blink::RTCVideoDecoderAdapter;
    friend class blink::RTCVideoEncoder;
    friend class blink::WebRtcVideoFrameAdapter;
    friend class blink::LegacyWebRtcVideoFrameAdapter;
    friend class cc::TileTaskManagerImpl;
    friend class content::CategorizedWorkerPool;
    friend class content::DesktopCaptureDevice;
    friend class content::EmergencyTraceFinalisationCoordinator;
    friend class content::InProcessUtilityThread;
    friend class content::RTCVideoDecoder;
    friend class content::SandboxHostLinux;
    friend class content::ScopedAllowWaitForDebugURL;
    friend class content::SynchronousCompositor;
    friend class content::SynchronousCompositorHost;
    friend class content::SynchronousCompositorSyncCallBridge;
    friend class content::WaitForProcessesToDumpProfilingInfo;
    friend class media::AudioInputDevice;
    friend class media::AudioOutputDevice;
    friend class media::PaintCanvasVideoRenderer;
    friend class mojo::SyncCallRestrictions;
    friend class net::NetworkConfigWatcherMacThread;
    friend class ui::DrmThreadProxy;
    friend class viz::HostGpuMemoryBufferManager;
    friend class vr::VrShell;
  
    // Usage that should be fixed:
    friend class ::chromeos::BlockingMethodCaller;  // http://crbug.com/125360
    friend class base::Thread;                      // http://crbug.com/918039
    friend class cc::CompletionEvent;               // http://crbug.com/902653
    friend class content::
        BrowserGpuChannelHostFactory;                 // http://crbug.com/125248
    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 midi::TaskService;                   // https://crbug.com/796830
    friend class net::internal::AddressTrackerLinux;  // http://crbug.com/125097
    friend class net::
        MultiThreadedProxyResolverScopedAllowJoinOnIO;  // http://crbug.com/69710
    friend class net::NetworkChangeNotifierMac;         // http://crbug.com/125097
    friend class printing::PrinterQuery;                 // http://crbug.com/66082
    friend class proxy_resolver::
        ScopedAllowThreadJoinForProxyResolverV8Tracing;  // http://crbug.com/69710
    friend class remoting::AutoThread;  // https://crbug.com/944316
    friend class remoting::protocol::
        ScopedAllowSyncPrimitivesForWebRtcTransport;  // http://crbug.com/1198501
    friend class remoting::protocol::
        ScopedAllowThreadJoinForWebRtcTransport;  // http://crbug.com/660081
    // Not used in production yet, https://crbug.com/844078.
    friend class service_manager::ServiceProcessLauncher;
    friend class ui::WindowResizeHelperMac;  // http://crbug.com/902829
    friend class content::TextInputClientMac;  // http://crbug.com/121917
  
    ScopedAllowBaseSyncPrimitivesOutsideBlockingScope(
        const Location& from_here = Location::Current());
  
    ~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope();
  
  #if DCHECK_IS_ON()
    std::unique_ptr<BooleanWithStack> was_disallowed_;
  #endif
  
    DISALLOW_COPY_AND_ASSIGN(ScopedAllowBaseSyncPrimitivesOutsideBlockingScope);
  };
  
  // Allow base-sync-primitives in tests, doesn't require explicit friend'ing like
  // ScopedAllowBaseSyncPrimitives-types aimed at production do.
  // Note: For WaitableEvents in the test logic, base::TestWaitableEvent is
  // exposed as a convenience to avoid the need for
  // ScopedAllowBaseSyncPrimitivesForTesting.
  class BASE_EXPORT ScopedAllowBaseSyncPrimitivesForTesting {
   public:
    ScopedAllowBaseSyncPrimitivesForTesting() EMPTY_BODY_IF_DCHECK_IS_OFF;
  
    ScopedAllowBaseSyncPrimitivesForTesting(
        const ScopedAllowBaseSyncPrimitivesForTesting&) = delete;
    ScopedAllowBaseSyncPrimitivesForTesting& operator=(
        const ScopedAllowBaseSyncPrimitivesForTesting&) = delete;
  
    ~ScopedAllowBaseSyncPrimitivesForTesting() EMPTY_BODY_IF_DCHECK_IS_OFF;
  
   private:
  #if DCHECK_IS_ON()
    std::unique_ptr<BooleanWithStack> was_disallowed_;
  #endif
  };
  
  // Counterpart to base::DisallowUnresponsiveTasks() for tests to allow them to
  // block their thread after it was banned.
  class BASE_EXPORT ScopedAllowUnresponsiveTasksForTesting {
   public:
    ScopedAllowUnresponsiveTasksForTesting() EMPTY_BODY_IF_DCHECK_IS_OFF;
  
    ScopedAllowUnresponsiveTasksForTesting(
        const ScopedAllowUnresponsiveTasksForTesting&) = delete;
    ScopedAllowUnresponsiveTasksForTesting& operator=(
        const ScopedAllowUnresponsiveTasksForTesting&) = delete;
  
    ~ScopedAllowUnresponsiveTasksForTesting() EMPTY_BODY_IF_DCHECK_IS_OFF;
  
   private:
  #if DCHECK_IS_ON()
    std::unique_ptr<BooleanWithStack> was_disallowed_base_sync_;
    std::unique_ptr<BooleanWithStack> was_disallowed_blocking_;
    std::unique_ptr<BooleanWithStack> was_disallowed_cpu_;
  #endif
  };
  
  namespace internal {
  
  // Asserts that waiting on a //base sync primitive is allowed in the current
  // scope.
  INLINE_OR_NOT_TAIL_CALLED void AssertBaseSyncPrimitivesAllowed()
      EMPTY_BODY_IF_DCHECK_IS_OFF;
  
  // Resets all thread restrictions on the current thread.
  INLINE_OR_NOT_TAIL_CALLED void ResetThreadRestrictionsForTesting()
      EMPTY_BODY_IF_DCHECK_IS_OFF;
  
  // Check whether the current thread is allowed to use singletons (Singleton /
  // LazyInstance).  DCHECKs if not.
  INLINE_OR_NOT_TAIL_CALLED void AssertSingletonAllowed()
      EMPTY_BODY_IF_DCHECK_IS_OFF;
  
  }  // namespace internal
  
  // Disallow using singleton on the current thread.
  INLINE_OR_NOT_TAIL_CALLED void DisallowSingleton() EMPTY_BODY_IF_DCHECK_IS_OFF;
  
  // Disallows singletons within its scope.
  class BASE_EXPORT ScopedDisallowSingleton {
   public:
    ScopedDisallowSingleton() EMPTY_BODY_IF_DCHECK_IS_OFF;
  
    ScopedDisallowSingleton(const ScopedDisallowSingleton&) = delete;
    ScopedDisallowSingleton& operator=(const ScopedDisallowSingleton&) = delete;
  
    ~ScopedDisallowSingleton() EMPTY_BODY_IF_DCHECK_IS_OFF;
  
   private:
  #if DCHECK_IS_ON()
    std::unique_ptr<BooleanWithStack> was_disallowed_;
  #endif
  };
  
  // Asserts that running long CPU work is allowed in the current scope.
  INLINE_OR_NOT_TAIL_CALLED void AssertLongCPUWorkAllowed()
      EMPTY_BODY_IF_DCHECK_IS_OFF;
  
  INLINE_OR_NOT_TAIL_CALLED void DisallowUnresponsiveTasks()
      EMPTY_BODY_IF_DCHECK_IS_OFF;
  
  class BASE_EXPORT ThreadRestrictions {
   public:
    ThreadRestrictions() = delete;
  
    // Constructing a ScopedAllowIO temporarily allows IO for the current
    // thread.  Doing this is almost certainly always incorrect.
    //
    // DEPRECATED. Use ScopedAllowBlocking(ForTesting).
    // TODO(crbug.com/766678): Migrate remaining users.
    class BASE_EXPORT ScopedAllowIO {
     public:
      ScopedAllowIO(const Location& from_here = Location::Current());
  
      ScopedAllowIO(const ScopedAllowIO&) = delete;
      ScopedAllowIO& operator=(const ScopedAllowIO&) = delete;
  
      ~ScopedAllowIO();
  
     private:
  #if DCHECK_IS_ON()
      std::unique_ptr<BooleanWithStack> was_disallowed_;
  #endif
    };
  };
  
  // Friend-only methods to permanently allow the current thread to use
  // blocking/sync-primitives calls. Threads start out in the *allowed* state but
  // are typically *disallowed* via the above base::Disallow*() methods after
  // being initialized.
  //
  // Only use these to permanently set the allowance on a thread, e.g. on
  // shutdown. For temporary allowances, use scopers above.
  class BASE_EXPORT PermanentThreadAllowance {
   public:
    // Class is merely a namespace-with-friends.
    PermanentThreadAllowance() = delete;
  
   private:
    friend class base::TestCustomDisallow;
    friend class content::BrowserMainLoop;
    friend class content::BrowserTestBase;
    friend class web::WebMainLoop;
  
    static void AllowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
    static void AllowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF;
  };
  
  // Similar to PermanentThreadAllowance but separate because it's dangerous and
  // should have even fewer friends.
  class BASE_EXPORT PermanentSingletonAllowance {
   public:
    // Class is merely a namespace-with-friends.
    PermanentSingletonAllowance() = delete;
  
   private:
    friend class nacl::nonsfi::PluginMainDelegate;
  
    // Re-allow singletons on this thread. Since //base APIs DisallowSingleton()
    // when they risk running past shutdown, this should only be called in rare
    // cases where the caller knows the process will be killed rather than
    // shutdown.
    static void AllowSingleton() EMPTY_BODY_IF_DCHECK_IS_OFF;
  };
  
  #undef INLINE_OR_NOT_TAIL_CALLED
  #undef EMPTY_BODY_IF_DCHECK_IS_OFF
  
  }  // namespace base
  
  #endif  // BASE_THREADING_THREAD_RESTRICTIONS_H_
  