summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-11 01:14:56 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-11 01:14:56 +0000
commit41f82d25cef085e5e8f9a931adc0067245268335 (patch)
treeb7f9606e299e427ab1707481c66d7c1fc7e4196c
parentb53c457c556a08a9dd3dd786085f51ca8c4cf98a (diff)
downloadchromium_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.cc137
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();