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