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 |