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

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

Powered by Google App Engine
This is Rietveld 408576698