/src/brpc/src/butil/threading/thread_restrictions.h
Line | Count | Source |
1 | | // Copyright (c) 2012 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 BUTIL_THREADING_THREAD_RESTRICTIONS_H_ |
6 | | #define BUTIL_THREADING_THREAD_RESTRICTIONS_H_ |
7 | | |
8 | | #include "butil/base_export.h" |
9 | | #include "butil/basictypes.h" |
10 | | |
11 | | // See comment at top of thread_checker.h |
12 | | #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) |
13 | | #define ENABLE_THREAD_RESTRICTIONS 1 |
14 | | #else |
15 | | #define ENABLE_THREAD_RESTRICTIONS 0 |
16 | | #endif |
17 | | |
18 | | class AcceleratedPresenter; |
19 | | class BrowserProcessImpl; |
20 | | class HistogramSynchronizer; |
21 | | class MetricsService; |
22 | | class NativeBackendKWallet; |
23 | | class ScopedAllowWaitForLegacyWebViewApi; |
24 | | class TestingAutomationProvider; |
25 | | |
26 | | namespace browser_sync { |
27 | | class NonFrontendDataTypeController; |
28 | | class UIModelWorker; |
29 | | } |
30 | | namespace cc { |
31 | | class CompletionEvent; |
32 | | } |
33 | | namespace chromeos { |
34 | | class AudioMixerAlsa; |
35 | | class BlockingMethodCaller; |
36 | | namespace system { |
37 | | class StatisticsProviderImpl; |
38 | | } |
39 | | } |
40 | | namespace chrome_browser_net { |
41 | | class Predictor; |
42 | | } |
43 | | namespace content { |
44 | | class BrowserGpuChannelHostFactory; |
45 | | class BrowserShutdownProfileDumper; |
46 | | class BrowserTestBase; |
47 | | class GLHelper; |
48 | | class GpuChannelHost; |
49 | | class NestedMessagePumpAndroid; |
50 | | class RenderWidgetHelper; |
51 | | class ScopedAllowWaitForAndroidLayoutTests; |
52 | | class TextInputClientMac; |
53 | | } |
54 | | namespace dbus { |
55 | | class Bus; |
56 | | } |
57 | | namespace disk_cache { |
58 | | class BackendImpl; |
59 | | class InFlightIO; |
60 | | } |
61 | | namespace media { |
62 | | class AudioOutputController; |
63 | | } |
64 | | namespace net { |
65 | | class FileStreamPosix; |
66 | | class FileStreamWin; |
67 | | namespace internal { |
68 | | class AddressTrackerLinux; |
69 | | } |
70 | | } |
71 | | |
72 | | namespace remoting { |
73 | | class AutoThread; |
74 | | } |
75 | | |
76 | | namespace butil { |
77 | | |
78 | | namespace android { |
79 | | class JavaHandlerThread; |
80 | | } |
81 | | |
82 | | class SequencedWorkerPool; |
83 | | class SimpleThread; |
84 | | class Thread; |
85 | | class ThreadTestHelper; |
86 | | |
87 | | // Certain behavior is disallowed on certain threads. ThreadRestrictions helps |
88 | | // enforce these rules. Examples of such rules: |
89 | | // |
90 | | // * Do not do blocking IO (makes the thread janky) |
91 | | // * Do not access Singleton/LazyInstance (may lead to shutdown crashes) |
92 | | // |
93 | | // Here's more about how the protection works: |
94 | | // |
95 | | // 1) If a thread should not be allowed to make IO calls, mark it: |
96 | | // butil::ThreadRestrictions::SetIOAllowed(false); |
97 | | // By default, threads *are* allowed to make IO calls. |
98 | | // In Chrome browser code, IO calls should be proxied to the File thread. |
99 | | // |
100 | | // 2) If a function makes a call that will go out to disk, check whether the |
101 | | // current thread is allowed: |
102 | | // butil::ThreadRestrictions::AssertIOAllowed(); |
103 | | // |
104 | | // |
105 | | // Style tip: where should you put AssertIOAllowed checks? It's best |
106 | | // if you put them as close to the disk access as possible, at the |
107 | | // lowest level. This rule is simple to follow and helps catch all |
108 | | // callers. For example, if your function GoDoSomeBlockingDiskCall() |
109 | | // only calls other functions in Chrome and not fopen(), you should go |
110 | | // add the AssertIOAllowed checks in the helper functions. |
111 | | |
112 | | class BUTIL_EXPORT ThreadRestrictions { |
113 | | public: |
114 | | // Constructing a ScopedAllowIO temporarily allows IO for the current |
115 | | // thread. Doing this is almost certainly always incorrect. |
116 | | class BUTIL_EXPORT ScopedAllowIO { |
117 | | public: |
118 | 0 | ScopedAllowIO() { previous_value_ = SetIOAllowed(true); } |
119 | 0 | ~ScopedAllowIO() { SetIOAllowed(previous_value_); } |
120 | | private: |
121 | | // Whether IO is allowed when the ScopedAllowIO was constructed. |
122 | | bool previous_value_; |
123 | | |
124 | | DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO); |
125 | | }; |
126 | | |
127 | | // Constructing a ScopedAllowSingleton temporarily allows accessing for the |
128 | | // current thread. Doing this is almost always incorrect. |
129 | | class BUTIL_EXPORT ScopedAllowSingleton { |
130 | | public: |
131 | 0 | ScopedAllowSingleton() { previous_value_ = SetSingletonAllowed(true); } |
132 | 0 | ~ScopedAllowSingleton() { SetSingletonAllowed(previous_value_); } |
133 | | private: |
134 | | // Whether singleton use is allowed when the ScopedAllowSingleton was |
135 | | // constructed. |
136 | | bool previous_value_; |
137 | | |
138 | | DISALLOW_COPY_AND_ASSIGN(ScopedAllowSingleton); |
139 | | }; |
140 | | |
141 | | #if ENABLE_THREAD_RESTRICTIONS |
142 | | // Set whether the current thread to make IO calls. |
143 | | // Threads start out in the *allowed* state. |
144 | | // Returns the previous value. |
145 | | static bool SetIOAllowed(bool allowed); |
146 | | |
147 | | // Check whether the current thread is allowed to make IO calls, |
148 | | // and DCHECK if not. See the block comment above the class for |
149 | | // a discussion of where to add these checks. |
150 | | static void AssertIOAllowed(); |
151 | | |
152 | | // Set whether the current thread can use singletons. Returns the previous |
153 | | // value. |
154 | | static bool SetSingletonAllowed(bool allowed); |
155 | | |
156 | | // Check whether the current thread is allowed to use singletons (Singleton / |
157 | | // LazyInstance). DCHECKs if not. |
158 | | static void AssertSingletonAllowed(); |
159 | | |
160 | | // Disable waiting on the current thread. Threads start out in the *allowed* |
161 | | // state. Returns the previous value. |
162 | | static void DisallowWaiting(); |
163 | | |
164 | | // Check whether the current thread is allowed to wait, and DCHECK if not. |
165 | | static void AssertWaitAllowed(); |
166 | | #else |
167 | | // Inline the empty definitions of these functions so that they can be |
168 | | // compiled out. |
169 | | static bool SetIOAllowed(bool) { return true; } |
170 | | static void AssertIOAllowed() {} |
171 | | static bool SetSingletonAllowed(bool) { return true; } |
172 | | static void AssertSingletonAllowed() {} |
173 | | static void DisallowWaiting() {} |
174 | | static void AssertWaitAllowed() {} |
175 | | #endif |
176 | | |
177 | | private: |
178 | | // DO NOT ADD ANY OTHER FRIEND STATEMENTS, talk to jam or brettw first. |
179 | | // BEGIN ALLOWED USAGE. |
180 | | friend class content::BrowserShutdownProfileDumper; |
181 | | friend class content::BrowserTestBase; |
182 | | friend class content::NestedMessagePumpAndroid; |
183 | | friend class content::RenderWidgetHelper; |
184 | | friend class content::ScopedAllowWaitForAndroidLayoutTests; |
185 | | friend class ::HistogramSynchronizer; |
186 | | friend class ::ScopedAllowWaitForLegacyWebViewApi; |
187 | | friend class ::TestingAutomationProvider; |
188 | | friend class cc::CompletionEvent; |
189 | | friend class remoting::AutoThread; |
190 | | friend class MessagePumpDefault; |
191 | | friend class SequencedWorkerPool; |
192 | | friend class SimpleThread; |
193 | | friend class Thread; |
194 | | friend class ThreadTestHelper; |
195 | | friend class PlatformThread; |
196 | | friend class android::JavaHandlerThread; |
197 | | |
198 | | // END ALLOWED USAGE. |
199 | | // BEGIN USAGE THAT NEEDS TO BE FIXED. |
200 | | friend class ::chromeos::AudioMixerAlsa; // http://crbug.com/125206 |
201 | | friend class ::chromeos::BlockingMethodCaller; // http://crbug.com/125360 |
202 | | friend class ::chromeos::system::StatisticsProviderImpl; // http://crbug.com/125385 |
203 | | friend class browser_sync::NonFrontendDataTypeController; // http://crbug.com/19757 |
204 | | friend class browser_sync::UIModelWorker; // http://crbug.com/19757 |
205 | | friend class chrome_browser_net::Predictor; // http://crbug.com/78451 |
206 | | friend class |
207 | | content::BrowserGpuChannelHostFactory; // http://crbug.com/125248 |
208 | | friend class content::GLHelper; // http://crbug.com/125415 |
209 | | friend class content::GpuChannelHost; // http://crbug.com/125264 |
210 | | friend class content::TextInputClientMac; // http://crbug.com/121917 |
211 | | friend class dbus::Bus; // http://crbug.com/125222 |
212 | | friend class disk_cache::BackendImpl; // http://crbug.com/74623 |
213 | | friend class disk_cache::InFlightIO; // http://crbug.com/74623 |
214 | | friend class media::AudioOutputController; // http://crbug.com/120973 |
215 | | friend class net::FileStreamPosix; // http://crbug.com/115067 |
216 | | friend class net::FileStreamWin; // http://crbug.com/115067 |
217 | | friend class net::internal::AddressTrackerLinux; // http://crbug.com/125097 |
218 | | friend class ::AcceleratedPresenter; // http://crbug.com/125391 |
219 | | friend class ::BrowserProcessImpl; // http://crbug.com/125207 |
220 | | friend class ::MetricsService; // http://crbug.com/124954 |
221 | | friend class ::NativeBackendKWallet; // http://crbug.com/125331 |
222 | | // END USAGE THAT NEEDS TO BE FIXED. |
223 | | |
224 | | #if ENABLE_THREAD_RESTRICTIONS |
225 | | static bool SetWaitAllowed(bool allowed); |
226 | | #else |
227 | | static bool SetWaitAllowed(bool) { return true; } |
228 | | #endif |
229 | | |
230 | | // FIXME(gejun): ScopedAllowWait can't be accessed by SequencedWorkerPool::Inner |
231 | | // in gcc 3.4 (SequencedWorkerPool is a friend class) |
232 | | #if __GNUC__ == 3 |
233 | | public: |
234 | | #endif |
235 | | // Constructing a ScopedAllowWait temporarily allows waiting on the current |
236 | | // thread. Doing this is almost always incorrect, which is why we limit who |
237 | | // can use this through friend. If you find yourself needing to use this, find |
238 | | // another way. Talk to jam or brettw. |
239 | | class BUTIL_EXPORT ScopedAllowWait { |
240 | | public: |
241 | 0 | ScopedAllowWait() { previous_value_ = SetWaitAllowed(true); } |
242 | 0 | ~ScopedAllowWait() { SetWaitAllowed(previous_value_); } |
243 | | private: |
244 | | // Whether singleton use is allowed when the ScopedAllowWait was |
245 | | // constructed. |
246 | | bool previous_value_; |
247 | | |
248 | | DISALLOW_COPY_AND_ASSIGN(ScopedAllowWait); |
249 | | }; |
250 | | |
251 | | private: |
252 | | DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions); |
253 | | }; |
254 | | |
255 | | } // namespace butil |
256 | | |
257 | | #endif // BUTIL_THREADING_THREAD_RESTRICTIONS_H_ |