46 PROCESS_INFORMATION pinfo;
52 static void _proc_exit_handler(
void*) { ::kill(::getpid(), SIGTERM); }
58 : pinfo(CPP_AGGREGATE_INIT(PROCESS_INFORMATION){ INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 })
71 bool start(
const char*
const args[],
const WCHAR*
const envp =
nullptr)
73 bool start(
const char*
const args[],
char*
const*
const envp =
nullptr)
79 for (uint i = 0; args[i] !=
nullptr; ++i)
84 if (args[i][0] !=
'"' && std::strchr(args[i],
' ') !=
nullptr)
96 wchar_t wcmd[PATH_MAX];
97 if (MultiByteToWideChar(CP_UTF8, 0, cmd.data(), -1, wcmd, PATH_MAX) <= 0)
100 STARTUPINFOW si = {};
103 d_stdout(
"will start process with args '%s'", cmd.data());
105 return CreateProcessW(
nullptr,
110 CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
111 const_cast<LPWSTR
>(envp),
116 const pid_t ret = pid = vfork();
122 #if defined(DAF_OS_LINUX)
123 ::prctl(PR_SET_PDEATHSIG, SIGTERM);
124 #elif defined(DAF_OS_MAC)
125 if (
const dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC,
130 dispatch_source_set_event_handler_f(source, _proc_exit_handler);
131 dispatch_resume(source);
136 execve(args[0],
const_cast<char* const*
>(args), envp);
138 execvp(args[0],
const_cast<char* const*
>(args));
140 d_stderr2(
"exec failed: %d:%s", errno, std::strerror(errno));
146 d_stderr2(
"vfork() failed: %d:%s", errno, std::strerror(errno));
154 void stop(
const uint32_t timeoutInMilliseconds = 2000)
156 const uint32_t timeout = d_gettime_ms() + timeoutInMilliseconds;
157 bool sendTerminate =
true;
159 #ifdef DAF_OS_WINDOWS
160 if (pinfo.hProcess == INVALID_HANDLE_VALUE)
163 const PROCESS_INFORMATION opinfo = pinfo;
164 pinfo = (PROCESS_INFORMATION){ INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 };
166 for (DWORD exitCode;;)
168 if (GetExitCodeProcess(opinfo.hProcess, &exitCode) == FALSE ||
169 exitCode != STILL_ACTIVE ||
170 WaitForSingleObject(opinfo.hProcess, 0) != WAIT_TIMEOUT)
172 CloseHandle(opinfo.hThread);
173 CloseHandle(opinfo.hProcess);
179 sendTerminate =
false;
180 TerminateProcess(opinfo.hProcess, ERROR_BROKEN_PIPE);
183 if (d_gettime_ms() < timeout)
188 d_stderr(
"ChildProcess::stop() - timed out");
189 TerminateProcess(opinfo.hProcess, 9);
191 CloseHandle(opinfo.hThread);
192 CloseHandle(opinfo.hProcess);
199 const pid_t opid = pid;
205 ret = ::waitpid(opid,
nullptr, WNOHANG);
206 } DAF_SAFE_EXCEPTION_BREAK(
"waitpid");
218 d_stderr(
"ChildProcess::stop() - waitpid failed: %d:%s", errno, std::strerror(errno));
226 sendTerminate =
false;
229 if (d_gettime_ms() < timeout)
235 d_stderr(
"ChildProcess::stop() - timed out");
237 waitpid(opid,
nullptr, WNOHANG);
248 d_stderr(
"ChildProcess::stop() - got wrong pid %i (requested was %i)",
int(ret),
int(opid));
260 #ifdef DAF_OS_WINDOWS
261 if (pinfo.hProcess == INVALID_HANDLE_VALUE)
265 if (GetExitCodeProcess(pinfo.hProcess, &exitCode) == FALSE ||
266 exitCode != STILL_ACTIVE ||
267 WaitForSingleObject(pinfo.hProcess, 0) != WAIT_TIMEOUT)
269 const PROCESS_INFORMATION opinfo = pinfo;
270 pinfo = (PROCESS_INFORMATION){ INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 };
271 CloseHandle(opinfo.hThread);
272 CloseHandle(opinfo.hProcess);
281 const pid_t ret = ::waitpid(pid,
nullptr, WNOHANG);
283 if (ret == pid || (ret == -1 && errno == ECHILD))
293 #ifndef DAF_OS_WINDOWS
294 void signal(
const int sig)
303 #ifdef DAF_OS_WINDOWS
304 if (pinfo.hProcess != INVALID_HANDLE_VALUE)
305 TerminateProcess(pinfo.hProcess, 15);
312 DAF_DECLARE_NON_COPYABLE(ChildProcess)