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 |