mirror of
https://github.com/MaskRay/ccls.git
synced 2025-01-19 03:55:49 +00:00
Remove tiny-process-library
This commit is contained in:
parent
1f0c1e922f
commit
172f9e2e80
@ -23,10 +23,8 @@
|
||||
#include "work_thread.h"
|
||||
#include "working_files.h"
|
||||
|
||||
#include <loguru.hpp>
|
||||
#include "tiny-process-library/process.hpp"
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
#include <loguru.hpp>
|
||||
#include <rapidjson/istreamwrapper.h>
|
||||
#include <rapidjson/ostreamwrapper.h>
|
||||
|
||||
|
@ -1,22 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2016 Ole Christian Eidheim
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
@ -1,42 +0,0 @@
|
||||
# tiny-process-library [![Build Status](https://travis-ci.org/eidheim/tiny-process-library.svg?branch=master)](https://travis-ci.org/eidheim/tiny-process-library)
|
||||
A small platform independent library making it simple to create and stop new processes in C++, as well as writing to stdin and reading from stdout and stderr of a new process.
|
||||
|
||||
This library was created for, and is used by the C++ IDE project [juCi++](https://github.com/cppit/jucipp).
|
||||
|
||||
### Features
|
||||
* No external dependencies
|
||||
* Simple to use
|
||||
* Platform independent
|
||||
* Creating processes using executables is supported on all platforms
|
||||
* Creating processes using functions is only possible on Unix-like systems
|
||||
* Read separately from stdout and stderr using anonymous functions
|
||||
* Write to stdin
|
||||
* Kill a running process (SIGTERM is supported on Unix-like systems)
|
||||
* Correctly closes file descriptors/handles
|
||||
|
||||
### Usage
|
||||
See [examples.cpp](https://github.com/eidheim/tiny-process-library/blob/master/examples.cpp).
|
||||
|
||||
### Get, compile and run
|
||||
|
||||
#### Unix-like systems
|
||||
```sh
|
||||
git clone http://github.com/eidheim/tiny-process-library
|
||||
cd tiny-process-library
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
./examples
|
||||
```
|
||||
|
||||
#### Windows with MSYS2 (https://msys2.github.io/)
|
||||
```sh
|
||||
git clone http://github.com/eidheim/tiny-process-library
|
||||
cd tiny-process-library
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G"MSYS Makefiles" ..
|
||||
make
|
||||
./examples
|
||||
```
|
@ -1,26 +0,0 @@
|
||||
#include "process.hpp"
|
||||
|
||||
namespace TinyProcessLib {
|
||||
|
||||
Process::Process(const string_type &command, const string_type &path,
|
||||
std::function<void(const char* bytes, size_t n)> read_stdout,
|
||||
std::function<void(const char* bytes, size_t n)> read_stderr,
|
||||
bool open_stdin, size_t buffer_size) noexcept:
|
||||
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() noexcept {
|
||||
close_fds();
|
||||
}
|
||||
|
||||
Process::id_type Process::get_id() const noexcept {
|
||||
return data.id;
|
||||
}
|
||||
|
||||
bool Process::write(const std::string &data) {
|
||||
return write(data.c_str(), data.size());
|
||||
}
|
||||
|
||||
} // TinyProsessLib
|
@ -1,99 +0,0 @@
|
||||
#ifndef TINY_PROCESS_LIBRARY_HPP_
|
||||
#define TINY_PROCESS_LIBRARY_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#ifndef _WIN32
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
namespace TinyProcessLib {
|
||||
|
||||
///Platform independent class for creating processes
|
||||
class Process {
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
typedef unsigned long id_type; //Process id type
|
||||
typedef void *fd_type; //File descriptor type
|
||||
#ifdef UNICODE
|
||||
typedef std::wstring string_type;
|
||||
#else
|
||||
typedef std::string string_type;
|
||||
#endif
|
||||
#else
|
||||
typedef pid_t id_type;
|
||||
typedef int fd_type;
|
||||
typedef std::string string_type;
|
||||
#endif
|
||||
private:
|
||||
class Data {
|
||||
public:
|
||||
Data() noexcept ;
|
||||
id_type id;
|
||||
#ifdef _WIN32
|
||||
void *handle;
|
||||
#endif
|
||||
};
|
||||
public:
|
||||
///Note on Windows: it seems not possible 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.
|
||||
Process(const string_type &command, const string_type &path=string_type(),
|
||||
std::function<void(const char *bytes, size_t n)> read_stdout=nullptr,
|
||||
std::function<void(const char *bytes, size_t n)> read_stderr=nullptr,
|
||||
bool open_stdin=false,
|
||||
size_t buffer_size=131072) noexcept;
|
||||
#ifndef _WIN32
|
||||
/// Supported on Unix-like systems only.
|
||||
Process(std::function<void()> function,
|
||||
std::function<void(const char *bytes, size_t n)> read_stdout=nullptr,
|
||||
std::function<void(const char *bytes, size_t n)> read_stderr=nullptr,
|
||||
bool open_stdin=false,
|
||||
size_t buffer_size=131072) noexcept;
|
||||
#endif
|
||||
~Process() noexcept;
|
||||
|
||||
///Get the process id of the started process.
|
||||
id_type get_id() const noexcept;
|
||||
///Wait until process is finished, and return exit status.
|
||||
int get_exit_status() noexcept;
|
||||
///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() noexcept;
|
||||
|
||||
///Kill the process. force=true is only supported on Unix-like systems.
|
||||
void kill(bool force=false) noexcept;
|
||||
///Kill a given process id. Use kill(bool force) instead if possible. force=true is only supported on Unix-like systems.
|
||||
static void kill(id_type id, bool force=false) noexcept;
|
||||
|
||||
private:
|
||||
Data data;
|
||||
bool closed;
|
||||
std::mutex close_mutex;
|
||||
std::function<void(const char* bytes, size_t n)> read_stdout;
|
||||
std::function<void(const char* bytes, size_t n)> read_stderr;
|
||||
std::thread stdout_thread, stderr_thread;
|
||||
bool open_stdin;
|
||||
std::mutex stdin_mutex;
|
||||
size_t buffer_size;
|
||||
|
||||
std::unique_ptr<fd_type> stdout_fd, stderr_fd, stdin_fd;
|
||||
|
||||
id_type open(const string_type &command, const string_type &path) noexcept;
|
||||
#ifndef _WIN32
|
||||
id_type open(std::function<void()> function) noexcept;
|
||||
#endif
|
||||
void async_read() noexcept;
|
||||
void close_fds() noexcept;
|
||||
};
|
||||
|
||||
} // TinyProsessLib
|
||||
|
||||
#endif // TINY_PROCESS_LIBRARY_HPP_
|
@ -1,204 +0,0 @@
|
||||
#include "process.hpp"
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace TinyProcessLib {
|
||||
|
||||
Process::Data::Data() noexcept : id(-1) {}
|
||||
|
||||
Process::Process(std::function<void()> function,
|
||||
std::function<void (const char *, size_t)> read_stdout,
|
||||
std::function<void (const char *, size_t)> read_stderr,
|
||||
bool open_stdin, size_t buffer_size) noexcept :
|
||||
closed(true), read_stdout(read_stdout), read_stderr(read_stderr), open_stdin(open_stdin), buffer_size(buffer_size) {
|
||||
open(function);
|
||||
async_read();
|
||||
}
|
||||
|
||||
Process::id_type Process::open(std::function<void()> function) noexcept {
|
||||
if(open_stdin)
|
||||
stdin_fd=std::unique_ptr<fd_type>(new fd_type);
|
||||
if(read_stdout)
|
||||
stdout_fd=std::unique_ptr<fd_type>(new fd_type);
|
||||
if(read_stderr)
|
||||
stderr_fd=std::unique_ptr<fd_type>(new fd_type);
|
||||
|
||||
int stdin_p[2], stdout_p[2], stderr_p[2];
|
||||
|
||||
if(stdin_fd && pipe(stdin_p)!=0)
|
||||
return -1;
|
||||
if(stdout_fd && pipe(stdout_p)!=0) {
|
||||
if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
|
||||
return -1;
|
||||
}
|
||||
if(stderr_fd && pipe(stderr_p)!=0) {
|
||||
if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
|
||||
if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
|
||||
return -1;
|
||||
}
|
||||
|
||||
id_type pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
|
||||
if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
|
||||
if(stderr_fd) {close(stderr_p[0]);close(stderr_p[1]);}
|
||||
return pid;
|
||||
}
|
||||
else if (pid == 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);
|
||||
if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
|
||||
if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
|
||||
if(stderr_fd) {close(stderr_p[0]);close(stderr_p[1]);}
|
||||
|
||||
//Based on http://stackoverflow.com/a/899533/3808293
|
||||
int fd_max=static_cast<int>(sysconf(_SC_OPEN_MAX)); // truncation is safe
|
||||
for(int fd=3;fd<fd_max;fd++)
|
||||
close(fd);
|
||||
|
||||
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(function)
|
||||
function();
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
Process::id_type Process::open(const std::string &command, const std::string &path) noexcept {
|
||||
return open([&command, &path] {
|
||||
if(!path.empty()) {
|
||||
auto path_escaped=path;
|
||||
size_t pos=0;
|
||||
//Based on https://www.reddit.com/r/cpp/comments/3vpjqg/a_new_platform_independent_process_library_for_c11/cxsxyb7
|
||||
while((pos=path_escaped.find('\'', pos))!=std::string::npos) {
|
||||
path_escaped.replace(pos, 1, "'\\''");
|
||||
pos+=4;
|
||||
}
|
||||
execl("/bin/sh", "sh", "-c", ("cd '"+path_escaped+"' && "+command).c_str(), NULL);
|
||||
}
|
||||
else
|
||||
execl("/bin/sh", "sh", "-c", command.c_str(), NULL);
|
||||
});
|
||||
}
|
||||
|
||||
void Process::async_read() noexcept {
|
||||
if(data.id<=0)
|
||||
return;
|
||||
if(stdout_fd) {
|
||||
stdout_thread=std::thread([this](){
|
||||
auto buffer = std::unique_ptr<char[]>( new char[buffer_size] );
|
||||
ssize_t n;
|
||||
while ((n=read(*stdout_fd, buffer.get(), buffer_size)) > 0)
|
||||
read_stdout(buffer.get(), static_cast<size_t>(n));
|
||||
});
|
||||
}
|
||||
if(stderr_fd) {
|
||||
stderr_thread=std::thread([this](){
|
||||
auto buffer = std::unique_ptr<char[]>( new char[buffer_size] );
|
||||
ssize_t n;
|
||||
while ((n=read(*stderr_fd, buffer.get(), buffer_size)) > 0)
|
||||
read_stderr(buffer.get(), static_cast<size_t>(n));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int Process::get_exit_status() noexcept {
|
||||
if(data.id<=0)
|
||||
return -1;
|
||||
int exit_status;
|
||||
waitpid(data.id, &exit_status, 0);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(close_mutex);
|
||||
closed=true;
|
||||
}
|
||||
close_fds();
|
||||
|
||||
if(exit_status>=256)
|
||||
exit_status=exit_status>>8;
|
||||
return exit_status;
|
||||
}
|
||||
|
||||
void Process::close_fds() noexcept {
|
||||
if(stdout_thread.joinable())
|
||||
stdout_thread.join();
|
||||
if(stderr_thread.joinable())
|
||||
stderr_thread.join();
|
||||
|
||||
if(stdin_fd)
|
||||
close_stdin();
|
||||
if(stdout_fd) {
|
||||
if(data.id>0)
|
||||
close(*stdout_fd);
|
||||
stdout_fd.reset();
|
||||
}
|
||||
if(stderr_fd) {
|
||||
if(data.id>0)
|
||||
close(*stderr_fd);
|
||||
stderr_fd.reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool Process::write(const char *bytes, size_t n) {
|
||||
if(!open_stdin)
|
||||
throw std::invalid_argument("Can't write to an unopened stdin pipe. Please set open_stdin=true when constructing the process.");
|
||||
|
||||
std::lock_guard<std::mutex> lock(stdin_mutex);
|
||||
if(stdin_fd) {
|
||||
if(::write(*stdin_fd, bytes, n)>=0) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Process::close_stdin() noexcept {
|
||||
std::lock_guard<std::mutex> lock(stdin_mutex);
|
||||
if(stdin_fd) {
|
||||
if(data.id>0)
|
||||
close(*stdin_fd);
|
||||
stdin_fd.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Process::kill(bool force) noexcept {
|
||||
std::lock_guard<std::mutex> lock(close_mutex);
|
||||
if(data.id>0 && !closed) {
|
||||
if(force)
|
||||
::kill(-data.id, SIGTERM);
|
||||
else
|
||||
::kill(-data.id, SIGINT);
|
||||
}
|
||||
}
|
||||
|
||||
void Process::kill(id_type id, bool force) noexcept {
|
||||
if(id<=0)
|
||||
return;
|
||||
if(force)
|
||||
::kill(-id, SIGTERM);
|
||||
else
|
||||
::kill(-id, SIGINT);
|
||||
}
|
||||
|
||||
} // TinyProsessLib
|
@ -1,272 +0,0 @@
|
||||
#if defined(_WIN32)
|
||||
#include "process.hpp"
|
||||
#include <windows.h>
|
||||
#include <cstring>
|
||||
#include <TlHelp32.h>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace TinyProcessLib {
|
||||
|
||||
Process::Data::Data() noexcept : id(0), handle(NULL) {}
|
||||
|
||||
// Simple HANDLE wrapper to close it automatically from the destructor.
|
||||
class Handle {
|
||||
public:
|
||||
Handle() : handle(INVALID_HANDLE_VALUE) { }
|
||||
~Handle() {
|
||||
close();
|
||||
}
|
||||
void close() {
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(handle);
|
||||
}
|
||||
HANDLE detach() {
|
||||
HANDLE old_handle = handle;
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
return old_handle;
|
||||
}
|
||||
operator HANDLE() const { return handle; }
|
||||
HANDLE* operator&() { return &handle; }
|
||||
private:
|
||||
HANDLE handle;
|
||||
};
|
||||
|
||||
//Based on the discussion thread: https://www.reddit.com/r/cpp/comments/3vpjqg/a_new_platform_independent_process_library_for_c11/cxq1wsj
|
||||
std::mutex create_process_mutex;
|
||||
|
||||
//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 string_type &command, const string_type &path) noexcept {
|
||||
if(open_stdin)
|
||||
stdin_fd=std::unique_ptr<fd_type>(new fd_type(NULL));
|
||||
if(read_stdout)
|
||||
stdout_fd=std::unique_ptr<fd_type>(new fd_type(NULL));
|
||||
if(read_stderr)
|
||||
stderr_fd=std::unique_ptr<fd_type>(new fd_type(NULL));
|
||||
|
||||
Handle stdin_rd_p;
|
||||
Handle stdin_wr_p;
|
||||
Handle stdout_rd_p;
|
||||
Handle stdout_wr_p;
|
||||
Handle stderr_rd_p;
|
||||
Handle stderr_wr_p;
|
||||
|
||||
SECURITY_ATTRIBUTES security_attributes;
|
||||
|
||||
security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
security_attributes.bInheritHandle = TRUE;
|
||||
security_attributes.lpSecurityDescriptor = nullptr;
|
||||
|
||||
std::lock_guard<std::mutex> lock(create_process_mutex);
|
||||
if(stdin_fd) {
|
||||
if (!CreatePipe(&stdin_rd_p, &stdin_wr_p, &security_attributes, 0) ||
|
||||
!SetHandleInformation(stdin_wr_p, HANDLE_FLAG_INHERIT, 0))
|
||||
return 0;
|
||||
}
|
||||
if(stdout_fd) {
|
||||
if (!CreatePipe(&stdout_rd_p, &stdout_wr_p, &security_attributes, 0) ||
|
||||
!SetHandleInformation(stdout_rd_p, HANDLE_FLAG_INHERIT, 0)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(stderr_fd) {
|
||||
if (!CreatePipe(&stderr_rd_p, &stderr_wr_p, &security_attributes, 0) ||
|
||||
!SetHandleInformation(stderr_rd_p, HANDLE_FLAG_INHERIT, 0)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
PROCESS_INFORMATION process_info;
|
||||
STARTUPINFO startup_info;
|
||||
|
||||
ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
|
||||
startup_info.cb = sizeof(STARTUPINFO);
|
||||
startup_info.hStdInput = stdin_rd_p;
|
||||
startup_info.hStdOutput = stdout_wr_p;
|
||||
startup_info.hStdError = stderr_wr_p;
|
||||
if(stdin_fd || stdout_fd || stderr_fd)
|
||||
startup_info.dwFlags |= STARTF_USESTDHANDLES;
|
||||
|
||||
string_type process_command=command;
|
||||
#ifdef MSYS_PROCESS_USE_SH
|
||||
size_t pos=0;
|
||||
while((pos=process_command.find('\\', pos))!=string_type::npos) {
|
||||
process_command.replace(pos, 1, "\\\\\\\\");
|
||||
pos+=4;
|
||||
}
|
||||
pos=0;
|
||||
while((pos=process_command.find('\"', pos))!=string_type::npos) {
|
||||
process_command.replace(pos, 1, "\\\"");
|
||||
pos+=2;
|
||||
}
|
||||
process_command.insert(0, "sh -c \"");
|
||||
process_command+="\"";
|
||||
#endif
|
||||
|
||||
BOOL bSuccess = CreateProcess(nullptr, process_command.empty()?nullptr:&process_command[0], nullptr, nullptr, TRUE, 0,
|
||||
nullptr, path.empty()?nullptr:path.c_str(), &startup_info, &process_info);
|
||||
|
||||
if(!bSuccess) {
|
||||
CloseHandle(process_info.hProcess);
|
||||
CloseHandle(process_info.hThread);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
CloseHandle(process_info.hThread);
|
||||
}
|
||||
|
||||
if(stdin_fd) *stdin_fd=stdin_wr_p.detach();
|
||||
if(stdout_fd) *stdout_fd=stdout_rd_p.detach();
|
||||
if(stderr_fd) *stderr_fd=stderr_rd_p.detach();
|
||||
|
||||
closed=false;
|
||||
data.id=process_info.dwProcessId;
|
||||
data.handle=process_info.hProcess;
|
||||
return process_info.dwProcessId;
|
||||
}
|
||||
|
||||
void Process::async_read() noexcept {
|
||||
if(data.id==0)
|
||||
return;
|
||||
if(stdout_fd) {
|
||||
stdout_thread=std::thread([this](){
|
||||
DWORD n;
|
||||
std::unique_ptr<char[]> buffer(new char[buffer_size]);
|
||||
for (;;) {
|
||||
BOOL bSuccess = ReadFile(*stdout_fd, static_cast<CHAR*>(buffer.get()), static_cast<DWORD>(buffer_size), &n, nullptr);
|
||||
if(!bSuccess || n == 0)
|
||||
break;
|
||||
read_stdout(buffer.get(), static_cast<size_t>(n));
|
||||
}
|
||||
});
|
||||
}
|
||||
if(stderr_fd) {
|
||||
stderr_thread=std::thread([this](){
|
||||
DWORD n;
|
||||
std::unique_ptr<char[]> buffer(new char[buffer_size]);
|
||||
for (;;) {
|
||||
BOOL bSuccess = ReadFile(*stderr_fd, static_cast<CHAR*>(buffer.get()), static_cast<DWORD>(buffer_size), &n, nullptr);
|
||||
if(!bSuccess || n == 0)
|
||||
break;
|
||||
read_stderr(buffer.get(), static_cast<size_t>(n));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int Process::get_exit_status() noexcept {
|
||||
if(data.id==0)
|
||||
return -1;
|
||||
DWORD exit_status;
|
||||
WaitForSingleObject(data.handle, INFINITE);
|
||||
if(!GetExitCodeProcess(data.handle, &exit_status))
|
||||
exit_status=-1;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(close_mutex);
|
||||
CloseHandle(data.handle);
|
||||
closed=true;
|
||||
}
|
||||
close_fds();
|
||||
|
||||
return static_cast<int>(exit_status);
|
||||
}
|
||||
|
||||
void Process::close_fds() noexcept {
|
||||
if(stdout_thread.joinable())
|
||||
stdout_thread.join();
|
||||
if(stderr_thread.joinable())
|
||||
stderr_thread.join();
|
||||
|
||||
if(stdin_fd)
|
||||
close_stdin();
|
||||
if(stdout_fd) {
|
||||
if(*stdout_fd!=NULL) CloseHandle(*stdout_fd);
|
||||
stdout_fd.reset();
|
||||
}
|
||||
if(stderr_fd) {
|
||||
if(*stderr_fd!=NULL) CloseHandle(*stderr_fd);
|
||||
stderr_fd.reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool Process::write(const char *bytes, size_t n) {
|
||||
if(!open_stdin)
|
||||
throw std::invalid_argument("Can't write to an unopened stdin pipe. Please set open_stdin=true when constructing the process.");
|
||||
|
||||
std::lock_guard<std::mutex> lock(stdin_mutex);
|
||||
if(stdin_fd) {
|
||||
DWORD written;
|
||||
BOOL bSuccess=WriteFile(*stdin_fd, bytes, static_cast<DWORD>(n), &written, nullptr);
|
||||
if(!bSuccess || written==0) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Process::close_stdin() noexcept {
|
||||
std::lock_guard<std::mutex> lock(stdin_mutex);
|
||||
if(stdin_fd) {
|
||||
if(*stdin_fd!=NULL) CloseHandle(*stdin_fd);
|
||||
stdin_fd.reset();
|
||||
}
|
||||
}
|
||||
|
||||
//Based on http://stackoverflow.com/a/1173396
|
||||
void Process::kill(bool force) noexcept {
|
||||
std::lock_guard<std::mutex> lock(close_mutex);
|
||||
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_TERMINATE, FALSE, process.th32ProcessID);
|
||||
if(process_handle) {
|
||||
TerminateProcess(process_handle, 2);
|
||||
CloseHandle(process_handle);
|
||||
}
|
||||
}
|
||||
} while (Process32Next(snapshot, &process));
|
||||
}
|
||||
CloseHandle(snapshot);
|
||||
}
|
||||
TerminateProcess(data.handle, 2);
|
||||
}
|
||||
}
|
||||
|
||||
//Based on http://stackoverflow.com/a/1173396
|
||||
void Process::kill(id_type id, bool force) noexcept {
|
||||
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_TERMINATE, FALSE, process.th32ProcessID);
|
||||
if(process_handle) {
|
||||
TerminateProcess(process_handle, 2);
|
||||
CloseHandle(process_handle);
|
||||
}
|
||||
}
|
||||
} while (Process32Next(snapshot, &process));
|
||||
}
|
||||
CloseHandle(snapshot);
|
||||
}
|
||||
HANDLE process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, id);
|
||||
if(process_handle) TerminateProcess(process_handle, 2);
|
||||
}
|
||||
|
||||
} // TinyProsessLib
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user