xref: /aosp_15_r20/external/cronet/base/threading/scoped_blocking_call.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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