| 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" |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 MessageLoopForUI::current()->Run(); | 164 MessageLoopForUI::current()->Run(); |
| 165 #endif | 165 #endif |
| 166 } | 166 } |
| 167 | 167 |
| 168 #if defined(OS_POSIX) | 168 #if defined(OS_POSIX) |
| 169 // See comment in BrowserMain, where sigaction is called. | 169 // See comment in BrowserMain, where sigaction is called. |
| 170 void SIGCHLDHandler(int signal) { | 170 void SIGCHLDHandler(int signal) { |
| 171 } | 171 } |
| 172 | 172 |
| 173 int g_shutdown_pipe_write_fd = -1; | 173 int g_shutdown_pipe_write_fd = -1; |
| 174 int g_shutdown_pipe_read_fd = -1; | |
| 175 | 174 |
| 176 // Common code between SIG{HUP, INT, TERM}Handler. | 175 // Common code between SIG{HUP, INT, TERM}Handler. |
| 177 void GracefulShutdownHandler(int signal) { | 176 void GracefulShutdownHandler(int signal) { |
| 178 // Reinstall the default handler. We had one shot at graceful shutdown. | 177 // Reinstall the default handler. We had one shot at graceful shutdown. |
| 179 struct sigaction action; | 178 struct sigaction action; |
| 180 memset(&action, 0, sizeof(action)); | 179 memset(&action, 0, sizeof(action)); |
| 181 action.sa_handler = SIG_DFL; | 180 action.sa_handler = SIG_DFL; |
| 182 CHECK(sigaction(signal, &action, NULL) == 0); | 181 CHECK(sigaction(signal, &action, NULL) == 0); |
| 183 | 182 |
| 184 RAW_CHECK(g_shutdown_pipe_write_fd != -1); | 183 RAW_CHECK(g_shutdown_pipe_write_fd != -1); |
| 185 RAW_CHECK(g_shutdown_pipe_read_fd != -1); | |
| 186 size_t bytes_written = 0; | 184 size_t bytes_written = 0; |
| 187 do { | 185 do { |
| 188 int rv = HANDLE_EINTR( | 186 int rv = HANDLE_EINTR( |
| 189 write(g_shutdown_pipe_write_fd, | 187 write(g_shutdown_pipe_write_fd, |
| 190 reinterpret_cast<const char*>(&signal) + bytes_written, | 188 reinterpret_cast<const char*>(&signal) + bytes_written, |
| 191 sizeof(signal) - bytes_written)); | 189 sizeof(signal) - bytes_written)); |
| 192 RAW_CHECK(rv >= 0); | 190 RAW_CHECK(rv >= 0); |
| 193 bytes_written += rv; | 191 bytes_written += rv; |
| 194 } while (bytes_written < sizeof(signal)); | 192 } while (bytes_written < sizeof(signal)); |
| 195 | 193 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 ssize_t ret; | 239 ssize_t ret; |
| 242 do { | 240 do { |
| 243 ret = HANDLE_EINTR( | 241 ret = HANDLE_EINTR( |
| 244 read(shutdown_fd_, | 242 read(shutdown_fd_, |
| 245 reinterpret_cast<char*>(&signal) + bytes_read, | 243 reinterpret_cast<char*>(&signal) + bytes_read, |
| 246 sizeof(signal) - bytes_read)); | 244 sizeof(signal) - bytes_read)); |
| 247 if (ret < 0) { | 245 if (ret < 0) { |
| 248 NOTREACHED() << "Unexpected error: " << strerror(errno); | 246 NOTREACHED() << "Unexpected error: " << strerror(errno); |
| 249 break; | 247 break; |
| 250 } else if (ret == 0) { | 248 } else if (ret == 0) { |
| 251 NOTREACHED() << "Unexpected closure of shutdown pipe."; | 249 // Normal shutdown. |
| 252 break; | 250 break; |
| 253 } | 251 } |
| 254 bytes_read += ret; | 252 bytes_read += ret; |
| 255 } while (bytes_read < sizeof(signal)); | 253 } while (bytes_read < sizeof(signal)); |
| 256 | 254 |
| 257 LOG(INFO) << "Handling shutdown for signal " << signal << "."; | 255 if (bytes_read == sizeof(signal)) { |
| 256 LOG(INFO) << "Handling shutdown for signal " << signal << "."; |
| 258 | 257 |
| 259 if (!ChromeThread::PostTask( | 258 if (!ChromeThread::PostTask( |
| 260 ChromeThread::UI, FROM_HERE, | 259 ChromeThread::UI, FROM_HERE, |
| 261 NewRunnableFunction(BrowserList::CloseAllBrowsersAndExit))) { | 260 NewRunnableFunction(BrowserList::CloseAllBrowsersAndExit))) { |
| 262 // Without a UI thread to post the exit task to, there aren't many | 261 // Without a UI thread to post the exit task to, there aren't many |
| 263 // options. Raise the signal again. The default handler will pick it up | 262 // options. Raise the signal again. The default handler will pick it up |
| 264 // and cause an ungraceful exit. | 263 // and cause an ungraceful exit. |
| 265 LOG(WARNING) << "No UI thread, exiting ungracefully."; | 264 LOG(WARNING) << "No UI thread, exiting ungracefully."; |
| 266 kill(getpid(), signal); | 265 PLOG_IF(ERROR, raise(signal) != 0) << "Failed to raise signal"; |
| 267 | 266 |
| 268 // The signal may be handled on another thread. Give that a chance to | 267 // The signal may be handled on another thread. Give that a chance to |
| 269 // happen. | 268 // happen. |
| 270 sleep(3); | 269 sleep(3); |
| 271 | 270 |
| 272 // We really should be dead by now. For whatever reason, we're not. Exit | 271 // We really should be dead by now. For whatever reason, we're not. Exit |
| 273 // immediately, with the exit status set to the signal number with bit 8 | 272 // immediately, with the exit status set to the signal number with bit 8 |
| 274 // set. On the systems that we care about, this exit status is what is | 273 // set. On the systems that we care about, this exit status is what is |
| 275 // normally used to indicate an exit by this signal's default handler. | 274 // normally used to indicate an exit by this signal's default handler. |
| 276 // This mechanism isn't a de jure standard, but even in the worst case, it | 275 // This mechanism isn't a de jure standard, but even in the worst case, it |
| 277 // should at least result in an immediate exit. | 276 // should at least result in an immediate exit. |
| 278 LOG(WARNING) << "Still here, exiting really ungracefully."; | 277 LOG(WARNING) << "Still here, exiting really ungracefully."; |
| 279 _exit(signal | (1 << 7)); | 278 _exit(signal | (1 << 7)); |
| 279 } |
| 280 } | 280 } |
| 281 |
| 282 delete this; |
| 281 } | 283 } |
| 282 | 284 |
| 283 // Sets the file descriptor soft limit to |max_descriptors| or the OS hard | 285 // Sets the file descriptor soft limit to |max_descriptors| or the OS hard |
| 284 // limit, whichever is lower. | 286 // limit, whichever is lower. |
| 285 void SetFileDescriptorLimit(unsigned int max_descriptors) { | 287 void SetFileDescriptorLimit(unsigned int max_descriptors) { |
| 286 struct rlimit limits; | 288 struct rlimit limits; |
| 287 if (getrlimit(RLIMIT_NOFILE, &limits) == 0) { | 289 if (getrlimit(RLIMIT_NOFILE, &limits) == 0) { |
| 288 unsigned int new_limit = max_descriptors; | 290 unsigned int new_limit = max_descriptors; |
| 289 if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) { | 291 if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) { |
| 290 new_limit = limits.rlim_max; | 292 new_limit = limits.rlim_max; |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 414 const char* thread_name = thread_name_string.c_str(); | 416 const char* thread_name = thread_name_string.c_str(); |
| 415 PlatformThread::SetName(thread_name); | 417 PlatformThread::SetName(thread_name); |
| 416 main_message_loop.set_thread_name(thread_name); | 418 main_message_loop.set_thread_name(thread_name); |
| 417 | 419 |
| 418 // Register the main thread by instantiating it, but don't call any methods. | 420 // Register the main thread by instantiating it, but don't call any methods. |
| 419 ChromeThread main_thread(ChromeThread::UI, MessageLoop::current()); | 421 ChromeThread main_thread(ChromeThread::UI, MessageLoop::current()); |
| 420 | 422 |
| 421 #if defined(OS_POSIX) | 423 #if defined(OS_POSIX) |
| 422 int pipefd[2]; | 424 int pipefd[2]; |
| 423 int ret = pipe(pipefd); | 425 int ret = pipe(pipefd); |
| 426 PlatformThreadHandle shutdown_detector_thread; |
| 424 if (ret < 0) { | 427 if (ret < 0) { |
| 425 PLOG(DFATAL) << "Failed to create pipe"; | 428 PLOG(DFATAL) << "Failed to create pipe"; |
| 426 } else { | 429 } else { |
| 427 g_shutdown_pipe_read_fd = pipefd[0]; | |
| 428 g_shutdown_pipe_write_fd = pipefd[1]; | |
| 429 const size_t kShutdownDetectorThreadStackSize = 4096; | 430 const size_t kShutdownDetectorThreadStackSize = 4096; |
| 430 if (!PlatformThread::CreateNonJoinable( | 431 if (PlatformThread::Create( |
| 431 kShutdownDetectorThreadStackSize, | 432 kShutdownDetectorThreadStackSize, |
| 432 new ShutdownDetector(g_shutdown_pipe_read_fd))) { | 433 new ShutdownDetector(pipefd[0]), |
| 434 &shutdown_detector_thread)) { |
| 435 // Successfully spawned shutdown detector thread. |
| 436 g_shutdown_pipe_write_fd = pipefd[1]; |
| 437 } else { |
| 433 LOG(DFATAL) << "Failed to create shutdown detector task."; | 438 LOG(DFATAL) << "Failed to create shutdown detector task."; |
| 439 ret = HANDLE_EINTR(close(pipefd[0])); |
| 440 PLOG_IF(ERROR, ret != 0) << "Failed to close shutdown read pipe"; |
| 441 ret = HANDLE_EINTR(close(pipefd[1])); |
| 442 PLOG_IF(ERROR, ret != 0) << "Failed to close shutdown write pipe"; |
| 434 } | 443 } |
| 435 } | 444 } |
| 436 #endif // defined(OS_POSIX) | 445 #endif // defined(OS_POSIX) |
| 437 | 446 |
| 438 FilePath user_data_dir; | 447 FilePath user_data_dir; |
| 439 #if defined(OS_WIN) | 448 #if defined(OS_WIN) |
| 440 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); | 449 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); |
| 441 #else | 450 #else |
| 442 // Getting the user data dir can fail if the directory isn't | 451 // Getting the user data dir can fail if the directory isn't |
| 443 // creatable, for example; on Windows in code below we bring up a | 452 // creatable, for example; on Windows in code below we bring up a |
| (...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 957 &result_code)) { | 966 &result_code)) { |
| 958 // Call Recycle() here as late as possible, before going into the loop | 967 // Call Recycle() here as late as possible, before going into the loop |
| 959 // because Start() will add things to it while creating the main window. | 968 // because Start() will add things to it while creating the main window. |
| 960 if (pool) | 969 if (pool) |
| 961 pool->Recycle(); | 970 pool->Recycle(); |
| 962 RunUIMessageLoop(browser_process.get()); | 971 RunUIMessageLoop(browser_process.get()); |
| 963 } | 972 } |
| 964 } | 973 } |
| 965 chrome_browser_net_websocket_experiment::WebSocketExperimentRunner::Stop(); | 974 chrome_browser_net_websocket_experiment::WebSocketExperimentRunner::Stop(); |
| 966 | 975 |
| 976 #if defined(OS_POSIX) |
| 977 // If we initialized the shutdown pipe, then close it. |
| 978 if (g_shutdown_pipe_write_fd != -1) { |
| 979 ret = HANDLE_EINTR(close(g_shutdown_pipe_write_fd)); |
| 980 g_shutdown_pipe_write_fd = -1; |
| 981 PLOG_IF(ERROR, ret != 0) << "Failed to close"; |
| 982 } |
| 983 #endif // defined(OS_POSIX) |
| 984 |
| 967 process_singleton.Cleanup(); | 985 process_singleton.Cleanup(); |
| 968 | 986 |
| 969 Platform::DidEndMainMessageLoop(); | 987 Platform::DidEndMainMessageLoop(); |
| 970 | 988 |
| 971 if (metrics) | 989 if (metrics) |
| 972 metrics->Stop(); | 990 metrics->Stop(); |
| 973 | 991 |
| 974 // browser_shutdown takes care of deleting browser_process, so we need to | 992 // browser_shutdown takes care of deleting browser_process, so we need to |
| 975 // release it. | 993 // release it. |
| 976 browser_process.release(); | 994 browser_process.release(); |
| 977 browser_shutdown::Shutdown(); | 995 browser_shutdown::Shutdown(); |
| 978 | 996 |
| 979 return result_code; | 997 return result_code; |
| 980 } | 998 } |
| OLD | NEW |