| 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 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 #elif defined(OS_POSIX) | 164 #elif defined(OS_POSIX) |
| 163 MessageLoopForUI::current()->Run(); | 165 MessageLoopForUI::current()->Run(); |
| 164 #endif | 166 #endif |
| 165 } | 167 } |
| 166 | 168 |
| 167 #if defined(OS_POSIX) | 169 #if defined(OS_POSIX) |
| 168 // See comment in BrowserMain, where sigaction is called. | 170 // See comment in BrowserMain, where sigaction is called. |
| 169 void SIGCHLDHandler(int signal) { | 171 void SIGCHLDHandler(int signal) { |
| 170 } | 172 } |
| 171 | 173 |
| 174 int g_shutdown_pipe_write_fd = -1; |
| 175 int g_shutdown_pipe_read_fd = -1; |
| 176 |
| 172 // Common code between SIG{HUP, INT, TERM}Handler. | 177 // Common code between SIG{HUP, INT, TERM}Handler. |
| 173 void GracefulShutdownHandler(int signal, const int expected_signal) { | 178 void GracefulShutdownHandler(int signal) { |
| 174 DCHECK_EQ(signal, expected_signal); | |
| 175 LOG(INFO) << "Addressing signal " << expected_signal << " on " | |
| 176 << PlatformThread::CurrentId(); | |
| 177 | |
| 178 bool posted = ChromeThread::PostTask( | |
| 179 ChromeThread::UI, FROM_HERE, | |
| 180 NewRunnableFunction(BrowserList::CloseAllBrowsersAndExit)); | |
| 181 | |
| 182 // Reinstall the default handler. We had one shot at graceful shutdown. | 179 // Reinstall the default handler. We had one shot at graceful shutdown. |
| 183 struct sigaction action; | 180 struct sigaction action; |
| 184 memset(&action, 0, sizeof(action)); | 181 memset(&action, 0, sizeof(action)); |
| 185 action.sa_handler = SIG_DFL; | 182 action.sa_handler = SIG_DFL; |
| 186 CHECK(sigaction(expected_signal, &action, NULL) == 0); | 183 CHECK(sigaction(signal, &action, NULL) == 0); |
| 187 | 184 |
| 188 if (posted) { | 185 RAW_CHECK(g_shutdown_pipe_write_fd != -1); |
| 189 LOG(INFO) << "Posted task to UI thread; resetting signal " | 186 RAW_CHECK(g_shutdown_pipe_read_fd != -1); |
| 190 << expected_signal << " handler"; | 187 size_t bytes_written = 0; |
| 191 } else { | 188 do { |
| 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))) { |
| 192 // Without a UI thread to post the exit task to, there aren't many | 263 // Without a UI thread to post the exit task to, there aren't many |
| 193 // options. Raise the signal again. The default handler will pick it up | 264 // options. Raise the signal again. The default handler will pick it up |
| 194 // and cause an ungraceful exit. | 265 // and cause an ungraceful exit. |
| 195 LOG(WARNING) << "No UI thread, exiting ungracefully"; | 266 LOG(WARNING) << "No UI thread, exiting ungracefully."; |
| 196 kill(getpid(), signal); | 267 kill(getpid(), signal); |
| 197 | 268 |
| 198 // The signal may be handled on another thread. Give that a chance to | 269 // The signal may be handled on another thread. Give that a chance to |
| 199 // happen. | 270 // happen. |
| 200 sleep(3); | 271 sleep(3); |
| 201 | 272 |
| 202 // We really should be dead by now. For whatever reason, we're not. Exit | 273 // We really should be dead by now. For whatever reason, we're not. Exit |
| 203 // immediately, with the exit status set to the signal number with bit 8 | 274 // immediately, with the exit status set to the signal number with bit 8 |
| 204 // set. On the systems that we care about, this exit status is what is | 275 // set. On the systems that we care about, this exit status is what is |
| 205 // normally used to indicate an exit by this signal's default handler. | 276 // normally used to indicate an exit by this signal's default handler. |
| 206 // This mechanism isn't a de jure standard, but even in the worst case, it | 277 // This mechanism isn't a de jure standard, but even in the worst case, it |
| 207 // should at least result in an immediate exit. | 278 // should at least result in an immediate exit. |
| 208 LOG(WARNING) << "Still here, exiting really ungracefully"; | 279 LOG(WARNING) << "Still here, exiting really ungracefully."; |
| 209 _exit(signal | (1 << 7)); | 280 _exit(signal | (1 << 7)); |
| 210 } | 281 } |
| 211 } | 282 } |
| 212 | 283 |
| 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 | |
| 228 // Sets the file descriptor soft limit to |max_descriptors| or the OS hard | 284 // Sets the file descriptor soft limit to |max_descriptors| or the OS hard |
| 229 // limit, whichever is lower. | 285 // limit, whichever is lower. |
| 230 void SetFileDescriptorLimit(unsigned int max_descriptors) { | 286 void SetFileDescriptorLimit(unsigned int max_descriptors) { |
| 231 struct rlimit limits; | 287 struct rlimit limits; |
| 232 if (getrlimit(RLIMIT_NOFILE, &limits) == 0) { | 288 if (getrlimit(RLIMIT_NOFILE, &limits) == 0) { |
| 233 unsigned int new_limit = max_descriptors; | 289 unsigned int new_limit = max_descriptors; |
| 234 if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) { | 290 if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) { |
| 235 new_limit = limits.rlim_max; | 291 new_limit = limits.rlim_max; |
| 236 } | 292 } |
| 237 limits.rlim_cur = new_limit; | 293 limits.rlim_cur = new_limit; |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 std::wstring app_name = chrome::kBrowserAppName; | 412 std::wstring app_name = chrome::kBrowserAppName; |
| 357 std::string thread_name_string = WideToASCII(app_name + L"_BrowserMain"); | 413 std::string thread_name_string = WideToASCII(app_name + L"_BrowserMain"); |
| 358 | 414 |
| 359 const char* thread_name = thread_name_string.c_str(); | 415 const char* thread_name = thread_name_string.c_str(); |
| 360 PlatformThread::SetName(thread_name); | 416 PlatformThread::SetName(thread_name); |
| 361 main_message_loop.set_thread_name(thread_name); | 417 main_message_loop.set_thread_name(thread_name); |
| 362 | 418 |
| 363 // Register the main thread by instantiating it, but don't call any methods. | 419 // Register the main thread by instantiating it, but don't call any methods. |
| 364 ChromeThread main_thread(ChromeThread::UI, MessageLoop::current()); | 420 ChromeThread main_thread(ChromeThread::UI, MessageLoop::current()); |
| 365 | 421 |
| 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 |
| 366 FilePath user_data_dir; | 439 FilePath user_data_dir; |
| 367 #if defined(OS_WIN) | 440 #if defined(OS_WIN) |
| 368 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); | 441 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); |
| 369 #else | 442 #else |
| 370 // Getting the user data dir can fail if the directory isn't | 443 // Getting the user data dir can fail if the directory isn't |
| 371 // creatable, for example; on Windows in code below we bring up a | 444 // creatable, for example; on Windows in code below we bring up a |
| 372 // dialog prompting the user to pick a different directory. | 445 // dialog prompting the user to pick a different directory. |
| 373 // However, ProcessSingleton needs a real user_data_dir on Mac/Linux, | 446 // However, ProcessSingleton needs a real user_data_dir on Mac/Linux, |
| 374 // so it's better to fail here than fail mysteriously elsewhere. | 447 // so it's better to fail here than fail mysteriously elsewhere. |
| 375 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) | 448 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) |
| (...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 919 if (metrics) | 992 if (metrics) |
| 920 metrics->Stop(); | 993 metrics->Stop(); |
| 921 | 994 |
| 922 // browser_shutdown takes care of deleting browser_process, so we need to | 995 // browser_shutdown takes care of deleting browser_process, so we need to |
| 923 // release it. | 996 // release it. |
| 924 browser_process.release(); | 997 browser_process.release(); |
| 925 browser_shutdown::Shutdown(); | 998 browser_shutdown::Shutdown(); |
| 926 | 999 |
| 927 return result_code; | 1000 return result_code; |
| 928 } | 1001 } |
| OLD | NEW |