From 29f2cc2f557a46e65521b118032358fb0eab2ba0 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 4 Dec 2015 17:48:51 +0100 Subject: [PATCH] Some cleanups to process* --- src/process.cc | 2 +- src/process.h | 26 ++++++++++++++-------- src/process_unix.cc | 16 +++++++++----- src/process_win.cc | 53 +++++++++++++++++++++++---------------------- 4 files changed, 55 insertions(+), 42 deletions(-) diff --git a/src/process.cc b/src/process.cc index 72a4906..0ab07f0 100644 --- a/src/process.cc +++ b/src/process.cc @@ -9,7 +9,7 @@ Process::Process(const std::string &command, const std::string &path, bool open_stdin, size_t buffer_size): read_stdout(read_stdout), read_stderr(read_stderr), open_stdin(open_stdin), buffer_size(buffer_size) { id=open(command, path); - if(id!=0) + if(id>0) async_read(); } diff --git a/src/process.h b/src/process.h index 79d0e68..88b69ab 100644 --- a/src/process.h +++ b/src/process.h @@ -8,16 +8,24 @@ #include #ifdef _WIN32 #include - typedef DWORD process_id_type; - typedef HANDLE file_descriptor_type; #else #include - typedef pid_t process_id_type; - typedef int file_descriptor_type; #endif +///Create a new process given command and run path. +///Note: on Windows it seems impossible to specify which pipes to use. +///Thus, if read_stdout=nullptr, read_stderr=nullptr and open_std=false, +///the stdout, stderr and stdin are sent to the parent process instead. +///Compile with -DMSYS_PROCESS_USE_SH to run command using "sh -c [command]" on Windows as well. class Process { public: +#ifdef _WIN32 + typedef DWORD id_type; //Process id type + typedef HANDLE fd_type; //File descriptor type +#else + typedef pid_t id_type; + typedef int fd_type; +#endif Process(const std::string &command, const std::string &path=std::string(), std::function read_stdout=nullptr, std::function read_stderr=nullptr, @@ -26,7 +34,7 @@ public: ~Process(); ///Get the process id of the started process. - process_id_type get_id() {return id;} + id_type get_id() {return id;} ///Wait until process is finished, and return exit_code. int get_exit_code(); ///Write to stdin. @@ -35,7 +43,7 @@ public: void close_stdin(); ///Kill a given process id. - static void kill(process_id_type id, bool force=false); + static void kill(id_type id, bool force=false); private: std::function read_stdout; @@ -45,10 +53,10 @@ private: std::mutex stdin_mutex; const size_t buffer_size; - std::unique_ptr stdout_fd, stderr_fd, stdin_fd; + std::unique_ptr stdout_fd, stderr_fd, stdin_fd; - process_id_type open(const std::string &command, const std::string &path); - process_id_type id; + id_type open(const std::string &command, const std::string &path); + id_type id; void async_read(); }; diff --git a/src/process_unix.cc b/src/process_unix.cc index f7e1fb5..14e99ae 100644 --- a/src/process_unix.cc +++ b/src/process_unix.cc @@ -6,13 +6,13 @@ #include //TODO: remove using namespace std; //TODO: remove -process_id_type Process::open(const std::string &command, const std::string &path) { +Process::id_type Process::open(const std::string &command, const std::string &path) { if(open_stdin) - stdin_fd=std::unique_ptr(new file_descriptor_type); + stdin_fd=std::unique_ptr(new fd_type); if(read_stdout) - stdout_fd=std::unique_ptr(new file_descriptor_type); + stdout_fd=std::unique_ptr(new fd_type); if(read_stderr) - stderr_fd=std::unique_ptr(new file_descriptor_type); + stderr_fd=std::unique_ptr(new fd_type); int stdin_p[2], stdout_p[2], stderr_p[2]; @@ -38,7 +38,7 @@ process_id_type Process::open(const std::string &command, const std::string &pat return -1; } - process_id_type pid = fork(); + id_type pid = fork(); if (pid < 0) { if(stdin_fd) close(stdin_p[0]); @@ -101,6 +101,8 @@ void Process::async_read() { } int Process::get_exit_code() { + if(id<=0) + return -1; int exit_code; waitpid(id, &exit_code, 0); @@ -147,7 +149,9 @@ void Process::close_stdin() { stdin_mutex.unlock(); } -void Process::kill(process_id_type id, bool force) { +void Process::kill(id_type id, bool force) { + if(id<=0) + return; if(force) ::kill(-id, SIGTERM); else diff --git a/src/process_win.cc b/src/process_win.cc index 6487adf..c2798ff 100644 --- a/src/process_win.cc +++ b/src/process_win.cc @@ -5,16 +5,16 @@ #include //TODO: remove using namespace std; //TODO: remove -//Based on the example at https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx -//Note: on Windows it seems impossible to specify which pipes to use -//Thus, if stdin_h, stdout_h and stderr all are NULL, the out,err,in is sent to the parent process instead -process_id_type Process::open(const std::string &command, const std::string &path) { +//Based on the example at https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx. +//Note: on Windows it seems impossible to specify which pipes to use. +//Thus, if read_stdout=nullptr, read_stderr=nullptr and open_std=false, the stdout, stderr and stdin are sent to the parent process instead. +Process::id_type Process::open(const std::string &command, const std::string &path) { if(open_stdin) - stdin_fd=std::unique_ptr(new file_descriptor_type); + stdin_fd=std::unique_ptr(new fd_type); if(read_stdout) - stdout_fd=std::unique_ptr(new file_descriptor_type); + stdout_fd=std::unique_ptr(new fd_type); if(read_stderr) - stderr_fd=std::unique_ptr(new file_descriptor_type); + stderr_fd=std::unique_ptr(new fd_type); HANDLE g_hChildStd_IN_Rd = NULL; HANDLE g_hChildStd_IN_Wr = NULL; @@ -112,16 +112,8 @@ process_id_type Process::open(const std::string &command, const std::string &pat std::strcpy(command_cstr, command.c_str()); #endif - BOOL bSuccess = CreateProcess(NULL, - command_cstr, // command line - NULL, // process security attributes - NULL, // primary thread security attributes - TRUE, // handles are inherited - 0, // creation flags - NULL, // use parent's environment - path_ptr, // use parent's current directory - &siStartInfo, // STARTUPINFO pointer - &process_info); // receives PROCESS_INFORMATION + BOOL bSuccess = CreateProcess(NULL, command_cstr, NULL, NULL, TRUE, 0, + NULL, path_ptr, &siStartInfo, &process_info); if(!bSuccess) { CloseHandle(process_info.hProcess); @@ -173,11 +165,17 @@ void Process::async_read() { } int Process::get_exit_code() { + if(id==0) + return -1; DWORD exit_code; - HANDLE process_info = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id); - WaitForSingleObject(process_info, INFINITE); - GetExitCodeProcess(process_info, &exit_code); - CloseHandle(process_info); + HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id); + if(process_handle) { + WaitForSingleObject(process_handle, INFINITE); + GetExitCodeProcess(process_handle, &exit_code); + CloseHandle(process_handle); + } + else + exit_code=-1; if(stdout_thread.joinable()) stdout_thread.join(); @@ -224,7 +222,10 @@ void Process::close_stdin() { stdin_mutex.unlock(); } -void Process::kill(process_id_type id, bool force) { +//Based on http://stackoverflow.com/a/1173396 +void Process::kill(id_type id, bool force) { + if(id==0) + return; HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(snapshot) { PROCESSENTRY32 process; @@ -233,12 +234,12 @@ void Process::kill(process_id_type id, bool force) { if(Process32First(snapshot, &process)) { do { if(process.th32ParentProcessID==id) { - HANDLE process_info = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID); - if(process_info) TerminateProcess(process_info, 2); + HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID); + if(process_handle) TerminateProcess(process_handle, 2); } } while (Process32Next(snapshot, &process)); } } - HANDLE process_info = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id); - if(process_info) TerminateProcess(process_info, 2); + HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id); + if(process_handle) TerminateProcess(process_handle, 2); }