From e5b6ccb1e7ada618347a5bb68d776718db7fa7c4 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 9 Dec 2015 10:51:16 +0100 Subject: [PATCH] Now uses files from eidheim/tiny-process-library --- README.md | 1 + src/CMakeLists.txt | 11 +- src/process.cpp | 25 ---- src/process.hpp | 81 ------------- src/process_unix.cpp | 183 ---------------------------- src/process_win.cpp | 281 ------------------------------------------- 6 files changed, 7 insertions(+), 575 deletions(-) delete mode 100644 src/process.cpp delete mode 100644 src/process.hpp delete mode 100644 src/process_unix.cpp delete mode 100644 src/process_win.cpp diff --git a/README.md b/README.md index eee04aa..8424dce 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ See [enhancements](https://github.com/cppit/jucipp/labels/enhancement) for plann * aspell * libclang * [libclangmm](http://github.com/cppit/libclangmm/) +* [tiny-process-library](http://github.com/eidheim/tiny-process-library/) ## Installation ## See [installation guide](http://github.com/cppit/jucipp/blob/master/docs/install.md). diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5bf9926..f47e2a1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -74,8 +74,6 @@ set(source_files juci.h cmake.h cmake.cc dialogs.cc - process.hpp - process.cpp ../libclangmm/src/CodeCompleteResults.cc ../libclangmm/src/CompilationDatabase.cc @@ -90,14 +88,16 @@ set(source_files juci.h ../libclangmm/src/Tokens.cc ../libclangmm/src/TranslationUnit.cc ../libclangmm/src/Diagnostic.cc - ../libclangmm/src/Utility.cc) + ../libclangmm/src/Utility.cc + + ../tiny-process-library/process.cpp) if(MSYS) - list(APPEND source_files process_win.cpp) list(APPEND source_files dialogs_unix.cc) #dialogs_win.cc does not work any more because of missing SHCreateItemFromParsingName + list(APPEND source_files ../tiny-process-library/process_win.cpp) else() - list(APPEND source_files process_unix.cpp) list(APPEND source_files dialogs_unix.cc) + list(APPEND source_files ../tiny-process-library/process_unix.cpp) endif() add_executable(${project_name} ${source_files}) @@ -114,6 +114,7 @@ include_directories( ${LIBCLANG_INCLUDE_DIRS} ${ASPELL_INCLUDE_DIR} ../libclangmm/src + ../tiny-process-library ) link_directories( diff --git a/src/process.cpp b/src/process.cpp deleted file mode 100644 index a1f7ec9..0000000 --- a/src/process.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "process.hpp" - -#include //TODO: remove -using namespace std; //TODO: remove - -Process::Process(const std::string &command, const std::string &path, - std::function read_stdout, - std::function read_stderr, - bool open_stdin, size_t buffer_size): - closed(true), read_stdout(read_stdout), read_stderr(read_stderr), open_stdin(open_stdin), buffer_size(buffer_size) { - open(command, path); - async_read(); -} - -Process::~Process() { - close_fds(); -} - -Process::id_type Process::get_id() { - return data.id; -} - -bool Process::write(const std::string &data) { - return write(data.c_str(), data.size()); -} diff --git a/src/process.hpp b/src/process.hpp deleted file mode 100644 index 6eb50e4..0000000 --- a/src/process.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef TINY_PROCESS_LIBRARY_HPP_ -#define TINY_PROCESS_LIBRARY_HPP_ - -#include -#include -#include -#include -#include -#include -#ifdef _WIN32 -#include -#else -#include -#endif - -///Create a new process given command and run path. -///TODO: on Windows it is harder to specify which pipes to redirect. -///Thus, at the moment, if read_stdout==nullptr, read_stderr==nullptr and open_stdin==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 -private: - class Data { - public: - Data(); - id_type id; -#ifdef _WIN32 - HANDLE handle; -#endif - }; -public: - Process(const std::string &command, const std::string &path=std::string(), - std::function read_stdout=nullptr, - std::function read_stderr=nullptr, - bool open_stdin=false, - size_t buffer_size=131072); - ~Process(); - - ///Get the process id of the started process. - id_type get_id(); - ///Wait until process is finished, and return exit status. - int get_exit_status(); - ///Write to stdin. - bool write(const char *bytes, size_t n); - ///Write to stdin. Convenience function using write(const char *, size_t). - bool write(const std::string &data); - ///Close stdin. If the process takes parameters from stdin, use this to notify that all parameters have been sent. - void close_stdin(); - - ///Kill the process. - void kill(bool force=false); - ///Kill a given process id. Use kill(bool force) instead if possible. - static void kill(id_type id, bool force=false); - -private: - Data data; - bool closed; - std::mutex close_mutex; - std::function read_stdout; - std::function read_stderr; - std::thread stdout_thread, stderr_thread; - bool open_stdin; - std::mutex stdin_mutex; - const size_t buffer_size; - - std::unique_ptr stdout_fd, stderr_fd, stdin_fd; - - id_type open(const std::string &command, const std::string &path); - void async_read(); - void close_fds(); -}; - -#endif // TINY_PROCESS_LIBRARY_HPP_ diff --git a/src/process_unix.cpp b/src/process_unix.cpp deleted file mode 100644 index ecb8805..0000000 --- a/src/process_unix.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "process.hpp" -#include -#include -#include - -#include //TODO: remove -using namespace std; //TODO: remove - -Process::Data::Data(): id(-1) {} - -Process::id_type Process::open(const std::string &command, const std::string &path) { - if(open_stdin) - stdin_fd=std::unique_ptr(new fd_type); - if(read_stdout) - stdout_fd=std::unique_ptr(new fd_type); - if(read_stderr) - stderr_fd=std::unique_ptr(new fd_type); - - int stdin_p[2], stdout_p[2], stderr_p[2]; - - if(stdin_fd && pipe(stdin_p)!=0) { - close(stdin_p[0]); - close(stdin_p[1]); - return -1; - } - if(stdout_fd && pipe(stdout_p)!=0) { - if(stdin_fd) close(stdin_p[0]); - if(stdin_fd) close(stdin_p[1]); - close(stdout_p[0]); - close(stdout_p[1]); - return -1; - } - if(stderr_fd && pipe(stderr_p)!=0) { - if(stdin_fd) close(stdin_p[0]); - if(stdin_fd) close(stdin_p[1]); - if(stdout_fd) close(stdout_p[0]); - if(stdout_fd) close(stdout_p[1]); - close(stderr_p[0]); - close(stderr_p[1]); - return -1; - } - - id_type pid = fork(); - - if (pid < 0) { - if(stdin_fd) close(stdin_p[0]); - if(stdin_fd) close(stdin_p[1]); - if(stdout_fd) close(stdout_p[0]); - if(stdout_fd) close(stdout_p[1]); - if(stderr_fd) close(stderr_p[0]); - if(stderr_fd) close(stderr_p[1]); - return pid; - } - else if (pid == 0) { - if(stdin_fd) close(stdin_p[1]); - if(stdout_fd) close(stdout_p[0]); - if(stderr_fd) close(stderr_p[0]); - if(stdin_fd) dup2(stdin_p[0], 0); - if(stdout_fd) dup2(stdout_p[1], 1); - if(stderr_fd) dup2(stderr_p[1], 2); - - setpgid(0, 0); - //TODO: See here on how to emulate tty for colors: http://stackoverflow.com/questions/1401002/trick-an-application-into-thinking-its-stdin-is-interactive-not-a-pipe - //TODO: One solution is: echo "command;exit"|script -q /dev/null - - if(!path.empty()) - execl("/bin/sh", "sh", "-c", ("cd \""+path+"\" && "+command).c_str(), NULL); - else - execl("/bin/sh", "sh", "-c", command.c_str(), NULL); - - _exit(EXIT_FAILURE); - } - - if(stdin_fd) close(stdin_p[0]); - if(stdout_fd) close(stdout_p[1]); - if(stderr_fd) close(stderr_p[1]); - - if(stdin_fd) *stdin_fd = stdin_p[1]; - if(stdout_fd) *stdout_fd = stdout_p[0]; - if(stderr_fd) *stderr_fd = stderr_p[0]; - - closed=false; - data.id=pid; - return pid; -} - -void Process::async_read() { - if(data.id<=0) - return; - if(stdout_fd) { - stdout_thread=std::thread([this](){ - char buffer[buffer_size]; - ssize_t n; - while ((n=read(*stdout_fd, buffer, buffer_size)) > 0) - read_stdout(buffer, static_cast(n)); - }); - } - if(stderr_fd) { - stderr_thread=std::thread([this](){ - char buffer[buffer_size]; - ssize_t n; - while ((n=read(*stderr_fd, buffer, buffer_size)) > 0) - read_stderr(buffer, static_cast(n)); - }); - } -} - -int Process::get_exit_status() { - if(data.id<=0) - return -1; - int exit_status; - waitpid(data.id, &exit_status, 0); - close_mutex.lock(); - closed=true; - close_mutex.unlock(); - - close_fds(); - - return exit_status; -} - -void Process::close_fds() { - if(stdout_thread.joinable()) - stdout_thread.join(); - if(stderr_thread.joinable()) - stderr_thread.join(); - - if(stdin_fd) - close_stdin(); - if(stdout_fd) { - close(*stdout_fd); - stdout_fd.reset(); - } - if(stderr_fd) { - close(*stderr_fd); - stderr_fd.reset(); - } -} - -bool Process::write(const char *bytes, size_t n) { - stdin_mutex.lock(); - if(stdin_fd) { - if(::write(*stdin_fd, bytes, n)>=0) { - stdin_mutex.unlock(); - return true; - } - else { - stdin_mutex.unlock(); - return false; - } - } - stdin_mutex.unlock(); - return false; -} - -void Process::close_stdin() { - stdin_mutex.lock(); - if(stdin_fd) { - close(*stdin_fd); - stdin_fd.reset(); - } - stdin_mutex.unlock(); -} - -void Process::kill(bool force) { - close_mutex.lock(); - if(data.id>0 && !closed) { - if(force) - ::kill(-data.id, SIGTERM); - else - ::kill(-data.id, SIGINT); - } - close_mutex.unlock(); -} - -void Process::kill(id_type id, bool force) { - if(id<=0) - return; - if(force) - ::kill(-id, SIGTERM); - else - ::kill(-id, SIGINT); -} diff --git a/src/process_win.cpp b/src/process_win.cpp deleted file mode 100644 index e307ab2..0000000 --- a/src/process_win.cpp +++ /dev/null @@ -1,281 +0,0 @@ -#include "process.hpp" -#include -#include "TlHelp32.h" - -#include //TODO: remove -using namespace std; //TODO: remove - -Process::Data::Data(): id(0), handle(NULL) {} - -//Based on the example at https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx. -Process::id_type Process::open(const std::string &command, const std::string &path) { - if(open_stdin) - stdin_fd=std::unique_ptr(new fd_type); - if(read_stdout) - stdout_fd=std::unique_ptr(new fd_type); - if(read_stderr) - stderr_fd=std::unique_ptr(new fd_type); - - HANDLE g_hChildStd_IN_Rd = NULL; - HANDLE g_hChildStd_IN_Wr = NULL; - HANDLE g_hChildStd_OUT_Rd = NULL; - HANDLE g_hChildStd_OUT_Wr = NULL; - HANDLE g_hChildStd_ERR_Rd = NULL; - HANDLE g_hChildStd_ERR_Wr = NULL; - - SECURITY_ATTRIBUTES saAttr; - - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - saAttr.lpSecurityDescriptor = NULL; - - if(stdin_fd) { - if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) - return 0; - if(!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) { - CloseHandle(g_hChildStd_IN_Rd); - CloseHandle(g_hChildStd_IN_Wr); - return 0; - } - } - if(stdout_fd) { - if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) { - if(stdin_fd) CloseHandle(g_hChildStd_IN_Rd); - if(stdin_fd) CloseHandle(g_hChildStd_IN_Wr); - return 0; - } - if(!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) { - if(stdin_fd) CloseHandle(g_hChildStd_IN_Rd); - if(stdin_fd) CloseHandle(g_hChildStd_IN_Wr); - CloseHandle(g_hChildStd_OUT_Rd); - CloseHandle(g_hChildStd_OUT_Wr); - return 0; - } - } - if(stderr_fd) { - if (!CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &saAttr, 0)) { - if(stdin_fd) CloseHandle(g_hChildStd_IN_Rd); - if(stdin_fd) CloseHandle(g_hChildStd_IN_Wr); - if(stdout_fd) CloseHandle(g_hChildStd_OUT_Rd); - if(stdout_fd) CloseHandle(g_hChildStd_OUT_Wr); - return 0; - } - if(!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0)) { - if(stdin_fd) CloseHandle(g_hChildStd_IN_Rd); - if(stdin_fd) CloseHandle(g_hChildStd_IN_Wr); - if(stdout_fd) CloseHandle(g_hChildStd_OUT_Rd); - if(stdout_fd) CloseHandle(g_hChildStd_OUT_Wr); - CloseHandle(g_hChildStd_ERR_Rd); - CloseHandle(g_hChildStd_ERR_Wr); - return 0; - } - } - - PROCESS_INFORMATION process_info; - STARTUPINFO siStartInfo; - - ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION)); - - ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); - siStartInfo.cb = sizeof(STARTUPINFO); - if(stdin_fd) siStartInfo.hStdInput = g_hChildStd_IN_Rd; - if(stdout_fd) siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; - if(stderr_fd) siStartInfo.hStdError = g_hChildStd_ERR_Wr; - if(stdin_fd || stdout_fd || stderr_fd) - siStartInfo.dwFlags |= STARTF_USESTDHANDLES; - - char* path_cstr; - if(path=="") - path_cstr=NULL; - else { - path_cstr=new char[path.size()+1]; - std::strcpy(path_cstr, path.c_str()); - } - - char* command_cstr; -#ifdef MSYS_PROCESS_USE_SH - size_t pos=0; - std::string sh_command=command; - while((pos=sh_command.find('\\', pos))!=std::string::npos) { - sh_command.replace(pos, 1, "\\\\\\\\"); - pos+=4; - } - pos=0; - while((pos=sh_command.find('\"', pos))!=std::string::npos) { - sh_command.replace(pos, 1, "\\\""); - pos+=2; - } - sh_command.insert(0, "sh -c \""); - sh_command+="\""; - command_cstr=new char[sh_command.size()+1]; - std::strcpy(command_cstr, sh_command.c_str()); -#else - command_cstr=new char[command.size()+1]; - std::strcpy(command_cstr, command.c_str()); -#endif - - BOOL bSuccess = CreateProcess(NULL, command_cstr, NULL, NULL, TRUE, 0, - NULL, path_cstr, &siStartInfo, &process_info); - delete[] path_cstr; - delete[] command_cstr; - - if(!bSuccess) { - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); - if(stdin_fd) CloseHandle(g_hChildStd_IN_Rd); - if(stdout_fd) CloseHandle(g_hChildStd_OUT_Wr); - if(stderr_fd) CloseHandle(g_hChildStd_ERR_Wr); - return 0; - } - else { - CloseHandle(process_info.hThread); - if(stdin_fd) CloseHandle(g_hChildStd_IN_Rd); - if(stdout_fd) CloseHandle(g_hChildStd_OUT_Wr); - if(stderr_fd) CloseHandle(g_hChildStd_ERR_Wr); - } - - if(stdin_fd) *stdin_fd=g_hChildStd_IN_Wr; - if(stdout_fd) *stdout_fd=g_hChildStd_OUT_Rd; - if(stderr_fd) *stderr_fd=g_hChildStd_ERR_Rd; - - closed=false; - data.id=process_info.dwProcessId; - data.handle=process_info.hProcess; - return process_info.dwProcessId; -} - -void Process::async_read() { - if(data.id==0) - return; - if(stdout_fd) { - stdout_thread=std::thread([this](){ - DWORD n; - char buffer[buffer_size]; - for (;;) { - BOOL bSuccess = ReadFile(*stdout_fd, static_cast(buffer), static_cast(buffer_size), &n, NULL); - if(!bSuccess || n == 0) - break; - read_stdout(buffer, static_cast(n)); - } - }); - } - if(stderr_fd) { - stderr_thread=std::thread([this](){ - DWORD n; - char buffer[buffer_size]; - for (;;) { - BOOL bSuccess = ReadFile(*stderr_fd, static_cast(buffer), static_cast(buffer_size), &n, NULL); - if(!bSuccess || n == 0) - break; - read_stderr(buffer, static_cast(n)); - } - }); - } -} - -int Process::get_exit_status() { - if(data.id==0) - return -1; - DWORD exit_status; - WaitForSingleObject(data.handle, INFINITE); - if(!GetExitCodeProcess(data.handle, &exit_status)) - exit_status=-1; - close_mutex.lock(); - CloseHandle(data.handle); - closed=true; - close_mutex.unlock(); - - close_fds(); - - return static_cast(exit_status); -} - -void Process::close_fds() { - if(stdout_thread.joinable()) - stdout_thread.join(); - if(stderr_thread.joinable()) - stderr_thread.join(); - - if(stdin_fd) - close_stdin(); - if(stdout_fd) { - CloseHandle(*stdout_fd); - stdout_fd.reset(); - } - if(stderr_fd) { - CloseHandle(*stderr_fd); - stderr_fd.reset(); - } -} - -bool Process::write(const char *bytes, size_t n) { - stdin_mutex.lock(); - if(stdin_fd) { - DWORD written; - BOOL bSuccess=WriteFile(*stdin_fd, bytes, static_cast(n), &written, NULL); - if(!bSuccess || written==0) { - stdin_mutex.unlock(); - return false; - } - else { - stdin_mutex.unlock(); - return true; - } - } - stdin_mutex.unlock(); - return false; -} - -void Process::close_stdin() { - stdin_mutex.lock(); - if(stdin_fd) { - CloseHandle(*stdin_fd); - stdin_fd.reset(); - } - stdin_mutex.unlock(); -} - -//Based on http://stackoverflow.com/a/1173396 -void Process::kill(bool force) { - close_mutex.lock(); - if(data.id>0 && !closed) { - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if(snapshot) { - PROCESSENTRY32 process; - ZeroMemory(&process, sizeof(process)); - process.dwSize = sizeof(process); - if(Process32First(snapshot, &process)) { - do { - if(process.th32ParentProcessID==data.id) { - HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID); - if(process_handle) TerminateProcess(process_handle, 2); - } - } while (Process32Next(snapshot, &process)); - } - } - TerminateProcess(data.handle, 2); - } - close_mutex.unlock(); -} - -//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; - ZeroMemory(&process, sizeof(process)); - process.dwSize = sizeof(process); - if(Process32First(snapshot, &process)) { - do { - if(process.th32ParentProcessID==id) { - HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID); - if(process_handle) TerminateProcess(process_handle, 2); - } - } while (Process32Next(snapshot, &process)); - } - } - HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id); - if(process_handle) TerminateProcess(process_handle, 2); -}