Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(413)

Side by Side Diff: content/browser/browser_thread_impl.cc

Issue 9124033: Hook up the SequencedWorkerPool to the browser thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/browser_thread_impl.h" 5 #include "content/browser/browser_thread_impl.h"
6 6
7 #include "base/atomicops.h" 7 #include "base/atomicops.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
11 #include "base/message_loop_proxy.h" 11 #include "base/message_loop_proxy.h"
12 #include "base/threading/sequenced_worker_pool.h"
12 #include "base/threading/thread_restrictions.h" 13 #include "base/threading/thread_restrictions.h"
13 14
14 namespace content { 15 namespace content {
15 16
16 namespace { 17 namespace {
17 18
18 // Friendly names for the well-known threads. 19 // Friendly names for the well-known threads.
19 static const char* g_browser_thread_names[BrowserThread::ID_COUNT] = { 20 static const char* g_browser_thread_names[BrowserThread::ID_COUNT] = {
20 "", // UI (name assembled in browser_main.cc). 21 "", // UI (name assembled in browser_main.cc).
21 "Chrome_DBThread", // DB 22 "Chrome_DBThread", // DB
22 "Chrome_WebKitThread", // WEBKIT_DEPRECATED 23 "Chrome_WebKitThread", // WEBKIT_DEPRECATED
23 "Chrome_FileThread", // FILE 24 "Chrome_FileThread", // FILE
24 "Chrome_FileUserBlockingThread", // FILE_USER_BLOCKING 25 "Chrome_FileUserBlockingThread", // FILE_USER_BLOCKING
25 "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER 26 "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER
26 "Chrome_CacheThread", // CACHE 27 "Chrome_CacheThread", // CACHE
27 "Chrome_IOThread", // IO 28 "Chrome_IOThread", // IO
28 #if defined(OS_CHROMEOS) 29 #if defined(OS_CHROMEOS)
29 "Chrome_WebSocketproxyThread", // WEB_SOCKET_PROXY 30 "Chrome_WebSocketproxyThread", // WEB_SOCKET_PROXY
30 #endif 31 #endif
31 }; 32 };
32 33
33 // This lock protects |g_browser_threads|. Do not read or modify that 34 struct BrowserThreadGlobals {
34 // array without holding this lock. Do not block while holding this 35 BrowserThreadGlobals()
35 // lock. 36 : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) {
36 base::LazyInstance<base::Lock, 37 memset(threads, 0,
37 base::LeakyLazyInstanceTraits<base::Lock> > 38 BrowserThread::ID_COUNT * sizeof(BrowserThreadImpl*));
38 g_lock = LAZY_INSTANCE_INITIALIZER; 39 memset(thread_delegates, 0,
40 BrowserThread::ID_COUNT * sizeof(BrowserThreadDelegate*));
41 }
39 42
40 // This array is protected by |g_lock|. The threads are not owned by this 43 // This lock protects |threads|. Do not read or modify that array
41 // array. Typically, the threads are owned on the UI thread by 44 // without holding this lock. Do not block while holding this lock.
42 // content::BrowserMainLoop. BrowserThreadImpl objects remove 45 base::Lock lock;
43 // themselves from this array upon destruction.
44 static BrowserThreadImpl* g_browser_threads[BrowserThread::ID_COUNT];
45 46
46 // Only atomic operations are used on this array. The delegates are 47 // This array is protected by |lock|. The threads are not owned by this
47 // not owned by this array, rather by whoever calls 48 // array. Typically, the threads are owned on the UI thread by
48 // BrowserThread::SetDelegate. 49 // content::BrowserMainLoop. BrowserThreadImpl objects remove themselves from
49 static BrowserThreadDelegate* g_browser_thread_delegates[ 50 // this array upon destruction.
50 BrowserThread::ID_COUNT]; 51 BrowserThreadImpl* threads[BrowserThread::ID_COUNT];
52
53 // Only atomic operations are used on this array. The delegates are not owned
54 // by this array, rather by whoever calls BrowserThread::SetDelegate.
55 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT];
56
57 // This pointer is deliberately leaked on shutdown. This allows the pool to
58 // implement "continue on shutdown" semantics.
59 base::SequencedWorkerPool* blocking_pool;
60 };
61
62 base::LazyInstance<BrowserThreadGlobals,
63 base::LeakyLazyInstanceTraits<BrowserThreadGlobals> >
64 g_globals = LAZY_INSTANCE_INITIALIZER;
51 65
52 } // namespace 66 } // namespace
53 67
54 BrowserThreadImpl::BrowserThreadImpl(ID identifier) 68 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
55 : Thread(g_browser_thread_names[identifier]), 69 : Thread(g_browser_thread_names[identifier]),
56 identifier_(identifier) { 70 identifier_(identifier) {
57 Initialize(); 71 Initialize();
58 } 72 }
59 73
60 BrowserThreadImpl::BrowserThreadImpl(ID identifier, 74 BrowserThreadImpl::BrowserThreadImpl(ID identifier,
61 MessageLoop* message_loop) 75 MessageLoop* message_loop)
62 : Thread(message_loop->thread_name().c_str()), 76 : Thread(message_loop->thread_name().c_str()),
63 identifier_(identifier) { 77 identifier_(identifier) {
64 set_message_loop(message_loop); 78 set_message_loop(message_loop);
65 Initialize(); 79 Initialize();
66 } 80 }
67 81
82 // static
83 void BrowserThreadImpl::ShutdownThreadPool() {
84 BrowserThreadGlobals& globals = g_globals.Get();
85 globals.blocking_pool->Shutdown();
86 }
87
68 void BrowserThreadImpl::Init() { 88 void BrowserThreadImpl::Init() {
89 BrowserThreadGlobals& globals = g_globals.Get();
90
69 using base::subtle::AtomicWord; 91 using base::subtle::AtomicWord;
70 AtomicWord* storage = 92 AtomicWord* storage =
71 reinterpret_cast<AtomicWord*>(&g_browser_thread_delegates[identifier_]); 93 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
72 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); 94 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
73 BrowserThreadDelegate* delegate = 95 BrowserThreadDelegate* delegate =
74 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); 96 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
75 if (delegate) 97 if (delegate)
76 delegate->Init(); 98 delegate->Init();
77 } 99 }
78 100
79 void BrowserThreadImpl::CleanUp() { 101 void BrowserThreadImpl::CleanUp() {
102 BrowserThreadGlobals& globals = g_globals.Get();
103
80 using base::subtle::AtomicWord; 104 using base::subtle::AtomicWord;
81 AtomicWord* storage = 105 AtomicWord* storage =
82 reinterpret_cast<AtomicWord*>(&g_browser_thread_delegates[identifier_]); 106 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
83 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); 107 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
84 BrowserThreadDelegate* delegate = 108 BrowserThreadDelegate* delegate =
85 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); 109 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
86 110
87 if (delegate) 111 if (delegate)
88 delegate->CleanUp(); 112 delegate->CleanUp();
89 } 113 }
90 114
91 void BrowserThreadImpl::Initialize() { 115 void BrowserThreadImpl::Initialize() {
92 base::AutoLock lock(g_lock.Get()); 116 BrowserThreadGlobals& globals = g_globals.Get();
117
118 base::AutoLock lock(globals.lock);
93 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); 119 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
94 DCHECK(g_browser_threads[identifier_] == NULL); 120 DCHECK(globals.threads[identifier_] == NULL);
95 g_browser_threads[identifier_] = this; 121 globals.threads[identifier_] = this;
96 } 122 }
97 123
98 BrowserThreadImpl::~BrowserThreadImpl() { 124 BrowserThreadImpl::~BrowserThreadImpl() {
99 // All Thread subclasses must call Stop() in the destructor. This is 125 // All Thread subclasses must call Stop() in the destructor. This is
100 // doubly important here as various bits of code check they are on 126 // doubly important here as various bits of code check they are on
101 // the right BrowserThread. 127 // the right BrowserThread.
102 Stop(); 128 Stop();
103 129
104 base::AutoLock lock(g_lock.Get()); 130 BrowserThreadGlobals& globals = g_globals.Get();
105 g_browser_threads[identifier_] = NULL; 131 base::AutoLock lock(globals.lock);
132 globals.threads[identifier_] = NULL;
106 #ifndef NDEBUG 133 #ifndef NDEBUG
107 // Double check that the threads are ordered correctly in the enumeration. 134 // Double check that the threads are ordered correctly in the enumeration.
108 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { 135 for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
109 DCHECK(!g_browser_threads[i]) << 136 DCHECK(!globals.threads[i]) <<
110 "Threads must be listed in the reverse order that they die"; 137 "Threads must be listed in the reverse order that they die";
111 } 138 }
112 #endif 139 #endif
113 } 140 }
114 141
115 // static 142 // static
116 bool BrowserThreadImpl::PostTaskHelper( 143 bool BrowserThreadImpl::PostTaskHelper(
117 BrowserThread::ID identifier, 144 BrowserThread::ID identifier,
118 const tracked_objects::Location& from_here, 145 const tracked_objects::Location& from_here,
119 const base::Closure& task, 146 const base::Closure& task,
120 int64 delay_ms, 147 int64 delay_ms,
121 bool nestable) { 148 bool nestable) {
122 DCHECK(identifier >= 0 && identifier < ID_COUNT); 149 DCHECK(identifier >= 0 && identifier < ID_COUNT);
123 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in 150 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
124 // order of lifetime. So no need to lock if we know that the other thread 151 // order of lifetime. So no need to lock if we know that the other thread
125 // outlives this one. 152 // outlives this one.
126 // Note: since the array is so small, ok to loop instead of creating a map, 153 // Note: since the array is so small, ok to loop instead of creating a map,
127 // which would require a lock because std::map isn't thread safe, defeating 154 // which would require a lock because std::map isn't thread safe, defeating
128 // the whole purpose of this optimization. 155 // the whole purpose of this optimization.
129 BrowserThread::ID current_thread; 156 BrowserThread::ID current_thread;
130 bool guaranteed_to_outlive_target_thread = 157 bool guaranteed_to_outlive_target_thread =
131 GetCurrentThreadIdentifier(&current_thread) && 158 GetCurrentThreadIdentifier(&current_thread) &&
132 current_thread <= identifier; 159 current_thread <= identifier;
133 160
161 BrowserThreadGlobals& globals = g_globals.Get();
134 if (!guaranteed_to_outlive_target_thread) 162 if (!guaranteed_to_outlive_target_thread)
135 g_lock.Get().Acquire(); 163 globals.lock.Acquire();
136 164
137 MessageLoop* message_loop = g_browser_threads[identifier] ? 165 MessageLoop* message_loop = globals.threads[identifier] ?
138 g_browser_threads[identifier]->message_loop() : NULL; 166 globals.threads[identifier]->message_loop() : NULL;
139 if (message_loop) { 167 if (message_loop) {
140 if (nestable) { 168 if (nestable) {
141 message_loop->PostDelayedTask(from_here, task, delay_ms); 169 message_loop->PostDelayedTask(from_here, task, delay_ms);
142 } else { 170 } else {
143 message_loop->PostNonNestableDelayedTask(from_here, task, delay_ms); 171 message_loop->PostNonNestableDelayedTask(from_here, task, delay_ms);
144 } 172 }
145 } 173 }
146 174
147 if (!guaranteed_to_outlive_target_thread) 175 if (!guaranteed_to_outlive_target_thread)
148 g_lock.Get().Release(); 176 globals.lock.Release();
149 177
150 return !!message_loop; 178 return !!message_loop;
151 } 179 }
152 180
153 // An implementation of MessageLoopProxy to be used in conjunction 181 // An implementation of MessageLoopProxy to be used in conjunction
154 // with BrowserThread. 182 // with BrowserThread.
155 class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy { 183 class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
156 public: 184 public:
157 explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier) 185 explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
158 : id_(identifier) { 186 : id_(identifier) {
(...skipping 26 matching lines...) Expand all
185 virtual bool BelongsToCurrentThread() { 213 virtual bool BelongsToCurrentThread() {
186 return BrowserThread::CurrentlyOn(id_); 214 return BrowserThread::CurrentlyOn(id_);
187 } 215 }
188 216
189 private: 217 private:
190 BrowserThread::ID id_; 218 BrowserThread::ID id_;
191 DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy); 219 DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy);
192 }; 220 };
193 221
194 // static 222 // static
195 bool BrowserThread::IsWellKnownThread(ID identifier) { 223 bool BrowserThread::PostBlockingPoolTask(
196 base::AutoLock lock(g_lock.Get()); 224 const tracked_objects::Location& from_here,
197 return (identifier >= 0 && identifier < ID_COUNT && 225 const base::Closure& task) {
198 g_browser_threads[identifier]); 226 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
199 } 227 }
200 228
201 // static 229 // static
230 bool BrowserThread::PostBlockingPoolSequencedTask(
231 const std::string& sequence_token_name,
232 const tracked_objects::Location& from_here,
233 const base::Closure& task) {
234 return g_globals.Get().blocking_pool->PostNamedSequencedWorkerTask(
235 sequence_token_name, from_here, task);
236 }
237
238 // static
239 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
240 return g_globals.Get().blocking_pool;
241 }
242
243 // static
244 bool BrowserThread::IsWellKnownThread(ID identifier) {
245 BrowserThreadGlobals& globals = g_globals.Get();
246 base::AutoLock lock(globals.lock);
247 return (identifier >= 0 && identifier < ID_COUNT &&
248 globals.threads[identifier]);
249 }
250
251 // static
202 bool BrowserThread::CurrentlyOn(ID identifier) { 252 bool BrowserThread::CurrentlyOn(ID identifier) {
203 // We shouldn't use MessageLoop::current() since it uses LazyInstance which 253 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
204 // may be deleted by ~AtExitManager when a WorkerPool thread calls this 254 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
205 // function. 255 // function.
206 // http://crbug.com/63678 256 // http://crbug.com/63678
207 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; 257 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
208 base::AutoLock lock(g_lock.Get()); 258 BrowserThreadGlobals& globals = g_globals.Get();
259 base::AutoLock lock(globals.lock);
209 DCHECK(identifier >= 0 && identifier < ID_COUNT); 260 DCHECK(identifier >= 0 && identifier < ID_COUNT);
210 return g_browser_threads[identifier] && 261 return globals.threads[identifier] &&
211 g_browser_threads[identifier]->message_loop() == 262 globals.threads[identifier]->message_loop() ==
212 MessageLoop::current(); 263 MessageLoop::current();
213 } 264 }
214 265
215 // static 266 // static
216 bool BrowserThread::IsMessageLoopValid(ID identifier) { 267 bool BrowserThread::IsMessageLoopValid(ID identifier) {
217 base::AutoLock lock(g_lock.Get()); 268 BrowserThreadGlobals& globals = g_globals.Get();
269 base::AutoLock lock(globals.lock);
218 DCHECK(identifier >= 0 && identifier < ID_COUNT); 270 DCHECK(identifier >= 0 && identifier < ID_COUNT);
219 return g_browser_threads[identifier] && 271 return globals.threads[identifier] &&
220 g_browser_threads[identifier]->message_loop(); 272 globals.threads[identifier]->message_loop();
221 } 273 }
222 274
223 // static 275 // static
224 bool BrowserThread::PostTask(ID identifier, 276 bool BrowserThread::PostTask(ID identifier,
225 const tracked_objects::Location& from_here, 277 const tracked_objects::Location& from_here,
226 const base::Closure& task) { 278 const base::Closure& task) {
227 return BrowserThreadImpl::PostTaskHelper( 279 return BrowserThreadImpl::PostTaskHelper(
228 identifier, from_here, task, 0, true); 280 identifier, from_here, task, 0, true);
229 } 281 }
230 282
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 } 320 }
269 321
270 // static 322 // static
271 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { 323 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
272 // We shouldn't use MessageLoop::current() since it uses LazyInstance which 324 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
273 // may be deleted by ~AtExitManager when a WorkerPool thread calls this 325 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
274 // function. 326 // function.
275 // http://crbug.com/63678 327 // http://crbug.com/63678
276 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; 328 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
277 MessageLoop* cur_message_loop = MessageLoop::current(); 329 MessageLoop* cur_message_loop = MessageLoop::current();
330 BrowserThreadGlobals& globals = g_globals.Get();
278 for (int i = 0; i < ID_COUNT; ++i) { 331 for (int i = 0; i < ID_COUNT; ++i) {
279 if (g_browser_threads[i] && 332 if (globals.threads[i] &&
280 g_browser_threads[i]->message_loop() == cur_message_loop) { 333 globals.threads[i]->message_loop() == cur_message_loop) {
281 *identifier = g_browser_threads[i]->identifier_; 334 *identifier = globals.threads[i]->identifier_;
282 return true; 335 return true;
283 } 336 }
284 } 337 }
285 338
286 return false; 339 return false;
287 } 340 }
288 341
289 // static 342 // static
290 scoped_refptr<base::MessageLoopProxy> 343 scoped_refptr<base::MessageLoopProxy>
291 BrowserThread::GetMessageLoopProxyForThread( 344 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
292 ID identifier) {
293 scoped_refptr<base::MessageLoopProxy> proxy( 345 scoped_refptr<base::MessageLoopProxy> proxy(
294 new BrowserThreadMessageLoopProxy(identifier)); 346 new BrowserThreadMessageLoopProxy(identifier));
295 return proxy; 347 return proxy;
296 } 348 }
297 349
298 // static 350 // static
299 MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { 351 MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
300 base::AutoLock lock(g_lock.Get()); 352 BrowserThreadGlobals& globals = g_globals.Get();
301 base::Thread* thread = g_browser_threads[identifier]; 353 base::AutoLock lock(globals.lock);
354 base::Thread* thread = globals.threads[identifier];
302 DCHECK(thread); 355 DCHECK(thread);
303 MessageLoop* loop = thread->message_loop(); 356 MessageLoop* loop = thread->message_loop();
304 return loop; 357 return loop;
305 } 358 }
306 359
307 // static 360 // static
308 void BrowserThread::SetDelegate(ID identifier, 361 void BrowserThread::SetDelegate(ID identifier,
309 BrowserThreadDelegate* delegate) { 362 BrowserThreadDelegate* delegate) {
310 using base::subtle::AtomicWord; 363 using base::subtle::AtomicWord;
364 BrowserThreadGlobals& globals = g_globals.Get();
311 AtomicWord* storage = reinterpret_cast<AtomicWord*>( 365 AtomicWord* storage = reinterpret_cast<AtomicWord*>(
312 &g_browser_thread_delegates[identifier]); 366 &globals.thread_delegates[identifier]);
313 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( 367 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
314 storage, reinterpret_cast<AtomicWord>(delegate)); 368 storage, reinterpret_cast<AtomicWord>(delegate));
315 369
316 // This catches registration when previously registered. 370 // This catches registration when previously registered.
317 DCHECK(!delegate || !old_pointer); 371 DCHECK(!delegate || !old_pointer);
318 } 372 }
319 373
320 } // namespace content 374 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698