Commit 2498dba8 authored by Adam Simpkins's avatar Adam Simpkins Committed by Facebook Github Bot

allow creation of a Subprocess from an existing child pid

Summary:
Add a static method to Subprocess that allows creating a `Subprocess` object
from an existing child process ID.  This allows creating `Subprocess` objects
for children processes that were originally spawned through other APIs than
Subprocess itself.

This allows using the Subprocess `wait()` and `poll()` APIs for these child
processes, and allows passing them to existing parts of the code that expect
to work with `Subprocess` objects.

Reviewed By: yfeldblum

Differential Revision: D19588079

fbshipit-source-id: e29b56be4def659cedfd007ddb3a85e826c0a44c
parent 44fd32d7
...@@ -214,6 +214,13 @@ Subprocess::Subprocess( ...@@ -214,6 +214,13 @@ Subprocess::Subprocess(
spawn(cloneStrings(argv), argv[0].c_str(), options, env); spawn(cloneStrings(argv), argv[0].c_str(), options, env);
} }
Subprocess Subprocess::fromExistingProcess(pid_t pid) {
Subprocess sp;
sp.pid_ = pid;
sp.returnCode_ = ProcessReturnCode::makeRunning();
return sp;
}
Subprocess::~Subprocess() { Subprocess::~Subprocess() {
CHECK_NE(returnCode_.state(), ProcessReturnCode::RUNNING) CHECK_NE(returnCode_.state(), ProcessReturnCode::RUNNING)
<< "Subprocess destroyed without reaping child"; << "Subprocess destroyed without reaping child";
......
...@@ -536,6 +536,15 @@ class Subprocess { ...@@ -536,6 +536,15 @@ class Subprocess {
const std::vector<std::string>* env = nullptr); const std::vector<std::string>* env = nullptr);
~Subprocess(); ~Subprocess();
/**
* Create a Subprocess object for an existing child process ID.
*
* The process ID must refer to an immediate child process of the current
* process. This allows using the poll() and wait() APIs on a process ID
* that was not originally spawned by Subprocess.
*/
static Subprocess fromExistingProcess(pid_t pid);
/** /**
* Create a subprocess run as a shell command (as shell -c 'command') * Create a subprocess run as a shell command (as shell -c 'command')
* *
......
...@@ -338,6 +338,25 @@ TEST(SimpleSubprocessTest, DetachExecFails) { ...@@ -338,6 +338,25 @@ TEST(SimpleSubprocessTest, DetachExecFails) {
"/no/such/file"); "/no/such/file");
} }
TEST(SimpleSubprocessTest, FromExistingProcess) {
// Manually fork a child process using fork() without exec(), and test waiting
// for it using the Subprocess API in the parent process.
static int constexpr kReturnCode = 123;
auto pid = fork();
ASSERT_NE(pid, -1) << "fork failed";
if (pid == 0) {
// child process
_exit(kReturnCode);
}
auto child = Subprocess::fromExistingProcess(pid);
EXPECT_TRUE(child.returnCode().running());
auto retCode = child.wait();
EXPECT_TRUE(retCode.exited());
EXPECT_EQ(kReturnCode, retCode.exitStatus());
}
TEST(ParentDeathSubprocessTest, ParentDeathSignal) { TEST(ParentDeathSubprocessTest, ParentDeathSignal) {
// Find out where we are. // Find out where we are.
const auto basename = "subprocess_test_parent_death_helper"; const auto basename = "subprocess_test_parent_death_helper";
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment