1 // Copyright 2017 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_THREADING_SCOPED_BLOCKING_CALL_H_ 6 #define BASE_THREADING_SCOPED_BLOCKING_CALL_H_ 7 8 #include "base/base_export.h" 9 #include "base/functional/callback_forward.h" 10 #include "base/location.h" 11 #include "base/threading/scoped_blocking_call_internal.h" 12 #include "base/types/strong_alias.h" 13 14 namespace base { 15 16 // A "blocking call" refers to any call that causes the calling thread to wait 17 // off-CPU. It includes but is not limited to calls that wait on synchronous 18 // file I/O operations: read or write a file from disk, interact with a pipe or 19 // a socket, rename or delete a file, enumerate files in a directory, etc. 20 // Acquiring a low contention lock is not considered a blocking call. 21 22 // BlockingType indicates the likelihood that a blocking call will actually 23 // block. 24 enum class BlockingType { 25 // The call might block (e.g. file I/O that might hit in memory cache). 26 MAY_BLOCK, 27 // The call will definitely block (e.g. cache already checked and now pinging 28 // server synchronously). 29 WILL_BLOCK 30 }; 31 32 // This class must be instantiated in every scope where a blocking call is made 33 // and serves as a precise annotation of the scope that may/will block for the 34 // scheduler. When a ScopedBlockingCall is instantiated, it asserts that 35 // blocking calls are allowed in its scope with a call to 36 // base::AssertBlockingAllowed(). CPU usage should be minimal within that scope. 37 // //base APIs that block instantiate their own ScopedBlockingCall; it is not 38 // necessary to instantiate another ScopedBlockingCall in the scope where these 39 // APIs are used. Nested ScopedBlockingCalls are supported (mostly a no-op 40 // except for WILL_BLOCK nested within MAY_BLOCK which will result in immediate 41 // WILL_BLOCK semantics). 42 // 43 // Good: 44 // Data data; 45 // { 46 // ScopedBlockingCall scoped_blocking_call( 47 // FROM_HERE, BlockingType::WILL_BLOCK); 48 // data = GetDataFromNetwork(); 49 // } 50 // CPUIntensiveProcessing(data); 51 // 52 // Bad: 53 // ScopedBlockingCall scoped_blocking_call(FROM_HERE, 54 // BlockingType::WILL_BLOCK); 55 // Data data = GetDataFromNetwork(); 56 // CPUIntensiveProcessing(data); // CPU usage within a ScopedBlockingCall. 57 // 58 // Good: 59 // Data a; 60 // Data b; 61 // { 62 // ScopedBlockingCall scoped_blocking_call( 63 // FROM_HERE, BlockingType::MAY_BLOCK); 64 // a = GetDataFromMemoryCacheOrNetwork(); 65 // b = GetDataFromMemoryCacheOrNetwork(); 66 // } 67 // CPUIntensiveProcessing(a); 68 // CPUIntensiveProcessing(b); 69 // 70 // Bad: 71 // ScopedBlockingCall scoped_blocking_call( 72 // FROM_HERE, BlockingType::MAY_BLOCK); 73 // Data a = GetDataFromMemoryCacheOrNetwork(); 74 // Data b = GetDataFromMemoryCacheOrNetwork(); 75 // CPUIntensiveProcessing(a); // CPU usage within a ScopedBlockingCall. 76 // CPUIntensiveProcessing(b); // CPU usage within a ScopedBlockingCall. 77 // 78 // Good: 79 // base::WaitableEvent waitable_event(...); 80 // waitable_event.Wait(); 81 // 82 // Bad: 83 // base::WaitableEvent waitable_event(...); 84 // ScopedBlockingCall scoped_blocking_call( 85 // FROM_HERE, BlockingType::WILL_BLOCK); 86 // waitable_event.Wait(); // Wait() instantiates its own ScopedBlockingCall. 87 // 88 // When a ScopedBlockingCall is instantiated from a ThreadPool parallel or 89 // sequenced task, the thread pool size is incremented to compensate for the 90 // blocked thread (more or less aggressively depending on BlockingType). 91 class BASE_EXPORT [[nodiscard]] ScopedBlockingCall 92 : public internal::UncheckedScopedBlockingCall { 93 public: 94 ScopedBlockingCall(const Location& from_here, BlockingType blocking_type); 95 ~ScopedBlockingCall(); 96 }; 97 98 // Usage reserved for //base callers. 99 namespace internal { 100 101 // This class must be instantiated in every scope where a sync primitive is 102 // used. When a ScopedBlockingCallWithBaseSyncPrimitives is instantiated, it 103 // asserts that sync primitives are allowed in its scope with a call to 104 // internal::AssertBaseSyncPrimitivesAllowed(). The same guidelines as for 105 // ScopedBlockingCall should be followed. 106 class BASE_EXPORT [[nodiscard]] ScopedBlockingCallWithBaseSyncPrimitives 107 : public UncheckedScopedBlockingCall { 108 public: 109 ScopedBlockingCallWithBaseSyncPrimitives(const Location& from_here, 110 BlockingType blocking_type); 111 ~ScopedBlockingCallWithBaseSyncPrimitives(); 112 }; 113 114 } // namespace internal 115 116 using IOJankReportingCallback = 117 RepeatingCallback<void(int janky_intervals_per_minute, 118 int total_janks_per_minute)>; 119 using OnlyObservedThreadsForTest = 120 StrongAlias<class OnlyObservedThreadsTag, bool>; 121 // Enables IO jank monitoring and reporting for this process. Should be called 122 // at most once per process and only if 123 // base::TimeTicks::IsConsistentAcrossProcesses() (the algorithm is unsafe 124 // otherwise). |reporting_callback| will be invoked each time a monitoring 125 // window completes, see internal::~IOJankMonitoringWindow() for details 126 // (must be thread-safe). |only_observed_threads| can be set to true to have 127 // the IOJank implementation ignore ScopedBlockingCalls on threads without a 128 // BlockingObserver in tests that need to deterministically observe 129 // ScopedBlockingCall side-effects. 130 void BASE_EXPORT EnableIOJankMonitoringForProcess( 131 IOJankReportingCallback reporting_callback, 132 OnlyObservedThreadsForTest only_observed_threads = 133 OnlyObservedThreadsForTest(false)); 134 135 } // namespace base 136 137 #endif // BASE_THREADING_SCOPED_BLOCKING_CALL_H_ 138