Make subprocesses die when their parents do
This could also be a configurable option in cvd::Subprocess, but it
seems to work when always enabled.
The PR_SET_PDEATHSIG setting is unset on the forked child, which happens
to do the right thing already with run_cvd daemonizing. Because that does
not use cvd::Subprocess, the setting doesn't apply to it (though it is
given to run_cvd originally by launch_cvd).
Bug: 145956571
Test: ctrl-c on launch_cvd
Change-Id: I387db1acabe90e1f41abb159b1c07e891ea46a87
diff --git a/common/libs/utils/subprocess.cpp b/common/libs/utils/subprocess.cpp
index e83b487..9c383d3 100644
--- a/common/libs/utils/subprocess.cpp
+++ b/common/libs/utils/subprocess.cpp
@@ -19,6 +19,7 @@
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
+#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -69,7 +70,8 @@
const char* const* command, const char* const* envp,
const std::map<cvd::Subprocess::StdIOChannel, int>& redirects,
const std::map<cvd::SharedFD, int>& inherited_fds, bool with_control_socket,
- cvd::SubprocessStopper stopper, bool in_group = false, bool verbose = false) {
+ cvd::SubprocessStopper stopper, bool in_group = false, bool verbose = false,
+ bool exit_with_parent = true) {
// The parent socket will get closed on the child on the call to exec, the
// child socket will be closed on the parent when this function returns and no
// references to the fd are left
@@ -91,6 +93,10 @@
pid_t pid = fork();
if (!pid) {
+ if (exit_with_parent) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP); // Die when parent dies
+ }
+
do_redirects(redirects);
if (in_group) {
// This call should never fail (see SETPGID(2))
@@ -293,17 +299,21 @@
verbose_ = verbose;
}
+void Command::SetExitWithParent(bool exit_with_parent) {
+ exit_with_parent_ = exit_with_parent;
+}
+
Subprocess Command::StartHelper(bool with_control_socket, bool in_group) const {
auto cmd = ToCharPointers(command_);
if (use_parent_env_) {
return subprocess_impl(cmd.data(), nullptr, redirects_, inherited_fds_,
with_control_socket, subprocess_stopper_, in_group,
- verbose_);
+ verbose_, exit_with_parent_);
} else {
auto envp = ToCharPointers(env_);
return subprocess_impl(cmd.data(), envp.data(), redirects_, inherited_fds_,
with_control_socket, subprocess_stopper_, in_group,
- verbose_);
+ verbose_, exit_with_parent_);
}
}
diff --git a/common/libs/utils/subprocess.h b/common/libs/utils/subprocess.h
index 44976f9..df3d9f6 100644
--- a/common/libs/utils/subprocess.h
+++ b/common/libs/utils/subprocess.h
@@ -118,8 +118,10 @@
// optional subprocess stopper. When not provided, stopper defaults to sending
// SIGKILL to the subprocess.
Command(const std::string& executable,
- SubprocessStopper stopper = KillSubprocess)
- : subprocess_stopper_(stopper), verbose_(true) {
+ SubprocessStopper stopper = KillSubprocess,
+ bool exit_with_parent = true)
+ : subprocess_stopper_(stopper), verbose_(true),
+ exit_with_parent_(exit_with_parent) {
command_.push_back(executable);
}
Command(Command&&) = default;
@@ -159,6 +161,7 @@
Subprocess::StdIOChannel parent_channel);
void SetVerbose(bool verbose);
+ void SetExitWithParent(bool exit_with_parent);
// Starts execution of the command. This method can be called multiple times,
// effectively staring multiple (possibly concurrent) instances. If
@@ -185,6 +188,7 @@
std::vector<std::string> env_{};
SubprocessStopper subprocess_stopper_;
bool verbose_;
+ bool exit_with_parent_;
};
/*