chromium/base/threading/thread_restrictions.h

// Copyright 2012 The Chromium Authors
// 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/auto_reset.h"
#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/dcheck_is_on.h"
#include "base/gtest_prod_util.h"
#include "base/location.h"
#include "build/build_config.h"

#if DCHECK_IS_ON()
#include <optional>

#include "base/debug/stack_trace.h"
#endif

// -----------------------------------------------------------------------------
// 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.
//
//   Prefer to allow a blocking call by posting a task to
//   base::ThreadPoolInstance with base::MayBlock().
//
// - Waiting on a //base sync primitive: Refers to calling one of these methods:
//   - base::WaitableEvent::*Wait*
//   - base::ConditionVariable::*Wait*
//   - base::Process::WaitForExit*
//
//   Prefer not to wait on //base sync primitives (see below for alternatives).
//   When it is unavoidable, use ScopedAllowBaseSyncPrimitives in a task posted
//   to base::ThreadPoolInstance with base::MayBlock().
//
// - 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: Allows blocking calls. Prefer to use base::MayBlock()
//    instead.
//  - ScopedAllowBaseSyncPrimitives: Allows waiting on a //base sync primitive.
//    Must also be in a scope where blocking calls are allowed.
//  - ScopedAllowBaseSyncPrimitivesOutsideBlockingScope: Allow waiting on a
//    //base sync primitive, even in a scope where blocking calls are
//    disallowed. Prefer to use a combination of base::MayBlock() and
//    ScopedAllowBaseSyncPrimitives.
//
// Avoid using allowances outside of unit tests. In unit tests, use allowances
// with the suffix "ForTesting":
//  - ScopedAllowBlockingForTesting: Allows blocking calls in unit tests.
//  - ScopedAllowBaseSyncPrimitivesForTesting: Allows waiting on a //base sync
//    primitive in unit tests. For convenience this can be used in a scope
//    where blocking calls are disallowed. Note that base::TestWaitableEvent can
//    be used without this, also for convenience.
//
// 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 BrowserThemePack;
class ChromeNSSCryptoModuleDelegate;
class DesktopNotificationBalloon;
class FirefoxProfileLock;
class GaiaConfig;
class KeyStorageLinux;
class NativeBackendKWallet;
class NativeDesktopMediaList;
class PartnerBookmarksReader;
class Profile;
class ProfileImpl;
class ScopedAllowBlockingForProfile;
class StartupTabProviderImpl;
class WebEngineBrowserMainParts;
struct StartupProfilePathInfo;

namespace base {
class Environment;
class File;
class FilePath;
class CommandLine;
namespace sequence_manager::internal {
class WorkTracker;
}  // namespace sequence_manager::internal
}  // namespace base

StartupProfilePathInfo GetStartupProfilePath(
    const base::FilePath& cur_dir,
    const base::CommandLine& command_line,
    bool ignore_profile_picker);

#if BUILDFLAG(IS_IOS)
class BrowserStateDirectoryBuilder;
#endif

Profile* GetLastProfileMac();
bool HasWaylandDisplay(base::Environment* env);

namespace android_webview {
class AwBrowserContext;
class AwFormDatabaseService;
class CookieManager;
class JsSandboxIsolate;
class OverlayProcessorWebView;
class ScopedAllowInitGLBindings;
class VizCompositorThreadRunnerWebView;
}  // namespace android_webview
namespace ash {
class BrowserDataBackMigrator;
class LoginEventRecorder;
class StartupCustomizationDocument;
class StartupUtils;
bool CameraAppUIShouldEnableLocalOverride(const std::string&);
namespace converters::diagnostics {
class MojoUtils;
}
namespace system {
class StatisticsProviderImpl;
class ProcStatFile;
}  // namespace system
}  // namespace ash
namespace audio {
class OutputDevice;
}
namespace blink {
class AudioDestination;
class DiskDataAllocator;
class RTCVideoDecoderAdapter;
class RTCVideoEncoder;
class SourceStream;
class VideoFrameResourceProvider;
class WebRtcVideoFrameAdapter;
class VideoTrackRecorderImplContextProvider;
class WorkerThread;
namespace scheduler {
class NonMainThreadImpl;
}
}  // namespace blink
namespace cc {
class CategorizedWorkerPoolImpl;
class CategorizedWorkerPoolJob;
class CategorizedWorkerPool;
class CompletionEvent;
class TileTaskManagerImpl;
}  // namespace cc
namespace chrome {
bool PathProvider(int, base::FilePath*);
void SessionEnding();
}  // namespace chrome
namespace chromecast {
class CrashUtil;
}
namespace chromeos {
class BlockingMethodCaller;
namespace system {
bool IsCoreSchedulingAvailable();
int NumberOfPhysicalCores();
}  // namespace system
}  // namespace chromeos
namespace content {
class BrowserGpuChannelHostFactory;
class BrowserMainLoop;
class BrowserProcessIOThread;
class BrowserTestBase;
#if BUILDFLAG(IS_IOS)
class ContentMainRunnerImpl;
#endif  // BUILDFLAG(IS_IOS)
class DesktopCaptureDevice;
class DWriteFontCollectionProxy;
class DWriteFontProxyImpl;
class EmergencyTraceFinalisationCoordinator;
class InProcessUtilityThread;
class NestedMessagePumpAndroid;
class NetworkServiceInstancePrivate;
class PepperPrintSettingsManagerImpl;
class RenderProcessHostImpl;
class RenderProcessHost;
class RenderWidgetHostViewMac;
class RendererBlinkPlatformImpl;
class SandboxHostLinux;
class ScopedAllowWaitForDebugURL;
class ServiceWorkerContextClient;
class ShellPathProvider;
class SynchronousCompositor;
class SynchronousCompositorHost;
class SynchronousCompositorSyncCallBridge;
class ScopedAllowBlockingForViewAura;
class TextInputClientMac;
class WebContentsImpl;
class WebContentsViewMac;
base::File CreateFileForDrop(base::FilePath*);
}  // namespace content
namespace cronet {
class CronetPrefsManager;
class CronetContext;
}  // namespace cronet
namespace crosapi {
class LacrosThreadTypeDelegate;
}  // namespace crosapi
namespace crypto {
class ScopedAllowBlockingForNSS;
}
namespace dbus {
class Bus;
}
namespace drive {
class FakeDriveService;
}
namespace device {
class UsbContext;
}
namespace discardable_memory {
class ClientDiscardableSharedMemoryManager;
}
namespace disk_cache {
class BackendImpl;
class InFlightIO;
bool CleanupDirectorySync(const base::FilePath&);
}  // namespace disk_cache
namespace enterprise_connectors {
class LinuxKeyRotationCommand;
}  // namespace enterprise_connectors
namespace extensions {
class InstalledLoader;
class UnpackedInstaller;
}  // namespace extensions
namespace font_service::internal {
class MappedFontFile;
}
namespace gl {
struct GLImplementationParts;
namespace init {
bool InitializeStaticGLBindings(GLImplementationParts);
}
}  // namespace gl
namespace history_report {
class HistoryReportJniBridge;
}
namespace ios_web_view {
class WebViewBrowserState;
}
namespace io_thread {
class IOSIOThread;
}
namespace leveldb::port {
class CondVar;
}  // namespace leveldb::port
namespace nearby::chrome {
class BleV2GattClient;
class BleV2Medium;
class ScheduledExecutor;
class SubmittableExecutor;
class WifiDirectSocket;
}  // namespace nearby::chrome
namespace media {
class AudioInputDevice;
class AudioOutputDevice;
class BlockingUrlProtocol;
template <class WorkerInterface,
          class WorkerImpl,
          class Worker,
          class WorkerStatus,
          WorkerStatus StatusNotOk,
          WorkerStatus StatusOk,
          WorkerStatus StatusWork>
class CodecWorkerImpl;
class FileVideoCaptureDeviceFactory;
class GpuMojoMediaClientWin;
class MojoVideoEncodeAccelerator;
class PaintCanvasVideoRenderer;
class V4L2DevicePoller;  // TODO(crbug.com/41486289): remove this.
}  // namespace media
namespace memory_instrumentation {
class OSMetrics;
}
namespace memory_pressure {
class UserLevelMemoryPressureSignalGenerator;
}
namespace metrics {
class AndroidMetricsServiceClient;
class CleanExitBeacon;
}  // namespace metrics
namespace midi {
class TaskService;  // https://crbug.com/796830
}
namespace module_installer {
class ScopedAllowModulePakLoad;
}
namespace mojo {
class SyncCallRestrictions;
namespace core {
class ScopedIPCSupport;
namespace ipcz_driver {
class MojoTrap;
}
}  // namespace core
}  // namespace mojo
namespace net {
class GSSAPISharedLibrary;
class MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives;
class MultiThreadedProxyResolverScopedAllowJoinOnIO;
class NetworkChangeNotifierApple;
class NetworkConfigWatcherAppleThread;
class ProxyConfigServiceWin;
class ScopedAllowBlockingForSettingGetter;
namespace internal {
class AddressTrackerLinux;
class PemFileCertStore;
}
}  // namespace net
namespace printing {
class LocalPrinterHandlerDefault;
#if BUILDFLAG(IS_MAC)
class PrintBackendServiceImpl;
#endif
class PrintBackendServiceManager;
class PrintPreviewUIUntrusted;
class PrinterQuery;
}  // namespace printing
namespace proxy_resolver {
class ScopedAllowThreadJoinForProxyResolverV8Tracing;
}
namespace remote_cocoa {
class DroppedScreenShotCopierMac;
class SelectFileDialogBridge;
}  // namespace remote_cocoa
namespace remoting {
class AutoThread;
class ScopedAllowBlockingForCrashReporting;
class ScopedBypassIOThreadRestrictions;
namespace protocol {
class ScopedAllowSyncPrimitivesForWebRtcDataStreamAdapter;
class ScopedAllowSyncPrimitivesForWebRtcTransport;
class ScopedAllowSyncPrimitivesForWebRtcVideoStream;
class ScopedAllowThreadJoinForWebRtcTransport;
}  // namespace protocol
}  // namespace remoting
namespace rlz_lib {
class FinancialPing;
}
namespace service_manager {
class ServiceProcessLauncher;
}
namespace shell_integration_linux {
class LaunchXdgUtilityScopedAllowBaseSyncPrimitives;
}
namespace storage {
class ObfuscatedFileUtil;
}
namespace syncer {
class GetLocalChangesRequest;
class HttpBridge;
}  // namespace syncer
namespace tracing {
class FuchsiaPerfettoProducerConnector;
}
namespace ui {
class DrmThreadProxy;
class DrmDisplayHostManager;
class ScopedAllowBlockingForGbmSurface;
class SelectFileDialogLinux;
class WindowResizeHelperMac;
}  // namespace ui
namespace updater {
class SystemctlLauncherScopedAllowBaseSyncPrimitives;
}
namespace viz {
class HostGpuMemoryBufferManager;
class ClientGpuMemoryBufferManager;
class DisplayCompositorMemoryAndTaskController;
class SkiaOutputSurfaceImpl;
class SharedImageInterfaceProvider;
}  // namespace viz
namespace vr {
class VrShell;
}
namespace web {
class WebMainLoop;
}  // namespace web
namespace weblayer {
class BrowserContextImpl;
class ContentBrowserClientImpl;
class ProfileImpl;
class WebLayerPathProvider;
}  // namespace weblayer
// NOTE: Please do not append entries here. Put them in the list above and keep
// the list sorted.

namespace base {

namespace android {
class JavaHandlerThread;
class PmfUtils;
class ScopedAllowBlockingForImportantFileWriter;
}  // namespace android

namespace apple::internal {
base::FilePath GetExecutablePath();
}

namespace debug {
class StackTrace;
}

namespace internal {
class GetAppOutputScopedAllowBaseSyncPrimitives;
class JobTaskSource;
class TaskTracker;
bool ReadProcFile(const FilePath& file, std::string* buffer);
}  // namespace internal

namespace sequence_manager::internal {
class TaskQueueImpl;
}  // namespace sequence_manager::internal

namespace subtle {
class PlatformSharedMemoryRegion;
}

namespace win {
class OSInfo;
class ObjectWatcher;
class ScopedAllowBlockingForUserAccountControl;
}  // namespace win

class AdjustOOMScoreHelper;
class ChromeOSVersionInfo;
class FileDescriptorWatcher;
class FilePath;
class Process;
class ScopedAllowBlockingForProc;
class ScopedAllowBlockingForProcessMetrics;
class ScopedAllowThreadRecallForStackSamplingProfiler;
class SimpleThread;
class StackSamplingProfiler;
class TestCustomDisallow;
class Thread;

#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
#define EMPTY_BODY_IF_DCHECK_IS_OFF
#define DEFAULT_IF_DCHECK_IS_OFF

class BooleanWithStack {};

#else
// inline if dcheck-is-off so it's no overhead
#define INLINE_OR_NOT_TAIL_CALLED

// The static_assert() eats follow-on semicolons.
#define EMPTY_BODY_IF_DCHECK_IS_OFF

#define DEFAULT_IF_DCHECK_IS_OFF
#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 [[maybe_unused, nodiscard]] ScopedDisallowBlocking {};

class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedAllowBlocking {};

class [[maybe_unused, nodiscard]] ScopedAllowBlockingForTesting {};

INLINE_OR_NOT_TAIL_CALLED void DisallowBaseSyncPrimitives()
    EMPTY_BODY_IF_DCHECK_IS_OFF;

// Disallows singletons within its scope.
class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedDisallowBaseSyncPrimitives {};

class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedAllowBaseSyncPrimitives {};

class BASE_EXPORT
    [[maybe_unused,
      nodiscard]] 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
    [[maybe_unused, nodiscard]] ScopedAllowBaseSyncPrimitivesForTesting {};

// Counterpart to base::DisallowUnresponsiveTasks() for tests to allow them to
// block their thread after it was banned.
class BASE_EXPORT
    [[maybe_unused, nodiscard]] ScopedAllowUnresponsiveTasksForTesting {};

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 [[maybe_unused, nodiscard]] ScopedDisallowSingleton {};

// 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;

// 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 {};

#undef INLINE_OR_NOT_TAIL_CALLED
#undef EMPTY_BODY_IF_DCHECK_IS_OFF
#undef DEFAULT_IF_DCHECK_IS_OFF

}  // namespace base

#endif  // BASE_THREADING_THREAD_RESTRICTIONS_H_