add process tests
This commit is contained in:
@@ -62,28 +62,49 @@
|
||||
|
||||
|
||||
namespace {
|
||||
enum class PipeDirection {
|
||||
Read,
|
||||
Write,
|
||||
Last = Write
|
||||
enum PipeDirection {
|
||||
PipeRead,
|
||||
PipeWrite,
|
||||
PipeLast = PipeWrite
|
||||
};
|
||||
|
||||
enum class StdFile {
|
||||
In,
|
||||
Out,
|
||||
Err,
|
||||
Last = Err
|
||||
enum StdFile {
|
||||
StdIn,
|
||||
StdOut,
|
||||
StdErr,
|
||||
StdLast = StdErr
|
||||
};
|
||||
|
||||
constexpr int PipesDirections = static_cast<int>(PipeDirection::Last) + 1;
|
||||
constexpr int StdFileCount = static_cast<int>(StdFile::Last) + 1;
|
||||
constexpr int PipesDirections = PipeLast + 1;
|
||||
constexpr int StdFileCount = StdLast + 1;
|
||||
|
||||
#ifdef WINDOWS
|
||||
# ifdef WINDOWS
|
||||
using PipeHandleType = HANDLE;
|
||||
#else
|
||||
# else
|
||||
using PipeHandleType = int;
|
||||
#endif
|
||||
# endif
|
||||
|
||||
# ifdef WINDOWS
|
||||
const char * convertWindowsCmd(PIStringList sl) {
|
||||
for (int i = 0; i < sl.size_s(); ++i) {
|
||||
sl[i].push_front('"');
|
||||
sl[i].push_back('"');
|
||||
}
|
||||
PIString s = sl.join(' ');
|
||||
return s.data();
|
||||
}
|
||||
# else
|
||||
char * const * convertToCharArrays(const PIStringList & sl) {
|
||||
char ** cc = new char *[sl.size() + 1];
|
||||
for (int i = 0; i < sl.size_s(); ++i) {
|
||||
cc[i] = const_cast<char *>(sl[i].data());
|
||||
}
|
||||
cc[sl.size()] = 0;
|
||||
return cc;
|
||||
}
|
||||
# endif
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(PIProcess)
|
||||
@@ -111,20 +132,20 @@ PRIVATE_DEFINITION_START(PIProcess)
|
||||
|
||||
bool createPipe(StdFile pipe_type) {
|
||||
const int pt = static_cast<int>(pipe_type);
|
||||
#ifdef WINDOWS
|
||||
# ifdef WINDOWS
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
if (!CreatePipe(&(pipes[pt][PipeDirection::Read]), &(pipes[pt][PipeDirection::Write]), &saAttr, 0)) {
|
||||
piCout << "CreatePipe failed: " << GetLastError() << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
# else
|
||||
int ret = pipe(pipes[pt]);
|
||||
return ret != -1;
|
||||
#endif
|
||||
# endif
|
||||
return false;
|
||||
}
|
||||
PRIVATE_DEFINITION_END(PIProcess)
|
||||
@@ -136,9 +157,9 @@ PIProcess::PIProcess(): PIThread() {
|
||||
PRIVATE->pi.dwProcessId = 0;
|
||||
# else
|
||||
PRIVATE->pid = 0;
|
||||
PRIVATE->forEachPipe([](PipeHandleType & pipe) { pipe = -1; });
|
||||
# endif
|
||||
is_exec = false;
|
||||
PRIVATE->forEachPipe([](PipeHandleType & pipe) { pipe = 0;});
|
||||
PRIVATE->initGrab();
|
||||
env = PIProcess::currentEnvironment();
|
||||
}
|
||||
@@ -161,49 +182,14 @@ void PIProcess::exec_() {
|
||||
|
||||
void PIProcess::startProc(bool detached) {
|
||||
// cout << "run" << endl;
|
||||
PIString str;
|
||||
const PIString & str = args.front();
|
||||
/// arguments convertion
|
||||
int as = 0;
|
||||
const char * argscc[args.size() + 1];
|
||||
int argsl[args.size()];
|
||||
for (int i = 0; i < args.size_s(); ++i) {
|
||||
argscc[i] = args[i].data();
|
||||
argsl[i] = strlen(argscc[i]);
|
||||
as += argsl[i] + 3;
|
||||
}
|
||||
argscc[args.size()] = 0;
|
||||
# ifdef WINDOWS
|
||||
char * a = new char[as];
|
||||
memset(a, ' ', as - 1);
|
||||
as = 0;
|
||||
for (int i = 0; i < args.size_s(); ++i) {
|
||||
str = args[i];
|
||||
a[as] = '"';
|
||||
memcpy(&(a[as + 1]), argscc[i], argsl[i]);
|
||||
a[as + argsl[i] + 1] = '"';
|
||||
as += argsl[i] + 3;
|
||||
}
|
||||
a[as - 1] = 0;
|
||||
// piCout << a;
|
||||
# endif
|
||||
# ifndef WINDOWS
|
||||
/// environment convertion
|
||||
const char * envcc[env.size() + 1];
|
||||
envcc[env.size_s()] = 0;
|
||||
for (int i = 0; i < env.size_s(); ++i) {
|
||||
envcc[i] = env[i].data();
|
||||
}
|
||||
# endif
|
||||
|
||||
/// files for stdin/out/err
|
||||
|
||||
str = args.front();
|
||||
is_exec = true;
|
||||
is_exec = true;
|
||||
if (!detached) execStarted(str);
|
||||
# ifndef WINDOWS
|
||||
int pid_ = fork();
|
||||
if (!detached) PRIVATE->pid = pid_;
|
||||
if (pid_ == 0) {
|
||||
# endif
|
||||
|
||||
// PRIVATE->tf_in = PRIVATE->tf_out = PRIVATE->tf_err = 0;
|
||||
// // cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;
|
||||
// // cout << f_out.path() << endl;
|
||||
@@ -212,41 +198,45 @@ void PIProcess::startProc(bool detached) {
|
||||
// if (g_err) PRIVATE->tf_err = freopen(f_err.path().data(), "w", stderr);
|
||||
|
||||
# ifdef WINDOWS
|
||||
STARTUPINFOA si;
|
||||
piZeroMemory(pi);
|
||||
si.cb = sizeof(STARTUPINFOA);
|
||||
if (PRIVATE->grab[StdFile::In]) si.hStdInput = PRIVATE->pipes[StdFile::In][PipeDirection::Read];
|
||||
if (PRIVATE->grab[StdFile::Out]) si.hStdOutput = PRIVATE->pipes[StdFile::Out][PipeDirection::Write];
|
||||
if (PRIVATE->grab[StdFile::Err]) si.hStdError = PRIVATE->pipes[StdFile::Err][PipeDirection::Write];
|
||||
si.dwFlags |= STARTF_USESTDHANDLES;
|
||||
if (CreateProcessA(0, // No module name (use command line)
|
||||
a, // Command line
|
||||
0, // Process handle not inheritable
|
||||
0, // Thread handle not inheritable
|
||||
false, // Set handle inheritance to FALSE
|
||||
detached ? DETACHED_PROCESS /*CREATE_NEW_CONSOLE*/ : 0, // Creation flags
|
||||
0, // envcc, // Use environment
|
||||
wd.isEmpty() ? 0 : wd.data(), // Use working directory
|
||||
&si, // Pointer to STARTUPINFO structure
|
||||
&(PRIVATE->pi))) // Pointer to PROCESS_INFORMATION structure
|
||||
{
|
||||
if (!detached) {
|
||||
WaitForSingleObject(PRIVATE->pi.hProcess, INFINITE);
|
||||
DWORD code = -1;
|
||||
if (GetExitCodeProcess(PRIVATE->pi.hProcess, &code) != 0) exit_code = code;
|
||||
}
|
||||
CloseHandle(PRIVATE->pi.hThread);
|
||||
CloseHandle(PRIVATE->pi.hProcess);
|
||||
} else {
|
||||
piCoutObj << "\"CreateProcess\" error: %1"_tr("PIProcess").arg(errorString());
|
||||
STARTUPINFOA si;
|
||||
piZeroMemory(pi);
|
||||
si.cb = sizeof(STARTUPINFOA);
|
||||
if (PRIVATE->grab[StdFile::In]) si.hStdInput = PRIVATE->pipes[StdFile::In][PipeDirection::Read];
|
||||
if (PRIVATE->grab[StdFile::Out]) si.hStdOutput = PRIVATE->pipes[StdFile::Out][PipeDirection::Write];
|
||||
if (PRIVATE->grab[StdFile::Err]) si.hStdError = PRIVATE->pipes[StdFile::Err][PipeDirection::Write];
|
||||
si.dwFlags |= STARTF_USESTDHANDLES;
|
||||
if (CreateProcessA(0, // No module name (use command line)
|
||||
convertWindowsCmd(args), // Command line
|
||||
0, // Process handle not inheritable
|
||||
0, // Thread handle not inheritable
|
||||
false, // Set handle inheritance to FALSE
|
||||
detached ? DETACHED_PROCESS /*CREATE_NEW_CONSOLE*/ : 0, // Creation flags
|
||||
0, // Use environment
|
||||
wd.isEmpty() ? 0 : wd.data(), // Use working directory
|
||||
&si, // Pointer to STARTUPINFO structure
|
||||
&(PRIVATE->pi))) // Pointer to PROCESS_INFORMATION structure
|
||||
{
|
||||
if (!detached) {
|
||||
WaitForSingleObject(PRIVATE->pi.hProcess, INFINITE);
|
||||
DWORD code = -1;
|
||||
if (GetExitCodeProcess(PRIVATE->pi.hProcess, &code) != 0) exit_code = code;
|
||||
}
|
||||
# endif
|
||||
# ifndef WINDOWS
|
||||
CloseHandle(PRIVATE->pi.hThread);
|
||||
CloseHandle(PRIVATE->pi.hProcess);
|
||||
} else {
|
||||
piCoutObj << "\"CreateProcess\" error: %1"_tr("PIProcess").arg(errorString());
|
||||
}
|
||||
# else
|
||||
auto largs = convertToCharArrays(args);
|
||||
auto lenv = convertToCharArrays(env);
|
||||
int pid_ = fork();
|
||||
if (!detached) PRIVATE->pid = pid_;
|
||||
if (pid_ == 0) {
|
||||
if (!wd.isEmpty()) {
|
||||
if (!chdir(wd.data())) piCoutObj << "Error while set working directory";
|
||||
}
|
||||
// cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;
|
||||
if (execve(str.data(), (char * const *)argscc, (char * const *)envcc) < 0) {
|
||||
if (execve(str.data(), largs, lenv) < 0) {
|
||||
piCoutObj << "\"execve" << str << args << "\" error :" << errorString();
|
||||
}
|
||||
} else {
|
||||
@@ -259,12 +249,11 @@ void PIProcess::startProc(bool detached) {
|
||||
// cout << "wait done" << endl;
|
||||
}
|
||||
}
|
||||
delete[] largs;
|
||||
delete[] lenv;
|
||||
# endif
|
||||
if (!detached) execFinished(str, exit_code);
|
||||
is_exec = false;
|
||||
# ifdef WINDOWS
|
||||
delete[] a;
|
||||
# endif
|
||||
}
|
||||
|
||||
// PIByteArray PIProcess::readFile(PIFile & f, bool clear)
|
||||
@@ -280,8 +269,7 @@ void PIProcess::startProc(bool detached) {
|
||||
|
||||
void PIProcess::terminate() {
|
||||
# ifdef WINDOWS
|
||||
if (is_exec)
|
||||
{
|
||||
if (is_exec) {
|
||||
if (!TerminateProcess(PRIVATE->pi.hProcess, 0)) return;
|
||||
}
|
||||
PRIVATE->pi.dwProcessId = 0;
|
||||
@@ -308,13 +296,28 @@ int PIProcess::pID() const {
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIProcess::readOutput(bool clear) {
|
||||
return {}; //readFile(f_out, clear);
|
||||
PIByteArray PIProcess::readOutput() {
|
||||
return {}; // readFile(f_out, clear);
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIProcess::readError(bool clear) {
|
||||
return {}; //readFile(f_err, clear);
|
||||
PIByteArray PIProcess::readError() {
|
||||
return {}; // readFile(f_err, clear);
|
||||
}
|
||||
|
||||
bool PIProcess::writeInput(const PIByteArray &data)
|
||||
{
|
||||
if (PRIVATE->grab[StdIn]) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PIProcess::closeInput()
|
||||
{
|
||||
if (PRIVATE->grab[StdIn]) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -68,11 +68,19 @@ public:
|
||||
|
||||
//! \~english Returns all attached execution output stream
|
||||
//! \~russian
|
||||
PIByteArray readOutput(bool clear = false);
|
||||
PIByteArray readOutput();
|
||||
|
||||
//! \~english Returns all attached execution error stream
|
||||
//! \~russian
|
||||
PIByteArray readError(bool clear = false);
|
||||
PIByteArray readError();
|
||||
|
||||
//! \~english Write data to attached execution input stream
|
||||
//! \~russian
|
||||
bool writeInput(const PIByteArray & data);
|
||||
|
||||
//! \~english Close attached execution input stream and send EOF
|
||||
//! \~russian
|
||||
void closeInput();
|
||||
|
||||
//! \~english Returns current attached execution environment
|
||||
//! \~russian
|
||||
|
||||
Reference in New Issue
Block a user