11#include <condition_variable>
26static bool WaitPidWithTimeout(
int pid, std::chrono::milliseconds timeout,
int& status_out)
28 const auto deadline = std::chrono::steady_clock::now() + timeout;
29 while (std::chrono::steady_clock::now() < deadline) {
30 const int r = ::waitpid(pid, &status_out, WNOHANG);
31 if (r == pid)
return true;
33 std::this_thread::sleep_for(std::chrono::milliseconds{1});
44KJ_TEST(
"SpawnProcess does not run callback in child")
49 std::mutex target_mutex;
50 std::mutex control_mutex;
51 std::condition_variable control_cv;
56 std::thread locker([&] {
57 std::unique_lock<std::mutex> target_lock(target_mutex);
59 std::lock_guard<std::mutex>
g(control_mutex);
62 control_cv.notify_one();
64 std::unique_lock<std::mutex> control_lock(control_mutex);
65 control_cv.wait(control_lock, [&] {
return release; });
70 std::unique_lock<std::mutex> l(control_mutex);
71 control_cv.wait(l, [&] {
return locked; });
75 std::thread releaser([&] {
79 std::this_thread::sleep_for(std::chrono::milliseconds{50});
81 std::lock_guard<std::mutex>
g(control_mutex);
84 control_cv.notify_one();
88 const int fd{
mp::SpawnProcess(pid, [&](
int child_fd) -> std::vector<std::string> {
91 std::lock_guard<std::mutex>
g(target_mutex);
92 return {
"true", std::to_string(child_fd)};
99 const bool exited{WaitPidWithTimeout(pid, std::chrono::milliseconds{1000}, status)};
101 ::kill(pid, SIGKILL);
102 ::waitpid(pid, &status, 0);
108 KJ_EXPECT(exited,
"Timeout waiting for child process to exit");
109 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")