Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2009 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 "chrome/browser/browser_main.h" | 5 #include "chrome/browser/browser_main.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "app/hi_res_timer_manager.h" | 9 #include "app/hi_res_timer_manager.h" |
| 10 #include "app/l10n_util.h" | 10 #include "app/l10n_util.h" |
| 11 #include "app/resource_bundle.h" | 11 #include "app/resource_bundle.h" |
| 12 #include "app/system_monitor.h" | 12 #include "app/system_monitor.h" |
| 13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 14 #include "base/field_trial.h" | 14 #include "base/field_trial.h" |
| 15 #include "base/file_util.h" | 15 #include "base/file_util.h" |
| 16 #include "base/histogram.h" | 16 #include "base/histogram.h" |
| 17 #include "base/lazy_instance.h" | 17 #include "base/lazy_instance.h" |
| 18 #include "base/scoped_nsautorelease_pool.h" | 18 #include "base/scoped_nsautorelease_pool.h" |
| 19 #include "base/path_service.h" | 19 #include "base/path_service.h" |
| 20 #include "base/platform_thread.h" | |
| 20 #include "base/process_util.h" | 21 #include "base/process_util.h" |
| 21 #include "base/string_piece.h" | 22 #include "base/string_piece.h" |
| 22 #include "base/string_util.h" | 23 #include "base/string_util.h" |
| 23 #include "base/sys_string_conversions.h" | 24 #include "base/sys_string_conversions.h" |
| 24 #include "base/time.h" | 25 #include "base/time.h" |
| 25 #include "base/tracked_objects.h" | 26 #include "base/tracked_objects.h" |
| 26 #include "base/values.h" | 27 #include "base/values.h" |
| 27 #include "chrome/browser/browser_main_win.h" | 28 #include "chrome/browser/browser_main_win.h" |
| 28 #include "chrome/browser/browser_init.h" | 29 #include "chrome/browser/browser_init.h" |
| 29 #include "chrome/browser/browser_list.h" | 30 #include "chrome/browser/browser_list.h" |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 65 #include "net/base/net_module.h" | 66 #include "net/base/net_module.h" |
| 66 #include "net/http/http_network_session.h" | 67 #include "net/http/http_network_session.h" |
| 67 #include "net/socket/client_socket_pool_base.h" | 68 #include "net/socket/client_socket_pool_base.h" |
| 68 | 69 |
| 69 #if defined(OS_POSIX) | 70 #if defined(OS_POSIX) |
| 70 // TODO(port): get rid of this include. It's used just to provide declarations | 71 // TODO(port): get rid of this include. It's used just to provide declarations |
| 71 // and stub definitions for classes we encouter during the porting effort. | 72 // and stub definitions for classes we encouter during the porting effort. |
| 72 #include <errno.h> | 73 #include <errno.h> |
| 73 #include <signal.h> | 74 #include <signal.h> |
| 74 #include <sys/resource.h> | 75 #include <sys/resource.h> |
| 76 #include "base/eintr_wrapper.h" | |
| 75 #endif | 77 #endif |
| 76 | 78 |
| 77 #if defined(USE_LINUX_BREAKPAD) | 79 #if defined(USE_LINUX_BREAKPAD) |
| 78 #include "base/linux_util.h" | 80 #include "base/linux_util.h" |
| 79 #include "chrome/app/breakpad_linux.h" | 81 #include "chrome/app/breakpad_linux.h" |
| 80 #endif | 82 #endif |
| 81 | 83 |
| 82 #if defined(OS_LINUX) | 84 #if defined(OS_LINUX) |
| 83 #include "chrome/common/gtk_util.h" | 85 #include "chrome/common/gtk_util.h" |
| 84 #endif | 86 #endif |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 161 #elif defined(OS_POSIX) | 163 #elif defined(OS_POSIX) |
| 162 MessageLoopForUI::current()->Run(); | 164 MessageLoopForUI::current()->Run(); |
| 163 #endif | 165 #endif |
| 164 } | 166 } |
| 165 | 167 |
| 166 #if defined(OS_POSIX) | 168 #if defined(OS_POSIX) |
| 167 // See comment in BrowserMain, where sigaction is called. | 169 // See comment in BrowserMain, where sigaction is called. |
| 168 void SIGCHLDHandler(int signal) { | 170 void SIGCHLDHandler(int signal) { |
| 169 } | 171 } |
| 170 | 172 |
| 173 int g_shutdown_pipe_write_fd = -1; | |
| 174 int g_shutdown_pipe_read_fd = -1; | |
| 175 | |
| 171 // Common code between SIG{HUP, INT, TERM}Handler. | 176 // Common code between SIG{HUP, INT, TERM}Handler. |
| 172 void GracefulShutdownHandler(int signal, const int expected_signal) { | 177 void GracefulShutdownHandler(int signal) { |
| 173 DCHECK_EQ(signal, expected_signal); | |
| 174 LOG(INFO) << "Addressing signal " << expected_signal << " on " | |
| 175 << PlatformThread::CurrentId(); | |
| 176 | |
| 177 bool posted = ChromeThread::PostTask( | |
| 178 ChromeThread::UI, FROM_HERE, | |
| 179 NewRunnableFunction(BrowserList::CloseAllBrowsersAndExit)); | |
| 180 | |
| 181 // Reinstall the default handler. We had one shot at graceful shutdown. | 178 // Reinstall the default handler. We had one shot at graceful shutdown. |
| 182 struct sigaction action; | 179 struct sigaction action; |
| 183 memset(&action, 0, sizeof(action)); | 180 memset(&action, 0, sizeof(action)); |
| 184 action.sa_handler = SIG_DFL; | 181 action.sa_handler = SIG_DFL; |
| 185 CHECK(sigaction(expected_signal, &action, NULL) == 0); | 182 CHECK(sigaction(signal, &action, NULL) == 0); |
| 186 | 183 |
| 187 if (posted) { | 184 RAW_CHECK(g_shutdown_pipe_write_fd != -1); |
| 188 LOG(INFO) << "Posted task to UI thread; resetting signal " | 185 RAW_CHECK(g_shutdown_pipe_read_fd != -1); |
| 189 << expected_signal << " handler"; | 186 size_t bytes_written = 0; |
| 190 } else { | 187 do { |
| 188 int rv = HANDLE_EINTR( | |
| 189 write(g_shutdown_pipe_write_fd, | |
| 190 reinterpret_cast<const char*>(&signal) + bytes_written, | |
| 191 sizeof(signal) - bytes_written)); | |
| 192 RAW_CHECK(rv >= 0); | |
| 193 bytes_written += rv; | |
| 194 } while (bytes_written < sizeof(signal)); | |
| 195 | |
| 196 RAW_LOG(INFO, | |
| 197 "Successfully wrote to shutdown pipe, resetting signal handler."); | |
| 198 } | |
| 199 | |
| 200 // See comment in BrowserMain, where sigaction is called. | |
| 201 void SIGHUPHandler(int signal) { | |
| 202 RAW_CHECK(signal == SIGHUP); | |
| 203 RAW_LOG(INFO, "Handling SIGHUP."); | |
| 204 GracefulShutdownHandler(signal); | |
| 205 } | |
| 206 | |
| 207 // See comment in BrowserMain, where sigaction is called. | |
| 208 void SIGINTHandler(int signal) { | |
| 209 RAW_CHECK(signal == SIGINT); | |
| 210 RAW_LOG(INFO, "Handling SIGINT."); | |
| 211 GracefulShutdownHandler(signal); | |
| 212 } | |
| 213 | |
| 214 // See comment in BrowserMain, where sigaction is called. | |
| 215 void SIGTERMHandler(int signal) { | |
| 216 RAW_CHECK(signal == SIGTERM); | |
| 217 RAW_LOG(INFO, "Handling SIGTERM."); | |
| 218 GracefulShutdownHandler(signal); | |
| 219 } | |
| 220 | |
| 221 class ShutdownDetector : public PlatformThread::Delegate { | |
| 222 public: | |
| 223 explicit ShutdownDetector(int shutdown_fd); | |
| 224 | |
| 225 virtual void ThreadMain(); | |
| 226 | |
| 227 private: | |
| 228 const int shutdown_fd_; | |
| 229 | |
| 230 DISALLOW_COPY_AND_ASSIGN(ShutdownDetector); | |
| 231 }; | |
| 232 | |
| 233 ShutdownDetector::ShutdownDetector(int shutdown_fd) | |
| 234 : shutdown_fd_(shutdown_fd) { | |
| 235 CHECK(shutdown_fd_ != -1); | |
| 236 } | |
| 237 | |
| 238 void ShutdownDetector::ThreadMain() { | |
| 239 int signal; | |
| 240 size_t bytes_read = 0; | |
| 241 ssize_t ret; | |
| 242 do { | |
| 243 ret = HANDLE_EINTR( | |
| 244 read(shutdown_fd_, | |
| 245 reinterpret_cast<char*>(&signal) + bytes_read, | |
| 246 sizeof(signal) - bytes_read)); | |
| 247 if (ret < 0) { | |
| 248 NOTREACHED() << "Unexpected error: " << strerror(errno); | |
| 249 break; | |
| 250 } else if (ret == 0) { | |
| 251 NOTREACHED() << "Unexpected closure of shutdown pipe."; | |
| 252 break; | |
| 253 } | |
| 254 bytes_read += ret; | |
| 255 } while (bytes_read < sizeof(signal)); | |
| 256 | |
| 257 LOG(INFO) << "Handling shutdown for signal " << signal << "."; | |
| 258 | |
| 259 if (!ChromeThread::PostTask( | |
| 260 ChromeThread::UI, FROM_HERE, | |
| 261 NewRunnableFunction(BrowserList::CloseAllBrowsersAndExit))) { | |
| 191 // Without a UI thread to post the exit task to, there aren't many | 262 // Without a UI thread to post the exit task to, there aren't many |
| 192 // options. Raise the signal again. The default handler will pick it up | 263 // options. Raise the signal again. The default handler will pick it up |
| 193 // and cause an ungraceful exit. | 264 // and cause an ungraceful exit. |
| 194 LOG(WARNING) << "No UI thread, exiting ungracefully"; | 265 LOG(WARNING) << "No UI thread, exiting ungracefully."; |
| 195 kill(getpid(), signal); | 266 kill(getpid(), signal); |
| 196 | 267 |
| 197 // The signal may be handled on another thread. Give that a chance to | 268 // The signal may be handled on another thread. Give that a chance to |
| 198 // happen. | 269 // happen. |
| 199 sleep(3); | 270 sleep(3); |
| 200 | 271 |
| 201 // We really should be dead by now. For whatever reason, we're not. Exit | 272 // We really should be dead by now. For whatever reason, we're not. Exit |
| 202 // immediately, with the exit status set to the signal number with bit 8 | 273 // immediately, with the exit status set to the signal number with bit 8 |
| 203 // set. On the systems that we care about, this exit status is what is | 274 // set. On the systems that we care about, this exit status is what is |
| 204 // normally used to indicate an exit by this signal's default handler. | 275 // normally used to indicate an exit by this signal's default handler. |
| 205 // This mechanism isn't a de jure standard, but even in the worst case, it | 276 // This mechanism isn't a de jure standard, but even in the worst case, it |
| 206 // should at least result in an immediate exit. | 277 // should at least result in an immediate exit. |
| 207 LOG(WARNING) << "Still here, exiting really ungracefully"; | 278 LOG(WARNING) << "Still here, exiting really ungracefully."; |
| 208 _exit(signal | (1 << 7)); | 279 _exit(signal | (1 << 7)); |
| 209 } | 280 } |
| 210 } | 281 } |
| 211 | 282 |
| 212 // See comment in BrowserMain, where sigaction is called. | |
| 213 void SIGHUPHandler(int signal) { | |
| 214 GracefulShutdownHandler(signal, SIGHUP); | |
| 215 } | |
| 216 | |
| 217 // See comment in BrowserMain, where sigaction is called. | |
| 218 void SIGINTHandler(int signal) { | |
| 219 GracefulShutdownHandler(signal, SIGINT); | |
| 220 } | |
| 221 | |
| 222 // See comment in BrowserMain, where sigaction is called. | |
| 223 void SIGTERMHandler(int signal) { | |
| 224 GracefulShutdownHandler(signal, SIGTERM); | |
| 225 } | |
| 226 | |
| 227 // Sets the file descriptor soft limit to |max_descriptors| or the OS hard | 283 // Sets the file descriptor soft limit to |max_descriptors| or the OS hard |
| 228 // limit, whichever is lower. | 284 // limit, whichever is lower. |
| 229 void SetFileDescriptorLimit(unsigned int max_descriptors) { | 285 void SetFileDescriptorLimit(unsigned int max_descriptors) { |
| 230 struct rlimit limits; | 286 struct rlimit limits; |
| 231 if (getrlimit(RLIMIT_NOFILE, &limits) == 0) { | 287 if (getrlimit(RLIMIT_NOFILE, &limits) == 0) { |
| 232 unsigned int new_limit = max_descriptors; | 288 unsigned int new_limit = max_descriptors; |
| 233 if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) { | 289 if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) { |
| 234 new_limit = limits.rlim_max; | 290 new_limit = limits.rlim_max; |
| 235 } | 291 } |
| 236 limits.rlim_cur = new_limit; | 292 limits.rlim_cur = new_limit; |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 355 std::wstring app_name = chrome::kBrowserAppName; | 411 std::wstring app_name = chrome::kBrowserAppName; |
| 356 std::string thread_name_string = WideToASCII(app_name + L"_BrowserMain"); | 412 std::string thread_name_string = WideToASCII(app_name + L"_BrowserMain"); |
| 357 | 413 |
| 358 const char* thread_name = thread_name_string.c_str(); | 414 const char* thread_name = thread_name_string.c_str(); |
| 359 PlatformThread::SetName(thread_name); | 415 PlatformThread::SetName(thread_name); |
| 360 main_message_loop.set_thread_name(thread_name); | 416 main_message_loop.set_thread_name(thread_name); |
| 361 | 417 |
| 362 // Register the main thread by instantiating it, but don't call any methods. | 418 // Register the main thread by instantiating it, but don't call any methods. |
| 363 ChromeThread main_thread(ChromeThread::UI, MessageLoop::current()); | 419 ChromeThread main_thread(ChromeThread::UI, MessageLoop::current()); |
| 364 | 420 |
| 421 #if defined(OS_POSIX) | |
| 422 int pipefd[2]; | |
| 423 int ret = pipe(pipefd); | |
| 424 if (ret < 0) { | |
| 425 PLOG(DFATAL) << "Failed to create pipe"; | |
| 426 } else { | |
| 427 g_shutdown_pipe_read_fd = pipefd[0]; | |
| 428 g_shutdown_pipe_write_fd = pipefd[1]; | |
| 429 const size_t kShutdownDetectorThreadStackSize = 4096; | |
| 430 if (!PlatformThread::CreateNonJoinable( | |
| 431 kShutdownDetectorThreadStackSize, | |
| 432 new ShutdownDetector(g_shutdown_pipe_read_fd))) { | |
|
Hironori Bono
2009/12/08 09:44:53
I'm wondering when this ShutdownDetector instance
| |
| 433 LOG(DFATAL) << "Failed to create shutdown detector task."; | |
| 434 } | |
| 435 } | |
| 436 #endif // defined(OS_POSIX) | |
| 437 | |
| 365 FilePath user_data_dir; | 438 FilePath user_data_dir; |
| 366 #if defined(OS_WIN) | 439 #if defined(OS_WIN) |
| 367 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); | 440 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); |
| 368 #else | 441 #else |
| 369 // Getting the user data dir can fail if the directory isn't | 442 // Getting the user data dir can fail if the directory isn't |
| 370 // creatable, for example; on Windows in code below we bring up a | 443 // creatable, for example; on Windows in code below we bring up a |
| 371 // dialog prompting the user to pick a different directory. | 444 // dialog prompting the user to pick a different directory. |
| 372 // However, ProcessSingleton needs a real user_data_dir on Mac/Linux, | 445 // However, ProcessSingleton needs a real user_data_dir on Mac/Linux, |
| 373 // so it's better to fail here than fail mysteriously elsewhere. | 446 // so it's better to fail here than fail mysteriously elsewhere. |
| 374 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) | 447 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) |
| (...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 898 if (metrics) | 971 if (metrics) |
| 899 metrics->Stop(); | 972 metrics->Stop(); |
| 900 | 973 |
| 901 // browser_shutdown takes care of deleting browser_process, so we need to | 974 // browser_shutdown takes care of deleting browser_process, so we need to |
| 902 // release it. | 975 // release it. |
| 903 browser_process.release(); | 976 browser_process.release(); |
| 904 browser_shutdown::Shutdown(); | 977 browser_shutdown::Shutdown(); |
| 905 | 978 |
| 906 return result_code; | 979 return result_code; |
| 907 } | 980 } |
| OLD | NEW |