4 # error "TODO: windows implementation of Process"
19 struct Process::Impl {
22 const string &path_in,
23 const vector<string> &args,
24 const vector<string> &env);
27 size_t WriteIn(const void *buffer, size_t max_len);
28 size_t ReadOut(void *buffer, size_t max_len);
29 size_t ReadErr(void *buffer, size_t max_len);
34 PROCESS_INFORMATION pi;
50 const vector<string> &args,
51 const vector<string> &env)
52 : impl(new Impl(path, args, env))
63 size_t Process::WriteIn(const void *buffer, size_t max_len) {
64 return impl->WriteIn(buffer, max_len);
67 size_t Process::ReadOut(void *buffer, size_t max_len) {
68 return impl->ReadOut(buffer, max_len);
71 size_t Process::ReadErr(void *buffer, size_t max_len) {
72 return impl->ReadErr(buffer, max_len);
79 status = impl->Join();
87 const string &path_in,
88 const vector<string> &args,
89 const vector<string> &env
91 const char *path = path_in.c_str();
92 char *envp[env.size() + 1];
93 for (size_t i = 0; i < env.size(); ++i) {
94 envp[i] = const_cast<char *>(env[i].c_str());
96 envp[env.size()] = nullptr;
99 for (const auto &arg : args) {
105 SECURITY_ATTRIBUTES sa;
106 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
107 sa.bInheritHandle = true;
108 sa.lpSecurityDescriptor = nullptr;
109 if (!CreatePipe(&fd_in[0], &fd_in[1], &sa, 0)) {
110 throw runtime_error("failed to open pipe for child process' stdin");
112 if (!SetHandleInformation(fd_in[1], HANDLE_FLAG_INHERIT, 0)) {
113 throw runtime_error("failed to stop child process from inheriting stdin write handle");
115 if (!CreatePipe(&fd_out[0], &fd_out[1], &sa, 0)) {
116 throw runtime_error("failed to open pipe for child process' stdout");
118 if (!SetHandleInformation(fd_out[0], HANDLE_FLAG_INHERIT, 0)) {
119 throw runtime_error("failed to stop child process from inheriting stdout read handle");
121 if (!CreatePipe(&fd_err[0], &fd_err[1], &sa, 0)) {
122 throw runtime_error("failed to open pipe for child process' stderr");
124 if (!SetHandleInformation(fd_err[0], HANDLE_FLAG_INHERIT, 0)) {
125 throw runtime_error("failed to stop child process from inheriting stderr read handle");
129 ZeroMemory(&si, sizeof(STARTUPINFO));
130 si.cb = sizeof(STARTUPINFO);
131 si.hStdError = fd_err[1];
132 si.hStdOutput = fd_out[1];
133 si.hStdInput = fd_in[0];
134 si.dwFlags |= STARTF_USESTDHANDLES;
135 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
149 throw runtime_error("CreateProcess");
152 char *argv[args.size() + 1];
153 for (size_t i = 0; i < args.size(); ++i) {
154 // I was promised exec won't modify my characters
155 argv[i] = const_cast<char *>(args[i].c_str());
157 argv[args.size()] = nullptr;
159 if (pipe(fd_in) != 0) {
160 throw runtime_error("failed to open pipe for child process' stdin");
162 if (pipe(fd_out) != 0) {
163 throw runtime_error("failed to open pipe for child process' stdout");
165 if (pipe(fd_err) != 0) {
166 throw runtime_error("failed to open pipe for child process' stderr");
171 throw runtime_error("fork");
172 } else if (pid == 0) {
174 if (dup2(fd_in[0], STDIN_FILENO) == -1) {
177 if (dup2(fd_out[1], STDOUT_FILENO) == -1) {
180 if (dup2(fd_err[1], STDERR_FILENO) == -1) {
191 execve(path, argv, envp);
192 // if execve returns, something bad happened
205 Process::Impl::~Impl() {
209 size_t Process::Impl::WriteIn(const void *buffer, size_t max_len) {
212 if (!WriteFile(fd_in[1], buffer, max_len, &written, nullptr)) {
213 throw runtime_error("failed to write to child process' input stream");
217 int written = write(fd_in[1], buffer, max_len);
219 if (errno == EAGAIN) {
222 throw runtime_error("failed to write to child process' input stream");
229 size_t Process::Impl::ReadOut(void *buffer, size_t max_len) {
232 if (!ReadFile(fd_out[0], buffer, max_len, &ret, nullptr)) {
233 throw runtime_error("failed to read from child process' output stream");
237 int ret = read(fd_out[0], buffer, max_len);
239 if (errno == EAGAIN) {
242 throw runtime_error("failed to read from child process' output stream");
249 size_t Process::Impl::ReadErr(void *buffer, size_t max_len) {
252 if (!ReadFile(fd_err[0], buffer, max_len, &ret, nullptr)) {
253 throw runtime_error("failed to read from child process' error stream");
257 int ret = read(fd_err[0], buffer, max_len);
259 if (errno == EAGAIN) {
262 throw runtime_error("failed to read from child process' error stream");
269 int Process::Impl::Join() {
271 CloseHandle(fd_in[1]);
272 CloseHandle(fd_out[0]);
273 CloseHandle(fd_err[0]);
276 WaitForSingleObject(pi.hProcess, INFINITE);
277 GetExitCodeProcess(pi.hProcess, &exit_code);
278 CloseHandle(pi.hProcess);
279 CloseHandle(pi.hThread);
282 // close streams before waiting on child termination
289 int result = waitpid(pid, &status, 0);
291 throw runtime_error("error waiting on child process");
293 if (result == pid && WIFEXITED(status)) {
294 return WEXITSTATUS(status);
296 // otherwise, child probably signalled, which we don't care
297 // about (please don't tell youth welfare), so try again