mirror of https://github.com/kiwix/libkiwix.git
Add backend to launch subprocess.
The windows backend is not tested.
This commit is contained in:
parent
c351e7ccf1
commit
f3dd83907d
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -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_
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_
|
Loading…
Reference in New Issue