// Copyright 2017 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_SCOPED_BLOCKING_CALL_H_ #define BASE_THREADING_SCOPED_BLOCKING_CALL_H_ #include "base/base_export.h" #include "base/functional/callback_forward.h" #include "base/location.h" #include "base/strings/string_piece.h" #include "base/threading/scoped_blocking_call_internal.h" #include "base/types/strong_alias.h" namespace base { // 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. // BlockingType indicates the likelihood that a blocking call will actually // block. enum class BlockingType { // The call might block (e.g. file I/O that might hit in memory cache). MAY_BLOCK, // The call will definitely block (e.g. cache already checked and now pinging // server synchronously). WILL_BLOCK }; // This class must be instantiated in every scope where a blocking call is made // and serves as a precise annotation of the scope that may/will block for the // scheduler. When a ScopedBlockingCall is instantiated, it asserts that // blocking calls are allowed in its scope with a call to // base::AssertBlockingAllowed(). CPU usage should be minimal within that scope. // //base APIs that block instantiate their own ScopedBlockingCall; it is not // necessary to instantiate another ScopedBlockingCall in the scope where these // APIs are used. Nested ScopedBlockingCalls are supported (mostly a no-op // except for WILL_BLOCK nested within MAY_BLOCK which will result in immediate // WILL_BLOCK semantics). // // Good: // Data data; // { // ScopedBlockingCall scoped_blocking_call( // FROM_HERE, BlockingType::WILL_BLOCK); // data = GetDataFromNetwork(); // } // CPUIntensiveProcessing(data); // // Bad: // ScopedBlockingCall scoped_blocking_call(FROM_HERE, // BlockingType::WILL_BLOCK); // Data data = GetDataFromNetwork(); // CPUIntensiveProcessing(data); // CPU usage within a ScopedBlockingCall. // // Good: // Data a; // Data b; // { // ScopedBlockingCall scoped_blocking_call( // FROM_HERE, BlockingType::MAY_BLOCK); // a = GetDataFromMemoryCacheOrNetwork(); // b = GetDataFromMemoryCacheOrNetwork(); // } // CPUIntensiveProcessing(a); // CPUIntensiveProcessing(b); // // Bad: // ScopedBlockingCall scoped_blocking_call( // FROM_HERE, BlockingType::MAY_BLOCK); // Data a = GetDataFromMemoryCacheOrNetwork(); // Data b = GetDataFromMemoryCacheOrNetwork(); // CPUIntensiveProcessing(a); // CPU usage within a ScopedBlockingCall. // CPUIntensiveProcessing(b); // CPU usage within a ScopedBlockingCall. // // Good: // base::WaitableEvent waitable_event(...); // waitable_event.Wait(); // // Bad: // base::WaitableEvent waitable_event(...); // ScopedBlockingCall scoped_blocking_call( // FROM_HERE, BlockingType::WILL_BLOCK); // waitable_event.Wait(); // Wait() instantiates its own ScopedBlockingCall. // // When a ScopedBlockingCall is instantiated from a ThreadPool parallel or // sequenced task, the thread pool size is incremented to compensate for the // blocked thread (more or less aggressively depending on BlockingType). class BASE_EXPORT [[nodiscard]] ScopedBlockingCall : public internal::UncheckedScopedBlockingCall { public: ScopedBlockingCall(const Location& from_here, BlockingType blocking_type); ~ScopedBlockingCall(); }; // Usage reserved for //base callers. namespace internal { // This class must be instantiated in every scope where a sync primitive is // used. When a ScopedBlockingCallWithBaseSyncPrimitives is instantiated, it // asserts that sync primitives are allowed in its scope with a call to // internal::AssertBaseSyncPrimitivesAllowed(). The same guidelines as for // ScopedBlockingCall should be followed. class BASE_EXPORT [[nodiscard]] ScopedBlockingCallWithBaseSyncPrimitives : public UncheckedScopedBlockingCall { public: ScopedBlockingCallWithBaseSyncPrimitives(const Location& from_here, BlockingType blocking_type); ~ScopedBlockingCallWithBaseSyncPrimitives(); }; } // namespace internal using IOJankReportingCallback = RepeatingCallback; using OnlyObservedThreadsForTest = StrongAlias; // Enables IO jank monitoring and reporting for this process. Should be called // at most once per process and only if // base::TimeTicks::IsConsistentAcrossProcesses() (the algorithm is unsafe // otherwise). |reporting_callback| will be invoked each time a monitoring // window completes, see internal::~IOJankMonitoringWindow() for details // (must be thread-safe). |only_observed_threads| can be set to true to have // the IOJank implementation ignore ScopedBlockingCalls on threads without a // BlockingObserver in tests that need to deterministically observe // ScopedBlockingCall side-effects. void BASE_EXPORT EnableIOJankMonitoringForProcess( IOJankReportingCallback reporting_callback, OnlyObservedThreadsForTest only_observed_threads = OnlyObservedThreadsForTest(false)); } // namespace base #endif // BASE_THREADING_SCOPED_BLOCKING_CALL_H_