diff options
author | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-11 01:14:56 +0000 |
---|---|---|
committer | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-11 01:14:56 +0000 |
commit | 41f82d25cef085e5e8f9a931adc0067245268335 (patch) | |
tree | b7f9606e299e427ab1707481c66d7c1fc7e4196c | |
parent | b53c457c556a08a9dd3dd786085f51ca8c4cf98a (diff) | |
download | chromium_src-41f82d25cef085e5e8f9a931adc0067245268335.zip chromium_src-41f82d25cef085e5e8f9a931adc0067245268335.tar.gz chromium_src-41f82d25cef085e5e8f9a931adc0067245268335.tar.bz2 |
Mac: for branded Google Chrome, handle SIGTERM in renderer to clean up Breakpad.
Test:
1. Build a (branded) Google Chrome.
2. From the command-line, run: "launchctl bslist | wc -l" and note the number.
3. Start Google Chrome on a fresh profile.
4. Once a browser window has opened, do #2 again, and note the number -- it should have increased (by 2).
5. Close the tab, and do #2 again. The number should have decreased by 1.
6. Open tabs, navigate, etc., and do #2 between each stage. Whenever a new (e.g., renderer) process is started, the number should increase (e.g., when you go to a "new" site). When a process is terminated (e.g., you close the last tab for a particular site), the number should decrease.
7. Quit, and do #2 again. Hopefully, the number should be the same as the first time.
(Note: when a renderer crashes, the number will not decrease -- so the number after quitting will not be the same as before starting. This is why this is only a stopgap. For comparison, do this on a branded Google Chrome without this patch; typically, the numbers will not decrease on renderer termination.)
BUG=28547
TEST=See above.
Review URL: http://codereview.chromium.org/484007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@34318 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/renderer/renderer_main.cc | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/chrome/renderer/renderer_main.cc b/chrome/renderer/renderer_main.cc index c8f89c9..d4e2c5f 100644 --- a/chrome/renderer/renderer_main.cc +++ b/chrome/renderer/renderer_main.cc @@ -28,10 +28,122 @@ #include "grit/generated_resources.h" #include "net/base/net_module.h" +#if defined(OS_MACOSX) +#include "base/eintr_wrapper.h" +#include "chrome/app/breakpad_mac.h" +#include <signal.h> +#include <unistd.h> +#endif // OS_MACOSX + #if defined(USE_LINUX_BREAKPAD) #include "chrome/app/breakpad_linux.h" #endif +#if defined(OS_MACOSX) +namespace { + +// TODO(viettrungluu): crbug.com/28547: The following signal handling is needed, +// as a stopgap, to avoid leaking due to not releasing Breakpad properly. +// Without this problem, this could all be eliminated. Remove when Breakpad is +// fixed? +// TODO(viettrungluu): Code taken from browser_main.cc (with a bit of editing). +// The code should be properly shared (or this code should be eliminated). +int g_shutdown_pipe_write_fd = -1; + +void SIGTERMHandler(int signal) { + RAW_CHECK(signal == SIGTERM); + RAW_LOG(INFO, "Handling SIGTERM in renderer."); + + // Reinstall the default handler. We had one shot at graceful shutdown. + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_DFL; + CHECK(sigaction(signal, &action, NULL) == 0); + + RAW_CHECK(g_shutdown_pipe_write_fd != -1); + size_t bytes_written = 0; + do { + int rv = HANDLE_EINTR( + write(g_shutdown_pipe_write_fd, + reinterpret_cast<const char*>(&signal) + bytes_written, + sizeof(signal) - bytes_written)); + RAW_CHECK(rv >= 0); + bytes_written += rv; + } while (bytes_written < sizeof(signal)); + + RAW_LOG(INFO, "Wrote signal to shutdown pipe."); +} + +class ShutdownDetector : public PlatformThread::Delegate { + public: + explicit ShutdownDetector(int shutdown_fd) : shutdown_fd_(shutdown_fd) { + CHECK(shutdown_fd_ != -1); + } + + virtual void ThreadMain() { + int signal; + size_t bytes_read = 0; + ssize_t ret; + do { + ret = HANDLE_EINTR( + read(shutdown_fd_, + reinterpret_cast<char*>(&signal) + bytes_read, + sizeof(signal) - bytes_read)); + if (ret < 0) { + NOTREACHED() << "Unexpected error: " << strerror(errno); + break; + } else if (ret == 0) { + NOTREACHED() << "Unexpected closure of shutdown pipe."; + break; + } + bytes_read += ret; + } while (bytes_read < sizeof(signal)); + + if (bytes_read == sizeof(signal)) + LOG(INFO) << "Handling shutdown for signal " << signal << "."; + else + LOG(INFO) << "Handling shutdown for unknown signal."; + + // Clean up Breakpad if necessary. + if (IsCrashReporterEnabled()) { + LOG(INFO) << "Cleaning up Breakpad."; + DestructCrashReporter(); + } else { + LOG(INFO) << "Breakpad not enabled; no clean-up needed."; + } + + // Something went seriously wrong, so get out. + if (bytes_read != sizeof(signal)) { + LOG(WARNING) << "Failed to get signal. Quitting ungracefully."; + _exit(1); + } + + // Re-raise the signal. + kill(getpid(), signal); + + // The signal may be handled on another thread. Give that a chance to + // happen. + sleep(3); + + // We really should be dead by now. For whatever reason, we're not. Exit + // immediately, with the exit status set to the signal number with bit 8 + // set. On the systems that we care about, this exit status is what is + // normally used to indicate an exit by this signal's default handler. + // This mechanism isn't a de jure standard, but even in the worst case, it + // should at least result in an immediate exit. + LOG(WARNING) << "Still here, exiting really ungracefully."; + _exit(signal | (1 << 7)); + } + + private: + const int shutdown_fd_; + + DISALLOW_COPY_AND_ASSIGN(ShutdownDetector); +}; + +} // namespace +#endif // OS_MACOSX + // This function provides some ways to test crash and assertion handling // behavior of the renderer. static void HandleRendererErrorTestParameters(const CommandLine& command_line) { @@ -56,6 +168,31 @@ int RendererMain(const MainFunctionParams& parameters) { const CommandLine& parsed_command_line = parameters.command_line_; base::ScopedNSAutoreleasePool* pool = parameters.autorelease_pool_; +#if defined(OS_MACOSX) + // TODO(viettrungluu): Code taken from browser_main.cc. + int pipefd[2]; + int ret = pipe(pipefd); + if (ret < 0) { + PLOG(DFATAL) << "Failed to create pipe"; + } else { + int shutdown_pipe_read_fd = pipefd[0]; + g_shutdown_pipe_write_fd = pipefd[1]; + const size_t kShutdownDetectorThreadStackSize = 4096; + if (!PlatformThread::CreateNonJoinable( + kShutdownDetectorThreadStackSize, + new ShutdownDetector(shutdown_pipe_read_fd))) { + LOG(DFATAL) << "Failed to create shutdown detector task."; + } + } + + // crbug.com/28547: When Breakpad is in use, handle SIGTERM to avoid leaking + // Mach ports. + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_handler = SIGTERMHandler; + CHECK(sigaction(SIGTERM, &action, NULL) == 0); +#endif // OS_MACOSX + #if defined(USE_LINUX_BREAKPAD) // Needs to be called after we have chrome::DIR_USER_DATA. InitCrashReporter(); |