refactor: align shutdown signal handling with upstream (#26559)
This commit is contained in:
parent
b4196ca486
commit
46972abf8b
3 changed files with 54 additions and 32 deletions
|
@ -504,7 +504,10 @@ void ElectronBrowserMainParts::PostMainMessageLoopStart() {
|
||||||
bluez::DBusBluezManagerWrapperLinux::Initialize();
|
bluez::DBusBluezManagerWrapperLinux::Initialize();
|
||||||
#endif
|
#endif
|
||||||
#if defined(OS_POSIX)
|
#if defined(OS_POSIX)
|
||||||
HandleShutdownSignals();
|
// Exit in response to SIGINT, SIGTERM, etc.
|
||||||
|
InstallShutdownSignalHandlers(
|
||||||
|
base::BindOnce(&Browser::Quit, base::Unretained(Browser::Get())),
|
||||||
|
content::GetUIThreadTaskRunner({}));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,9 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
|
||||||
#if defined(OS_POSIX)
|
#if defined(OS_POSIX)
|
||||||
// Set signal handlers.
|
// Set signal handlers.
|
||||||
void HandleSIGCHLD();
|
void HandleSIGCHLD();
|
||||||
void HandleShutdownSignals();
|
void InstallShutdownSignalHandlers(
|
||||||
|
base::OnceCallback<void()> shutdown_callback,
|
||||||
|
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(OS_MAC)
|
#if defined(OS_MAC)
|
||||||
|
|
|
@ -80,19 +80,32 @@ void SIGTERMHandler(int signal) {
|
||||||
|
|
||||||
class ShutdownDetector : public base::PlatformThread::Delegate {
|
class ShutdownDetector : public base::PlatformThread::Delegate {
|
||||||
public:
|
public:
|
||||||
explicit ShutdownDetector(int shutdown_fd);
|
explicit ShutdownDetector(
|
||||||
|
int shutdown_fd,
|
||||||
|
base::OnceCallback<void()> shutdown_callback,
|
||||||
|
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
|
||||||
|
|
||||||
|
// base::PlatformThread::Delegate:
|
||||||
void ThreadMain() override;
|
void ThreadMain() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const int shutdown_fd_;
|
const int shutdown_fd_;
|
||||||
|
base::OnceCallback<void()> shutdown_callback_;
|
||||||
|
const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
|
DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
|
||||||
};
|
};
|
||||||
|
|
||||||
ShutdownDetector::ShutdownDetector(int shutdown_fd)
|
ShutdownDetector::ShutdownDetector(
|
||||||
: shutdown_fd_(shutdown_fd) {
|
int shutdown_fd,
|
||||||
|
base::OnceCallback<void()> shutdown_callback,
|
||||||
|
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
|
||||||
|
: shutdown_fd_(shutdown_fd),
|
||||||
|
shutdown_callback_(std::move(shutdown_callback)),
|
||||||
|
task_runner_(task_runner) {
|
||||||
CHECK_NE(shutdown_fd_, -1);
|
CHECK_NE(shutdown_fd_, -1);
|
||||||
|
CHECK(!shutdown_callback_.is_null());
|
||||||
|
CHECK(task_runner_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// These functions are used to help us diagnose crash dumps that happen
|
// These functions are used to help us diagnose crash dumps that happen
|
||||||
|
@ -121,7 +134,7 @@ void ShutdownDetector::ThreadMain() {
|
||||||
int signal;
|
int signal;
|
||||||
size_t bytes_read = 0;
|
size_t bytes_read = 0;
|
||||||
do {
|
do {
|
||||||
ssize_t ret = HANDLE_EINTR(
|
const ssize_t ret = HANDLE_EINTR(
|
||||||
read(shutdown_fd_, reinterpret_cast<char*>(&signal) + bytes_read,
|
read(shutdown_fd_, reinterpret_cast<char*>(&signal) + bytes_read,
|
||||||
sizeof(signal) - bytes_read));
|
sizeof(signal) - bytes_read));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -137,13 +150,12 @@ void ShutdownDetector::ThreadMain() {
|
||||||
} while (bytes_read < sizeof(signal));
|
} while (bytes_read < sizeof(signal));
|
||||||
VLOG(1) << "Handling shutdown for signal " << signal << ".";
|
VLOG(1) << "Handling shutdown for signal " << signal << ".";
|
||||||
|
|
||||||
if (!base::PostTask(
|
if (!task_runner_->PostTask(FROM_HERE,
|
||||||
FROM_HERE, {BrowserThread::UI},
|
base::BindOnce(std::move(shutdown_callback_)))) {
|
||||||
base::BindOnce(&Browser::Quit, base::Unretained(Browser::Get())))) {
|
// Without a valid task runner to post the exit task to, there aren't many
|
||||||
// Without a UI thread to post the exit task to, there aren't many
|
|
||||||
// options. Raise the signal again. The default handler will pick it up
|
// options. Raise the signal again. The default handler will pick it up
|
||||||
// and cause an ungraceful exit.
|
// and cause an ungraceful exit.
|
||||||
RAW_LOG(WARNING, "No UI thread, exiting ungracefully.");
|
RAW_LOG(WARNING, "No valid task runner, exiting ungracefully.");
|
||||||
kill(getpid(), signal);
|
kill(getpid(), signal);
|
||||||
|
|
||||||
// The signal may be handled on another thread. Give that a chance to
|
// The signal may be handled on another thread. Give that a chance to
|
||||||
|
@ -173,31 +185,34 @@ void ElectronBrowserMainParts::HandleSIGCHLD() {
|
||||||
CHECK_EQ(sigaction(SIGCHLD, &action, nullptr), 0);
|
CHECK_EQ(sigaction(SIGCHLD, &action, nullptr), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElectronBrowserMainParts::HandleShutdownSignals() {
|
void ElectronBrowserMainParts::InstallShutdownSignalHandlers(
|
||||||
|
base::OnceCallback<void()> shutdown_callback,
|
||||||
|
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
int ret = pipe(pipefd);
|
int ret = pipe(pipefd);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
PLOG(DFATAL) << "Failed to create pipe";
|
PLOG(DFATAL) << "Failed to create pipe";
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
g_pipe_pid = getpid();
|
g_pipe_pid = getpid();
|
||||||
g_shutdown_pipe_read_fd = pipefd[0];
|
g_shutdown_pipe_read_fd = pipefd[0];
|
||||||
g_shutdown_pipe_write_fd = pipefd[1];
|
g_shutdown_pipe_write_fd = pipefd[1];
|
||||||
#if !defined(ADDRESS_SANITIZER) && !defined(KEEP_SHADOW_STACKS)
|
#if !defined(ADDRESS_SANITIZER)
|
||||||
const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 2;
|
const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 2;
|
||||||
#else
|
#else
|
||||||
// ASan instrumentation and -finstrument-functions (used for keeping the
|
// ASan instrumentation bloats the stack frames, so we need to increase the
|
||||||
// shadow stacks) bloat the stack frames, so we need to increase the stack
|
// stack size to avoid hitting the guard page.
|
||||||
// size to avoid hitting the guard page.
|
|
||||||
const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4;
|
const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4;
|
||||||
#endif
|
#endif
|
||||||
// TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so
|
ShutdownDetector* detector = new ShutdownDetector(
|
||||||
// if you change this, you'll probably need to change the suppression.
|
g_shutdown_pipe_read_fd, std::move(shutdown_callback), task_runner);
|
||||||
if (!base::PlatformThread::CreateNonJoinable(
|
|
||||||
kShutdownDetectorThreadStackSize,
|
// PlatformThread does not delete its delegate.
|
||||||
new ShutdownDetector(g_shutdown_pipe_read_fd))) {
|
ANNOTATE_LEAKING_OBJECT_PTR(detector);
|
||||||
|
if (!base::PlatformThread::CreateNonJoinable(kShutdownDetectorThreadStackSize,
|
||||||
|
detector)) {
|
||||||
LOG(DFATAL) << "Failed to create shutdown detector task.";
|
LOG(DFATAL) << "Failed to create shutdown detector task.";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Setup signal handlers for shutdown AFTER shutdown pipe is setup because
|
// Setup signal handlers for shutdown AFTER shutdown pipe is setup because
|
||||||
// it may be called right away after handler is set.
|
// it may be called right away after handler is set.
|
||||||
|
|
||||||
|
@ -205,16 +220,18 @@ void ElectronBrowserMainParts::HandleShutdownSignals() {
|
||||||
// needs to be reset in child processes. See
|
// needs to be reset in child processes. See
|
||||||
// base/process_util_posix.cc:LaunchProcess.
|
// base/process_util_posix.cc:LaunchProcess.
|
||||||
|
|
||||||
// We need to handle SIGTERM, because that is how many POSIX-based distros ask
|
// We need to handle SIGTERM, because that is how many POSIX-based distros
|
||||||
// processes to quit gracefully at shutdown time.
|
// ask processes to quit gracefully at shutdown time.
|
||||||
struct sigaction action;
|
struct sigaction action;
|
||||||
memset(&action, 0, sizeof(action));
|
memset(&action, 0, sizeof(action));
|
||||||
action.sa_handler = SIGTERMHandler;
|
action.sa_handler = SIGTERMHandler;
|
||||||
CHECK_EQ(sigaction(SIGTERM, &action, nullptr), 0);
|
CHECK_EQ(sigaction(SIGTERM, &action, nullptr), 0);
|
||||||
|
|
||||||
// Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
|
// Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
|
||||||
// the browser process is being debugged, GDB will catch the SIGINT first.
|
// the browser process is being debugged, GDB will catch the SIGINT first.
|
||||||
action.sa_handler = SIGINTHandler;
|
action.sa_handler = SIGINTHandler;
|
||||||
CHECK_EQ(sigaction(SIGINT, &action, nullptr), 0);
|
CHECK_EQ(sigaction(SIGINT, &action, nullptr), 0);
|
||||||
|
|
||||||
// And SIGHUP, for when the terminal disappears. On shutdown, many Linux
|
// And SIGHUP, for when the terminal disappears. On shutdown, many Linux
|
||||||
// distros send SIGHUP, SIGTERM, and then SIGKILL.
|
// distros send SIGHUP, SIGTERM, and then SIGKILL.
|
||||||
action.sa_handler = SIGHUPHandler;
|
action.sa_handler = SIGHUPHandler;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue