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