• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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