Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/app/shutdown_signal_handlers_posix.h" | |
| 6 | |
| 7 #include <limits.h> | |
| 8 #include <signal.h> | |
| 9 #include <string.h> | |
| 10 #include <unistd.h> | |
| 11 | |
| 12 #include "base/callback.h" | |
| 13 #include "base/debug/leak_annotations.h" | |
| 14 #include "base/logging.h" | |
| 15 #include "base/macros.h" | |
| 16 #include "base/posix/eintr_wrapper.h" | |
| 17 #include "base/single_thread_task_runner.h" | |
| 18 #include "base/threading/platform_thread.h" | |
| 19 #include "base/threading/thread_task_runner_handle.h" | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 // The OSX fork() implementation can crash in the child process before | |
|
James Cook
2017/03/01 18:24:38
This code is a straight cut-paste from chrome_brow
| |
| 24 // fork() returns. In that case, the shutdown pipe will still be | |
| 25 // shared with the parent process. To prevent child crashes from | |
| 26 // causing parent shutdowns, |g_pipe_pid| is the pid for the process | |
| 27 // which registered |g_shutdown_pipe_write_fd|. | |
| 28 // See <http://crbug.com/175341>. | |
| 29 pid_t g_pipe_pid = -1; | |
| 30 int g_shutdown_pipe_write_fd = -1; | |
| 31 int g_shutdown_pipe_read_fd = -1; | |
| 32 | |
| 33 // Common code between SIG{HUP, INT, TERM}Handler. | |
| 34 void GracefulShutdownHandler(int signal) { | |
| 35 // Reinstall the default handler. We had one shot at graceful shutdown. | |
| 36 struct sigaction action; | |
| 37 memset(&action, 0, sizeof(action)); | |
| 38 action.sa_handler = SIG_DFL; | |
| 39 RAW_CHECK(sigaction(signal, &action, NULL) == 0); | |
| 40 | |
| 41 RAW_CHECK(g_pipe_pid != -1); | |
| 42 RAW_CHECK(g_shutdown_pipe_write_fd != -1); | |
| 43 RAW_CHECK(g_shutdown_pipe_read_fd != -1); | |
| 44 RAW_CHECK(g_pipe_pid == getpid()); | |
| 45 size_t bytes_written = 0; | |
| 46 do { | |
| 47 int rv = HANDLE_EINTR( | |
| 48 write(g_shutdown_pipe_write_fd, | |
| 49 reinterpret_cast<const char*>(&signal) + bytes_written, | |
| 50 sizeof(signal) - bytes_written)); | |
| 51 RAW_CHECK(rv >= 0); | |
| 52 bytes_written += rv; | |
| 53 } while (bytes_written < sizeof(signal)); | |
| 54 } | |
| 55 | |
| 56 void SIGHUPHandler(int signal) { | |
| 57 RAW_CHECK(signal == SIGHUP); | |
| 58 GracefulShutdownHandler(signal); | |
| 59 } | |
| 60 | |
| 61 void SIGINTHandler(int signal) { | |
| 62 RAW_CHECK(signal == SIGINT); | |
| 63 GracefulShutdownHandler(signal); | |
| 64 } | |
| 65 | |
| 66 void SIGTERMHandler(int signal) { | |
| 67 RAW_CHECK(signal == SIGTERM); | |
| 68 GracefulShutdownHandler(signal); | |
| 69 } | |
| 70 | |
| 71 // Runs a thread that invokes a callback when a termination signal handler | |
| 72 // is invoked. Uses a pipe to wait for the signal handler to run. | |
| 73 class ShutdownDetector : public base::PlatformThread::Delegate { | |
| 74 public: | |
| 75 ShutdownDetector( | |
| 76 int shutdown_fd, | |
| 77 const base::Closure& shutdown_callback, | |
| 78 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); | |
|
James Cook
2017/03/01 18:24:38
Added the task runner and callback.
| |
| 79 ~ShutdownDetector() override; | |
|
James Cook
2017/03/01 18:24:38
Added destructor.
| |
| 80 | |
| 81 // base::PlatformThread::Delegate: | |
| 82 void ThreadMain() override; | |
| 83 | |
| 84 private: | |
| 85 const int shutdown_fd_; | |
| 86 const base::Closure shutdown_callback_; | |
| 87 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
| 88 | |
| 89 DISALLOW_COPY_AND_ASSIGN(ShutdownDetector); | |
| 90 }; | |
| 91 | |
| 92 ShutdownDetector::ShutdownDetector( | |
| 93 int shutdown_fd, | |
| 94 const base::Closure& shutdown_callback, | |
| 95 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | |
| 96 : shutdown_fd_(shutdown_fd), | |
| 97 shutdown_callback_(shutdown_callback), | |
| 98 task_runner_(task_runner) { | |
| 99 CHECK_NE(shutdown_fd_, -1); | |
| 100 CHECK(!shutdown_callback.is_null()); | |
| 101 CHECK(task_runner_); | |
| 102 } | |
| 103 | |
| 104 ShutdownDetector::~ShutdownDetector() {} | |
| 105 | |
| 106 // These functions are used to help us diagnose crash dumps that happen | |
| 107 // during the shutdown process. | |
| 108 NOINLINE void ShutdownFDReadError() { | |
| 109 // Ensure function isn't optimized away. | |
| 110 asm(""); | |
| 111 sleep(UINT_MAX); | |
| 112 } | |
| 113 | |
| 114 NOINLINE void ShutdownFDClosedError() { | |
| 115 // Ensure function isn't optimized away. | |
| 116 asm(""); | |
| 117 sleep(UINT_MAX); | |
| 118 } | |
| 119 | |
| 120 NOINLINE void ExitPosted() { | |
| 121 // Ensure function isn't optimized away. | |
| 122 asm(""); | |
| 123 sleep(UINT_MAX); | |
| 124 } | |
| 125 | |
| 126 void ShutdownDetector::ThreadMain() { | |
| 127 base::PlatformThread::SetName("CrShutdownDetector"); | |
| 128 | |
| 129 int signal; | |
| 130 size_t bytes_read = 0; | |
| 131 ssize_t ret; | |
| 132 do { | |
| 133 ret = HANDLE_EINTR(read(shutdown_fd_, | |
| 134 reinterpret_cast<char*>(&signal) + bytes_read, | |
| 135 sizeof(signal) - bytes_read)); | |
| 136 if (ret < 0) { | |
| 137 NOTREACHED() << "Unexpected error: " << strerror(errno); | |
| 138 ShutdownFDReadError(); | |
| 139 break; | |
| 140 } else if (ret == 0) { | |
| 141 NOTREACHED() << "Unexpected closure of shutdown pipe."; | |
| 142 ShutdownFDClosedError(); | |
| 143 break; | |
| 144 } | |
| 145 bytes_read += ret; | |
| 146 } while (bytes_read < sizeof(signal)); | |
| 147 VLOG(1) << "Handling shutdown for signal " << signal << "."; | |
| 148 | |
| 149 if (!task_runner_->PostTask(FROM_HERE, shutdown_callback_)) { | |
|
James Cook
2017/03/01 18:24:38
Used it here.
| |
| 150 // Without a valid task runner to post the exit task to, there aren't many | |
| 151 // options. Raise the signal again. The default handler will pick it up | |
| 152 // and cause an ungraceful exit. | |
| 153 RAW_LOG(WARNING, "No valid task runner, exiting ungracefully."); | |
| 154 kill(getpid(), signal); | |
| 155 | |
| 156 // The signal may be handled on another thread. Give that a chance to | |
| 157 // happen. | |
| 158 sleep(3); | |
| 159 | |
| 160 // We really should be dead by now. For whatever reason, we're not. Exit | |
| 161 // immediately, with the exit status set to the signal number with bit 8 | |
| 162 // set. On the systems that we care about, this exit status is what is | |
| 163 // normally used to indicate an exit by this signal's default handler. | |
| 164 // This mechanism isn't a de jure standard, but even in the worst case, it | |
| 165 // should at least result in an immediate exit. | |
| 166 RAW_LOG(WARNING, "Still here, exiting really ungracefully."); | |
| 167 _exit(signal | (1 << 7)); | |
| 168 } | |
| 169 ExitPosted(); | |
| 170 } | |
| 171 | |
| 172 } // namespace | |
| 173 | |
| 174 void InstallShutdownSignalHandlers( | |
| 175 const base::Closure& shutdown_callback, | |
| 176 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { | |
| 177 int pipefd[2]; | |
| 178 int ret = pipe(pipefd); | |
| 179 if (ret < 0) { | |
| 180 PLOG(DFATAL) << "Failed to create pipe"; | |
| 181 return; | |
|
James Cook
2017/03/01 18:24:38
Added early exit to reduce indenting.
| |
| 182 } | |
| 183 g_pipe_pid = getpid(); | |
| 184 g_shutdown_pipe_read_fd = pipefd[0]; | |
| 185 g_shutdown_pipe_write_fd = pipefd[1]; | |
| 186 #if !defined(ADDRESS_SANITIZER) && !defined(KEEP_SHADOW_STACKS) | |
| 187 const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 2; | |
| 188 #else | |
| 189 // ASan instrumentation and -finstrument-functions (used for keeping the | |
| 190 // shadow stacks) bloat the stack frames, so we need to increase the stack | |
| 191 // size to avoid hitting the guard page. | |
| 192 const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4; | |
| 193 #endif | |
| 194 ShutdownDetector* detector = new ShutdownDetector( | |
|
James Cook
2017/03/01 18:24:38
Used local variable so I could add the leak annota
| |
| 195 g_shutdown_pipe_read_fd, shutdown_callback, task_runner); | |
| 196 // PlatformThread does not delete its delegate. | |
| 197 ANNOTATE_LEAKING_OBJECT_PTR(detector); | |
| 198 if (!base::PlatformThread::CreateNonJoinable(kShutdownDetectorThreadStackSize, | |
| 199 detector)) { | |
| 200 LOG(DFATAL) << "Failed to create shutdown detector task."; | |
| 201 } | |
| 202 | |
| 203 // Setup signal handlers for shutdown AFTER shutdown pipe is setup because | |
| 204 // it may be called right away after handler is set. | |
| 205 | |
| 206 // If adding to this list of signal handlers, note the new signal probably | |
| 207 // needs to be reset in child processes. See | |
| 208 // base/process_util_posix.cc:LaunchProcess. | |
| 209 | |
| 210 // We need to handle SIGTERM, because that is how many POSIX-based distros | |
| 211 // ask processes to quit gracefully at shutdown time. | |
| 212 struct sigaction action; | |
| 213 memset(&action, 0, sizeof(action)); | |
| 214 action.sa_handler = SIGTERMHandler; | |
| 215 CHECK(sigaction(SIGTERM, &action, nullptr) == 0); | |
| 216 | |
| 217 // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If | |
| 218 // the browser process is being debugged, GDB will catch the SIGINT first. | |
| 219 action.sa_handler = SIGINTHandler; | |
| 220 CHECK(sigaction(SIGINT, &action, nullptr) == 0); | |
| 221 | |
| 222 // And SIGHUP, for when the terminal disappears. On shutdown, many Linux | |
| 223 // distros send SIGHUP, SIGTERM, and then SIGKILL. | |
| 224 action.sa_handler = SIGHUPHandler; | |
| 225 CHECK(sigaction(SIGHUP, &action, nullptr) == 0); | |
| 226 } | |
| OLD | NEW |