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

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

Issue 8477004: Have content/ create and destroy its own threads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix official build, avoid DCHECK in official Linux/ChromeOS builds. Created 9 years 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_main_loop.h ('k') | content/browser/browser_process_sub_thread.cc » ('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) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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_main_loop.h" 5 #include "content/browser/browser_main_loop.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
11 #include "base/metrics/field_trial.h" 11 #include "base/metrics/field_trial.h"
12 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
13 #include "base/threading/thread_restrictions.h" 13 #include "base/threading/thread_restrictions.h"
14 #include "content/browser/browser_thread_impl.h" 14 #include "content/browser/browser_thread_impl.h"
15 #include "content/browser/trace_controller.h" 15 #include "content/browser/trace_controller.h"
16 #include "content/common/hi_res_timer_manager.h" 16 #include "content/common/hi_res_timer_manager.h"
17 #include "content/common/sandbox_policy.h" 17 #include "content/common/sandbox_policy.h"
18 #include "content/public/browser/browser_main_parts.h" 18 #include "content/public/browser/browser_main_parts.h"
19 #include "content/public/browser/browser_shutdown.h"
19 #include "content/public/browser/content_browser_client.h" 20 #include "content/public/browser/content_browser_client.h"
20 #include "content/public/common/content_switches.h" 21 #include "content/public/common/content_switches.h"
21 #include "content/public/common/main_function_params.h" 22 #include "content/public/common/main_function_params.h"
22 #include "content/public/common/result_codes.h" 23 #include "content/public/common/result_codes.h"
23 #include "crypto/nss_util.h" 24 #include "crypto/nss_util.h"
24 #include "net/base/network_change_notifier.h" 25 #include "net/base/network_change_notifier.h"
25 #include "net/base/ssl_config_service.h" 26 #include "net/base/ssl_config_service.h"
26 #include "net/socket/client_socket_factory.h" 27 #include "net/socket/client_socket_factory.h"
27 #include "net/socket/tcp_client_socket.h" 28 #include "net/socket/tcp_client_socket.h"
28 29
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 GLibLogHandler, 139 GLibLogHandler,
139 NULL); 140 NULL);
140 } 141 }
141 } 142 }
142 #endif 143 #endif
143 144
144 } // namespace 145 } // namespace
145 146
146 namespace content { 147 namespace content {
147 148
149 // The currently-running BrowserMainLoop. There can be one or zero.
150 // This is stored to enable immediate shutdown when needed.
151 BrowserMainLoop* current_browser_main_loop = NULL;
152
153 // This is just to be able to keep ShutdownThreadsAndCleanUp out of
154 // the public interface of BrowserMainLoop.
155 class BrowserShutdownImpl {
156 public:
157 static void ImmediateShutdownAndExitProcess() {
158 DCHECK(current_browser_main_loop);
159 current_browser_main_loop->ShutdownThreadsAndCleanUp();
160
161 #if defined(OS_WIN)
162 // At this point the message loop is still running yet we've shut everything
163 // down. If any messages are processed we'll likely crash. Exit now.
164 ExitProcess(content::RESULT_CODE_NORMAL_EXIT);
165 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
166 _exit(content::RESULT_CODE_NORMAL_EXIT);
167 #else
168 NOTIMPLEMENTED();
169 #endif
170 }
171 };
172
173 void ImmediateShutdownAndExitProcess() {
174 BrowserShutdownImpl::ImmediateShutdownAndExitProcess();
175 }
148 176
149 // BrowserMainLoop construction / destructione ============================= 177 // BrowserMainLoop construction / destructione =============================
150 178
151 BrowserMainLoop::BrowserMainLoop(const content::MainFunctionParams& parameters) 179 BrowserMainLoop::BrowserMainLoop(const content::MainFunctionParams& parameters)
152 : parameters_(parameters), 180 : parameters_(parameters),
153 parsed_command_line_(parameters.command_line), 181 parsed_command_line_(parameters.command_line),
154 result_code_(content::RESULT_CODE_NORMAL_EXIT) { 182 result_code_(content::RESULT_CODE_NORMAL_EXIT) {
183 DCHECK(!current_browser_main_loop);
184 current_browser_main_loop = this;
155 #if defined(OS_WIN) 185 #if defined(OS_WIN)
156 OleInitialize(NULL); 186 OleInitialize(NULL);
157 #endif 187 #endif
158 } 188 }
159 189
160 BrowserMainLoop::~BrowserMainLoop() { 190 BrowserMainLoop::~BrowserMainLoop() {
191 DCHECK_EQ(this, current_browser_main_loop);
192 current_browser_main_loop = NULL;
161 #if defined(OS_WIN) 193 #if defined(OS_WIN)
162 OleUninitialize(); 194 OleUninitialize();
163 #endif 195 #endif
164 } 196 }
165 197
166 void BrowserMainLoop::Init() { 198 void BrowserMainLoop::Init() {
167 parts_.reset( 199 parts_.reset(
168 GetContentClient()->browser()->CreateBrowserMainParts(parameters_)); 200 GetContentClient()->browser()->CreateBrowserMainParts(parameters_));
169 } 201 }
170 202
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 system_message_window_.reset(new SystemMessageWindowWin); 287 system_message_window_.reset(new SystemMessageWindowWin);
256 #endif 288 #endif
257 289
258 if (parts_.get()) 290 if (parts_.get())
259 parts_->PostMainMessageLoopStart(); 291 parts_->PostMainMessageLoopStart();
260 } 292 }
261 293
262 void BrowserMainLoop::RunMainMessageLoopParts( 294 void BrowserMainLoop::RunMainMessageLoopParts(
263 bool* completed_main_message_loop) { 295 bool* completed_main_message_loop) {
264 if (parts_.get()) 296 if (parts_.get())
297 parts_->PreCreateThreads();
298
299 base::Thread::Options default_options;
300 base::Thread::Options io_message_loop_options;
301 io_message_loop_options.message_loop_type = MessageLoop::TYPE_IO;
302 base::Thread::Options ui_message_loop_options;
303 ui_message_loop_options.message_loop_type = MessageLoop::TYPE_UI;
304
305 // Start threads in the order they occur in the BrowserThread::ID
306 // enumeration, except for BrowserThread::UI which is the main
307 // thread.
308 //
309 // Must be size_t so we can increment it.
310 for (size_t thread_id = BrowserThread::UI + 1;
311 thread_id < BrowserThread::ID_COUNT;
312 ++thread_id) {
313 scoped_ptr<BrowserProcessSubThread>* thread_to_start = NULL;
314 base::Thread::Options* options = &default_options;
315
316 switch (thread_id) {
317 case BrowserThread::DB:
318 thread_to_start = &db_thread_;
319 break;
320 case BrowserThread::WEBKIT:
321 // For now, the WebKit thread in the browser is owned by
322 // ResourceDispatcherHost, not by the content framework. Until
323 // this is fixed, we don't start the thread but still call
324 // Pre/PostStartThread for the ID.
325 break;
326 case BrowserThread::FILE:
327 thread_to_start = &file_thread_;
328 #if defined(OS_WIN)
329 // On Windows, the FILE thread needs to be have a UI message loop
330 // which pumps messages in such a way that Google Update can
331 // communicate back to us.
332 options = &ui_message_loop_options;
333 #else
334 options = &io_message_loop_options;
335 #endif
336 break;
337 case BrowserThread::PROCESS_LAUNCHER:
338 thread_to_start = &process_launcher_thread_;
339 break;
340 case BrowserThread::CACHE:
341 thread_to_start = &cache_thread_;
342 options = &io_message_loop_options;
343 break;
344 case BrowserThread::IO:
345 thread_to_start = &io_thread_;
346 options = &io_message_loop_options;
347 break;
348 #if defined(OS_CHROMEOS)
349 case BrowserThread::WEB_SOCKET_PROXY:
350 thread_to_start = &web_socket_proxy_thread_;
351 options = &io_message_loop_options;
352 break;
353 #endif
354 case BrowserThread::UI:
355 case BrowserThread::ID_COUNT:
356 default:
357 NOTREACHED();
358 break;
359 }
360
361 BrowserThread::ID id = static_cast<BrowserThread::ID>(thread_id);
362
363 if (parts_.get())
364 parts_->PreStartThread(id);
365
366 if (thread_to_start) {
367 (*thread_to_start).reset(new BrowserProcessSubThread(id));
368 (*thread_to_start)->StartWithOptions(*options);
369 }
370
371 if (parts_.get())
372 parts_->PostStartThread(id);
373 }
374
375 if (parts_.get())
265 parts_->PreMainMessageLoopRun(); 376 parts_->PreMainMessageLoopRun();
266 377
267 TRACE_EVENT_BEGIN_ETW("BrowserMain:MESSAGE_LOOP", 0, ""); 378 TRACE_EVENT_BEGIN_ETW("BrowserMain:MESSAGE_LOOP", 0, "");
268 // If the UI thread blocks, the whole UI is unresponsive. 379 // If the UI thread blocks, the whole UI is unresponsive.
269 // Do not allow disk IO from the UI thread. 380 // Do not allow disk IO from the UI thread.
270 base::ThreadRestrictions::SetIOAllowed(false); 381 base::ThreadRestrictions::SetIOAllowed(false);
271 382
272 bool ran_main_loop = false; 383 bool ran_main_loop = false;
273 if (parts_.get()) 384 if (parts_.get())
274 ran_main_loop = parts_->MainMessageLoopRun(&result_code_); 385 ran_main_loop = parts_->MainMessageLoopRun(&result_code_);
275 386
276 if (!ran_main_loop) 387 if (!ran_main_loop)
277 MainMessageLoopRun(); 388 MainMessageLoopRun();
278 389
279 TRACE_EVENT_END_ETW("BrowserMain:MESSAGE_LOOP", 0, ""); 390 TRACE_EVENT_END_ETW("BrowserMain:MESSAGE_LOOP", 0, "");
280 391
281 if (completed_main_message_loop) 392 if (completed_main_message_loop)
282 *completed_main_message_loop = true; 393 *completed_main_message_loop = true;
283 394
395 ShutdownThreadsAndCleanUp();
396 }
397
398 void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
399 // Teardown may start in PostMainMessageLoopRun, and during teardown we
400 // need to be able to perform IO.
401 base::ThreadRestrictions::SetIOAllowed(true);
402 BrowserThread::PostTask(
403 BrowserThread::IO,
404 FROM_HERE,
405 NewRunnableFunction(&base::ThreadRestrictions::SetIOAllowed, true));
406
284 if (parts_.get()) 407 if (parts_.get())
285 parts_->PostMainMessageLoopRun(); 408 parts_->PostMainMessageLoopRun();
409
410 // Must be size_t so we can subtract from it.
411 for (size_t thread_id = BrowserThread::ID_COUNT - 1;
412 thread_id >= (BrowserThread::UI + 1);
413 --thread_id) {
414 // Find the thread object we want to stop. Looping over all valid
415 // BrowserThread IDs and DCHECKing on a missing case in the switch
416 // statement helps avoid a mismatch between this code and the
417 // BrowserThread::ID enumeration.
418 //
419 // The destruction order is the reverse order of occurrence in the
420 // BrowserThread::ID list. The rationale for the order is as
421 // follows (need to be filled in a bit):
422 //
423 // - (Not sure why the WEB_SOCKET_PROXY thread is stopped first.)
424 //
425 // - The IO thread is the only user of the CACHE thread.
426 //
427 // - The PROCESS_LAUNCHER thread must be stopped after IO in case
428 // the IO thread posted a task to terminate a process on the
429 // process launcher thread.
430 //
431 // - (Not sure why FILE needs to stop before WEBKIT.)
432 //
433 // - The WEBKIT thread (which currently is the responsibility of
434 // the embedder to stop, by destroying ResourceDispatcherHost
435 // before the DB thread is stopped)
436 //
437 // - (Not sure why DB stops last.)
438 scoped_ptr<BrowserProcessSubThread>* thread_to_stop = NULL;
439 switch (thread_id) {
440 case BrowserThread::DB:
441 thread_to_stop = &db_thread_;
442 break;
443 case BrowserThread::WEBKIT:
444 // For now, the WebKit thread in the browser is owned by
445 // ResourceDispatcherHost, not by the content framework. Until
446 // this is fixed, we don't stop the thread but still call
447 // Pre/PostStopThread for the ID.
448 break;
449 case BrowserThread::FILE:
450 thread_to_stop = &file_thread_;
451 break;
452 case BrowserThread::PROCESS_LAUNCHER:
453 thread_to_stop = &process_launcher_thread_;
454 break;
455 case BrowserThread::CACHE:
456 thread_to_stop = &cache_thread_;
457 break;
458 case BrowserThread::IO:
459 thread_to_stop = &io_thread_;
460 break;
461 #if defined(OS_CHROMEOS)
462 case BrowserThread::WEB_SOCKET_PROXY:
463 thread_to_stop = &web_socket_proxy_thread_;
464 break;
465 #endif
466 case BrowserThread::UI:
467 case BrowserThread::ID_COUNT:
468 default:
469 NOTREACHED();
470 break;
471 }
472
473 BrowserThread::ID id = static_cast<BrowserThread::ID>(thread_id);
474
475 if (parts_.get())
476 parts_->PreStopThread(id);
477 if (thread_to_stop)
478 thread_to_stop->reset();
479 if (parts_.get())
480 parts_->PostStopThread(id);
481 }
482
483 if (parts_.get())
484 parts_->PostDestroyThreads();
286 } 485 }
287 486
288 void BrowserMainLoop::InitializeMainThread() { 487 void BrowserMainLoop::InitializeMainThread() {
289 const char* kThreadName = "CrBrowserMain"; 488 const char* kThreadName = "CrBrowserMain";
290 base::PlatformThread::SetName(kThreadName); 489 base::PlatformThread::SetName(kThreadName);
291 main_message_loop_->set_thread_name(kThreadName); 490 main_message_loop_->set_thread_name(kThreadName);
292 491
293 // Register the main thread by instantiating it, but don't call any methods. 492 // Register the main thread by instantiating it, but don't call any methods.
294 main_thread_.reset(new BrowserThreadImpl(BrowserThread::UI, 493 main_thread_.reset(new BrowserThreadImpl(BrowserThread::UI,
295 MessageLoop::current())); 494 MessageLoop::current()));
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 MessageLoopForUI::current()->PostTask(FROM_HERE, parameters_.ui_task); 539 MessageLoopForUI::current()->PostTask(FROM_HERE, parameters_.ui_task);
341 540
342 #if defined(OS_MACOSX) 541 #if defined(OS_MACOSX)
343 MessageLoopForUI::current()->Run(); 542 MessageLoopForUI::current()->Run();
344 #else 543 #else
345 MessageLoopForUI::current()->RunWithDispatcher(NULL); 544 MessageLoopForUI::current()->RunWithDispatcher(NULL);
346 #endif 545 #endif
347 } 546 }
348 547
349 } // namespace content 548 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/browser_main_loop.h ('k') | content/browser/browser_process_sub_thread.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698