Add backend to launch subprocess.

The windows backend is not tested.
This commit is contained in:
Matthieu Gautier 2018-08-29 11:40:35 +02:00
parent c351e7ccf1
commit f3dd83907d
7 changed files with 304 additions and 0 deletions

View File

@ -6,6 +6,7 @@ kiwix_sources = [
'reader.cpp', 'reader.cpp',
'entry.cpp', 'entry.cpp',
'searcher.cpp', 'searcher.cpp',
'subprocess.cpp',
'common/base64.cpp', 'common/base64.cpp',
'common/pathTools.cpp', 'common/pathTools.cpp',
'common/regexTools.cpp', 'common/regexTools.cpp',
@ -17,6 +18,12 @@ kiwix_sources = [
] ]
kiwix_sources += lib_resources kiwix_sources += lib_resources
if host_machine.system() == 'windows'
kiwix_sources += 'subprocess_windows.cpp'
else
kiwix_sources += 'subprocess_unix.cpp'
endif
if xapian_dep.found() if xapian_dep.found()
kiwix_sources += ['xapianSearcher.cpp'] kiwix_sources += ['xapianSearcher.cpp']
endif endif

40
src/subprocess.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "subprocess.h"
#ifdef _WIN32
# include "subprocess_windows.h"
#else
# include "subprocess_unix.h"
#endif
Subprocess::Subprocess(std::unique_ptr<SubprocessImpl> impl, const commandLine_t& commandLine) :
mp_impl(std::move(impl))
{
mp_impl->run(commandLine);
}
Subprocess::~Subprocess()
{
mp_impl->kill();
}
std::unique_ptr<Subprocess> Subprocess::run(const commandLine_t& commandLine)
{
#ifdef _WIN32
auto impl = std::unique_ptr<SubprocessImpl>(new WinImpl);
#else
auto impl = std::unique_ptr<UnixImpl>(new UnixImpl);
#endif
return std::unique_ptr<Subprocess>(new Subprocess(std::move(impl), commandLine));
}
bool Subprocess::isRunning()
{
return mp_impl->isRunning();
}
bool Subprocess::kill()
{
return mp_impl->kill();
}

36
src/subprocess.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef KIWIX_SUBPROCESS_H_
#define KIWIX_SUBPROCESS_H_
#include <string>
#include <memory>
#include <vector>
typedef std::vector<const char *> commandLine_t;
class SubprocessImpl
{
public:
virtual void run(const commandLine_t& commandLine) = 0;
virtual bool kill() = 0;
virtual bool isRunning() = 0;
virtual ~SubprocessImpl() = default;
};
class Subprocess
{
private:
// Impl depends of the system (window, unix, ...)
std::unique_ptr<SubprocessImpl> mp_impl;
Subprocess(std::unique_ptr<SubprocessImpl> impl, const commandLine_t& commandLine);
public:
static std::unique_ptr<Subprocess> run(const commandLine_t& commandLine);
~Subprocess();
bool isRunning();
bool kill();
};
#endif // KIWIX_SUBPROCESS_H_

72
src/subprocess_unix.cpp Normal file
View File

@ -0,0 +1,72 @@
#include "subprocess_unix.h"
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <signal.h>
#include <sys/wait.h>
UnixImpl::UnixImpl():
m_pid(0),
m_running(false),
m_mutex(PTHREAD_MUTEX_INITIALIZER),
m_waitingThread()
{
}
UnixImpl::~UnixImpl()
{
kill();
pthread_cancel(m_waitingThread);
}
void* UnixImpl::waitForPID(void* _self)
{
UnixImpl* self = static_cast<UnixImpl*>(_self);
waitpid(self->m_pid, NULL, WEXITED);
pthread_mutex_lock(&self->m_mutex);
self->m_running = false;
pthread_mutex_unlock(&self->m_mutex);
return self;
}
void UnixImpl::run(const commandLine_t& commandLine)
{
const char* binary = commandLine[0];
std::cerr << "running " << binary << std::endl;
int pid = fork();
switch(pid) {
case -1:
std::cerr << "cannot fork" << std::endl;
break;
case 0:
if (execvp(binary, const_cast<char* const*>(commandLine.data()))) {
perror("Cannot launch\n");
exit(-1);
}
break;
default:
m_pid = pid;
m_running = true;
pthread_create(&m_waitingThread, NULL, waitForPID, this);
break;
}
}
bool UnixImpl::kill()
{
return (::kill(m_pid, SIGKILL) == 0);
}
bool UnixImpl::isRunning()
{
pthread_mutex_lock(&m_mutex);
bool ret = m_running;
pthread_mutex_unlock(&m_mutex);
return ret;
}

28
src/subprocess_unix.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef KIWIX_SUBPROCESS_UNIX_H_
#define KIWIX_SUBPROCESS_UNIX_H_
#include "subprocess.h"
#include <pthread.h>
class UnixImpl : public SubprocessImpl
{
private:
int m_pid;
bool m_running;
pthread_mutex_t m_mutex;
pthread_t m_waitingThread;
public:
UnixImpl();
virtual ~UnixImpl();
void run(const commandLine_t& commandLine);
bool kill();
bool isRunning();
static void* waitForPID(void* self);
};
#endif //KIWIX_SUBPROCESS_UNIX_H_

View File

@ -0,0 +1,94 @@
#include "subprocess_windows.h"
#include <windows.h>
#include <winbase.h>
#include <iostream>
#include <sstream>
WinImpl::WinImpl():
m_pid(0),
m_running(false),
m_handle(INVALID_HANDLE_VALUE)
{
InitializeCriticalSection(&m_criticalSection);
}
WinImpl::~WinImpl()
{
kill();
CloseHandle(m_handle);
DeleteCriticalSection(&m_criticalSection);
}
DWORD WINAPI WinImpl::waitForPID(void* _self)
{
WinImpl* self = static_cast<WinImpl*>(_self);
WaitForSingleObject(self->m_handle, INFINITE);
EnterCriticalSection(&self->m_criticalSection);
self->m_running = false;
LeaveCriticalSection(&self->m_criticalSection);
return 0;
}
std::unique_ptr<wchar_t[]> toWideChar(const std::string& value)
{
auto size = MultiByteToWideChar(CP_UTF8, 0,
value.c_str(), -1, nullptr, 0);
auto wdata = std::unique_ptr<wchar_t[]>(new wchar_t[size]);
auto ret = MultiByteToWideChar(CP_UTF8, 0,
value.c_str(), -1, wdata.get(), size);
if (0 == ret) {
std::ostringstream oss;
oss << "Cannot convert to wchar : " << GetLastError();
throw std::runtime_error(oss.str());
}
return wdata;
}
void WinImpl::run(const commandLine_t& commandLine)
{
STARTUPINFOW startInfo = {0};
PROCESS_INFORMATION procInfo;
startInfo.cb = sizeof(startInfo);
const char* binary = commandLine[0];
std::cerr << "running " << binary << std::endl;
std::ostringstream oss;
for(auto& item: commandLine) {
oss << item << " ";
}
if (CreateProcessW(
toWideChar(binary).get(),
toWideChar(oss.str()).get(),
NULL,
NULL,
false,
CREATE_NO_WINDOW,
NULL,
NULL,
&startInfo,
&procInfo)) {
m_pid = procInfo.dwProcessId;
m_handle = procInfo.hProcess;
CloseHandle(procInfo.hThread);
m_running = true;
CreateThread(NULL, 0, &waitForPID, this, 0, NULL );
}
}
bool WinImpl::kill()
{
return TerminateProcess(m_handle, 0);
}
bool WinImpl::isRunning()
{
EnterCriticalSection(&m_criticalSection);
bool ret = m_running;
LeaveCriticalSection(&m_criticalSection);
return ret;
}

27
src/subprocess_windows.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef KIWIX_SUBPROCESS_WINDOWS_H_
#define KIWIX_SUBPROCESS_WINDOWS_H_
#include "subprocess.h"
#include <synchapi.h>
class WinImpl : public SubprocessImpl
{
private:
int m_pid;
bool m_running;
HANDLE m_handle;
CRITICAL_SECTION m_criticalSection;
public:
WinImpl();
virtual ~WinImpl();
void run(const commandLine_t& commandLine);
bool kill();
bool isRunning();
static DWORD WINAPI waitForPID(void* self);
};
#endif //KIWIX_SUBPROCESS_WINDOWS_H_