11#include <condition_variable>
23constexpr auto FAILURE_TIMEOUT = std::chrono::seconds{30};
28static bool WaitPidWithTimeout(
int pid, std::chrono::milliseconds timeout,
int& status_out)
30 const auto deadline = std::chrono::steady_clock::now() + timeout;
31 while (std::chrono::steady_clock::now() < deadline) {
32 const int r = ::waitpid(pid, &status_out, WNOHANG);
33 if (r == pid)
return true;
35 std::this_thread::sleep_for(std::chrono::milliseconds{1});
46KJ_TEST(
"SpawnProcess does not run callback in child")
51 std::mutex target_mutex;
52 std::mutex control_mutex;
53 std::condition_variable control_cv;
58 std::thread locker([&] {
59 std::unique_lock<std::mutex> target_lock(target_mutex);
61 std::lock_guard<std::mutex>
g(control_mutex);
64 control_cv.notify_one();
66 std::unique_lock<std::mutex> control_lock(control_mutex);
67 control_cv.wait(control_lock, [&] {
return release; });
72 std::unique_lock<std::mutex> l(control_mutex);
73 control_cv.wait(l, [&] {
return locked; });
77 std::thread releaser([&] {
81 std::this_thread::sleep_for(std::chrono::milliseconds{50});
83 std::lock_guard<std::mutex>
g(control_mutex);
86 control_cv.notify_one();
90 const int fd{
mp::SpawnProcess(pid, [&](
int child_fd) -> std::vector<std::string> {
93 std::lock_guard<std::mutex>
g(target_mutex);
94 return {
"true", std::to_string(child_fd)};
101 const bool exited{WaitPidWithTimeout(pid, FAILURE_TIMEOUT, status)};
103 ::kill(pid, SIGKILL);
104 ::waitpid(pid, &status, 0);
110 KJ_EXPECT(exited,
"Timeout waiting for child process to exit");
111 KJ_EXPECT(WIFEXITED(status) && WEXITSTATUS(status) == 0);
int SpawnProcess(int &pid, FdToArgsFn &&fd_to_args)
Spawn a new process that communicates with the current process over a socket pair.
KJ_TEST("SpawnProcess does not run callback in child")