1 // Copyright 2017 The Chromium Authors. All rights reserved.
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/logging.h"
10 
11 namespace base {
12 
13 // BlockingType indicates the likelihood that a blocking call will actually
14 // block.
15 enum class BlockingType {
16   // The call might block (e.g. file I/O that might hit in memory cache).
17   MAY_BLOCK,
18   // The call will definitely block (e.g. cache already checked and now pinging
19   // server synchronously).
20   WILL_BLOCK
21 };
22 
23 namespace internal {
24 class BlockingObserver;
25 }
26 
27 // This class must be instantiated in every scope where a blocking call is made.
28 // CPU usage should be minimal within that scope. //base APIs that block
29 // instantiate their own ScopedBlockingCall; it is not necessary to instantiate
30 // another ScopedBlockingCall in the scope where these APIs are used.
31 //
32 // Good:
33 //   Data data;
34 //   {
35 //     ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
36 //     data = GetDataFromNetwork();
37 //   }
38 //   CPUIntensiveProcessing(data);
39 //
40 // Bad:
41 //   ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
42 //   Data data = GetDataFromNetwork();
43 //   CPUIntensiveProcessing(data);  // CPU usage within a ScopedBlockingCall.
44 //
45 // Good:
46 //   Data a;
47 //   Data b;
48 //   {
49 //     ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK);
50 //     a = GetDataFromMemoryCacheOrNetwork();
51 //     b = GetDataFromMemoryCacheOrNetwork();
52 //   }
53 //   CPUIntensiveProcessing(a);
54 //   CPUIntensiveProcessing(b);
55 //
56 // Bad:
57 //   ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK);
58 //   Data a = GetDataFromMemoryCacheOrNetwork();
59 //   Data b = GetDataFromMemoryCacheOrNetwork();
60 //   CPUIntensiveProcessing(a);  // CPU usage within a ScopedBlockingCall.
61 //   CPUIntensiveProcessing(b);  // CPU usage within a ScopedBlockingCall.
62 //
63 // Good:
64 //   base::WaitableEvent waitable_event(...);
65 //   waitable_event.Wait();
66 //
67 // Bad:
68 //  base::WaitableEvent waitable_event(...);
69 //  ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
70 //  waitable_event.Wait();  // Wait() instantiates its own ScopedBlockingCall.
71 //
72 // When a ScopedBlockingCall is instantiated from a TaskScheduler parallel or
73 // sequenced task, the thread pool size is incremented to compensate for the
74 // blocked thread (more or less aggressively depending on BlockingType).
75 class BASE_EXPORT ScopedBlockingCall {
76  public:
77   ScopedBlockingCall(BlockingType blocking_type);
78   ~ScopedBlockingCall();
79 
80  private:
81   internal::BlockingObserver* const blocking_observer_;
82 
83   // Previous ScopedBlockingCall instantiated on this thread.
84   ScopedBlockingCall* const previous_scoped_blocking_call_;
85 
86   // Whether the BlockingType of the current thread was WILL_BLOCK after this
87   // ScopedBlockingCall was instantiated.
88   const bool is_will_block_;
89 
90   DISALLOW_COPY_AND_ASSIGN(ScopedBlockingCall);
91 };
92 
93 namespace internal {
94 
95 // Interface for an observer to be informed when a thread enters or exits
96 // the scope of ScopedBlockingCall objects.
97 class BASE_EXPORT BlockingObserver {
98  public:
99   virtual ~BlockingObserver() = default;
100 
101   // Invoked when a ScopedBlockingCall is instantiated on the observed thread
102   // where there wasn't an existing ScopedBlockingCall.
103   virtual void BlockingStarted(BlockingType blocking_type) = 0;
104 
105   // Invoked when a WILL_BLOCK ScopedBlockingCall is instantiated on the
106   // observed thread where there was a MAY_BLOCK ScopedBlockingCall but not a
107   // WILL_BLOCK ScopedBlockingCall.
108   virtual void BlockingTypeUpgraded() = 0;
109 
110   // Invoked when the last ScopedBlockingCall on the observed thread is
111   // destroyed.
112   virtual void BlockingEnded() = 0;
113 };
114 
115 // Registers |blocking_observer| on the current thread. It is invalid to call
116 // this on a thread where there is an active ScopedBlockingCall.
117 BASE_EXPORT void SetBlockingObserverForCurrentThread(
118     BlockingObserver* blocking_observer);
119 
120 BASE_EXPORT void ClearBlockingObserverForTesting();
121 
122 // Unregisters the |blocking_observer| on the current thread within its scope.
123 // Used in TaskScheduler tests to prevent calls to //base sync primitives from
124 // affecting the thread pool capacity.
125 class BASE_EXPORT ScopedClearBlockingObserverForTesting {
126  public:
127   ScopedClearBlockingObserverForTesting();
128   ~ScopedClearBlockingObserverForTesting();
129 
130  private:
131   BlockingObserver* const blocking_observer_;
132 
133   DISALLOW_COPY_AND_ASSIGN(ScopedClearBlockingObserverForTesting);
134 };
135 
136 }  // namespace internal
137 
138 }  // namespace base
139 
140 #endif  // BASE_THREADING_SCOPED_BLOCKING_CALL_H
141