Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: chrome/browser/browser_main.cc

Issue 460094: Make POSIX SIGTERM/SIGINT/SIGHUP handler async signal safe. (Closed)
Patch Set: move shutdown thread creation after UI thread is registered. Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/logging.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « base/logging.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698