X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;ds=sidebyside;f=src%2Fapp%2Fproc.cpp;h=add16d1787a4779068b6ce36b06be9c9d1d9e194;hb=65dfaba8d22823ccbde6669c13fa598b6d23710e;hp=33d1a14c9c83a8126d4bd039897aaa6a278b58cb;hpb=e40a5620036f6887828fe547588125f08ff718be;p=blank.git diff --git a/src/app/proc.cpp b/src/app/proc.cpp index 33d1a14..add16d1 100644 --- a/src/app/proc.cpp +++ b/src/app/proc.cpp @@ -1,14 +1,18 @@ #include "Process.hpp" +#include "error.hpp" + #ifdef _WIN32 -# error "TODO: windows implementation of Process" +# include +# include #else -# include # include +# include # include # include #endif +#include #include using namespace std; @@ -20,14 +24,15 @@ struct Process::Impl { Impl( const string &path_in, - const vector &args, - const vector &env); + const Arguments &args, + const Environment &env); ~Impl(); size_t WriteIn(const void *buffer, size_t max_len); size_t ReadOut(void *buffer, size_t max_len); size_t ReadErr(void *buffer, size_t max_len); + void Terminate(); int Join(); #ifdef _WIN32 @@ -47,8 +52,8 @@ struct Process::Impl { Process::Process( const string &path, - const vector &args, - const vector &env) + const Arguments &args, + const Environment &env) : impl(new Impl(path, args, env)) , joined(false) , status(0) { @@ -72,6 +77,12 @@ size_t Process::ReadErr(void *buffer, size_t max_len) { return impl->ReadErr(buffer, max_len); } +void Process::Terminate() { + if (!joined) { + impl->Terminate(); + } +} + int Process::Join() { if (joined) { return status; @@ -85,8 +96,8 @@ int Process::Join() { Process::Impl::Impl( const string &path_in, - const vector &args, - const vector &env + const Arguments &args, + const Environment &env ) { const char *path = path_in.c_str(); char *envp[env.size() + 1]; @@ -157,18 +168,18 @@ Process::Impl::Impl( argv[args.size()] = nullptr; if (pipe(fd_in) != 0) { - throw runtime_error("failed to open pipe for child process' stdin"); + throw SysError("failed to open pipe for child process' stdin"); } if (pipe(fd_out) != 0) { - throw runtime_error("failed to open pipe for child process' stdout"); + throw SysError("failed to open pipe for child process' stdout"); } if (pipe(fd_err) != 0) { - throw runtime_error("failed to open pipe for child process' stderr"); + throw SysError("failed to open pipe for child process' stderr"); } pid = fork(); if (pid == -1) { - throw runtime_error("fork"); + throw SysError("fork"); } else if (pid == 0) { if (dup2(fd_in[0], STDIN_FILENO) == -1) { @@ -219,7 +230,7 @@ size_t Process::Impl::WriteIn(const void *buffer, size_t max_len) { if (errno == EAGAIN) { return 0; } else { - throw runtime_error("failed to write to child process' input stream"); + throw SysError("failed to write to child process' input stream"); } } return written; @@ -239,7 +250,7 @@ size_t Process::Impl::ReadOut(void *buffer, size_t max_len) { if (errno == EAGAIN) { return 0; } else { - throw runtime_error("failed to read from child process' output stream"); + throw SysError("failed to read from child process' output stream"); } } return ret; @@ -259,13 +270,23 @@ size_t Process::Impl::ReadErr(void *buffer, size_t max_len) { if (errno == EAGAIN) { return 0; } else { - throw runtime_error("failed to read from child process' error stream"); + throw SysError("failed to read from child process' error stream"); } } return ret; #endif } +void Process::Impl::Terminate() { +#ifdef _WIN32 + if (!TerminateProcess(pi.hProcess, -1)) { +#else + if (kill(pid, SIGTERM) == -1) { +#endif + throw SysError("failed to terminate child process"); + } +} + int Process::Impl::Join() { #ifdef _WIN32 CloseHandle(fd_in[1]); @@ -288,13 +309,22 @@ int Process::Impl::Join() { int status; int result = waitpid(pid, &status, 0); if (result == -1) { - throw runtime_error("error waiting on child process"); + throw SysError("error waiting on child process"); + } + if (result != pid) { + // should in theory only happen with WNOHANG set + continue; } - if (result == pid && WIFEXITED(status)) { + if (WIFEXITED(status)) { + // autonomous termination return WEXITSTATUS(status); } - // otherwise, child probably signalled, which we don't care - // about (please don't tell youth welfare), so try again + if (WIFSIGNALED(status)) { + // signalled termination + return WTERMSIG(status); + } + // otherwise, child probably signalled stop/continue, which we + // don't care about (please don't tell youth welfare), so try again } #endif }