mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 05:16:21 +00:00
merge the Forked* machinery into a single pair of files
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21863 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
parent
28afd72c65
commit
1aafa6ff77
@ -81,7 +81,7 @@
|
||||
#include "support/debug.h"
|
||||
#include "support/FileFilterList.h"
|
||||
#include "support/filetools.h"
|
||||
#include "support/Forkedcall.h"
|
||||
#include "support/ForkedCalls.h"
|
||||
#include "support/gettext.h"
|
||||
#include "support/gzstream.h"
|
||||
#include "support/lstrings.h"
|
||||
|
@ -15,14 +15,14 @@
|
||||
#include "ISpell.h"
|
||||
|
||||
#include "BufferParams.h"
|
||||
#include "support/debug.h"
|
||||
#include "Encoding.h"
|
||||
#include "support/gettext.h"
|
||||
#include "Language.h"
|
||||
#include "LyXRC.h"
|
||||
#include "WordLangTuple.h"
|
||||
|
||||
#include "support/Forkedcall.h"
|
||||
#include "support/debug.h"
|
||||
#include "support/gettext.h"
|
||||
#include "support/ForkedCalls.h"
|
||||
#include "support/lstrings.h"
|
||||
#include "support/unicode.h"
|
||||
|
||||
|
@ -18,10 +18,8 @@
|
||||
#include "BufferView.h"
|
||||
#include "CoordCache.h"
|
||||
#include "Cursor.h"
|
||||
#include "support/debug.h"
|
||||
#include "Font.h"
|
||||
#include "FuncRequest.h"
|
||||
#include "support/gettext.h"
|
||||
#include "GuiApplication.h"
|
||||
#include "GuiKeySymbol.h"
|
||||
#include "GuiPainter.h"
|
||||
@ -37,8 +35,10 @@
|
||||
#include "graphics/GraphicsImage.h"
|
||||
#include "graphics/GraphicsLoader.h"
|
||||
|
||||
#include "support/debug.h"
|
||||
#include "support/gettext.h"
|
||||
#include "support/FileName.h"
|
||||
#include "support/ForkedcallsController.h"
|
||||
#include "support/ForkedCalls.h"
|
||||
|
||||
#include "frontends/Application.h"
|
||||
#include "frontends/FontMetrics.h"
|
||||
@ -79,7 +79,7 @@ using std::string;
|
||||
namespace lyx {
|
||||
|
||||
using support::FileName;
|
||||
using support::ForkedcallsController;
|
||||
using support::ForkedCallsController;
|
||||
|
||||
|
||||
/// return the LyX mouse button state from Qt's
|
||||
@ -458,7 +458,7 @@ void GuiWorkArea::toggleCursor()
|
||||
// Use this opportunity to deal with any child processes that
|
||||
// have finished but are waiting to communicate this fact
|
||||
// to the rest of LyX.
|
||||
ForkedcallsController & fcc = ForkedcallsController::get();
|
||||
ForkedCallsController & fcc = ForkedCallsController::get();
|
||||
fcc.handleCompletedProcesses();
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,12 @@
|
||||
#include "GraphicsConverter.h"
|
||||
|
||||
#include "Converter.h"
|
||||
#include "support/debug.h"
|
||||
#include "Format.h"
|
||||
|
||||
#include "support/filetools.h"
|
||||
#include "support/ForkedCallQueue.h"
|
||||
#include "support/convert.h"
|
||||
#include "support/debug.h"
|
||||
#include "support/filetools.h"
|
||||
#include "support/ForkedCalls.h"
|
||||
#include "support/lstrings.h"
|
||||
#include "support/lyxlib.h"
|
||||
#include "support/os.h"
|
||||
@ -33,7 +33,7 @@ namespace support = lyx::support;
|
||||
using support::addExtension;
|
||||
using support::changeExtension;
|
||||
using support::FileName;
|
||||
using support::Forkedcall;
|
||||
using support::ForkedCall;
|
||||
using support::ForkedCallQueue;
|
||||
using support::getExtension;
|
||||
using support::libScriptSearch;
|
||||
@ -193,7 +193,7 @@ void Converter::Impl::startConversion()
|
||||
return;
|
||||
}
|
||||
|
||||
Forkedcall::SignalTypePtr
|
||||
ForkedCall::SignalTypePtr
|
||||
ptr = ForkedCallQueue::get().add(script_command_);
|
||||
|
||||
ptr->connect(boost::bind(&Impl::converted, this, _1, _2));
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "Buffer.h"
|
||||
#include "BufferParams.h"
|
||||
#include "Converter.h"
|
||||
#include "support/debug.h"
|
||||
#include "Encoding.h"
|
||||
#include "Format.h"
|
||||
#include "InsetIterator.h"
|
||||
@ -31,12 +30,12 @@
|
||||
|
||||
#include "insets/Inset.h"
|
||||
|
||||
#include "support/convert.h"
|
||||
#include "support/debug.h"
|
||||
#include "support/filetools.h"
|
||||
#include "support/Forkedcall.h"
|
||||
#include "support/ForkedcallsController.h"
|
||||
#include "support/ForkedCalls.h"
|
||||
#include "support/lstrings.h"
|
||||
#include "support/lyxlib.h"
|
||||
#include "support/convert.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
@ -229,7 +228,7 @@ public:
|
||||
Buffer const & buffer() const { return buffer_; }
|
||||
|
||||
private:
|
||||
/// Called by the Forkedcall process that generated the bitmap files.
|
||||
/// Called by the ForkedCall process that generated the bitmap files.
|
||||
void finishedGenerating(pid_t, int);
|
||||
///
|
||||
void dumpPreamble(odocstream &) const;
|
||||
@ -384,7 +383,7 @@ InProgress::InProgress(string const & filename_base,
|
||||
void InProgress::stop() const
|
||||
{
|
||||
if (pid)
|
||||
lyx::support::ForkedcallsController::get().kill(pid, 0);
|
||||
lyx::support::ForkedCallsController::get().kill(pid, 0);
|
||||
|
||||
if (!metrics_file.empty())
|
||||
metrics_file.removeFile();
|
||||
@ -608,12 +607,12 @@ void PreviewLoader::Impl::startLoading()
|
||||
string const command = support::libScriptSearch(cs.str());
|
||||
|
||||
// Initiate the conversion from LaTeX to bitmap images files.
|
||||
support::Forkedcall::SignalTypePtr
|
||||
convert_ptr(new support::Forkedcall::SignalType);
|
||||
support::ForkedCall::SignalTypePtr
|
||||
convert_ptr(new support::ForkedCall::SignalType);
|
||||
convert_ptr->connect(bind(&Impl::finishedGenerating, this, _1, _2));
|
||||
|
||||
support::Forkedcall call;
|
||||
int ret = call.startscript(command, convert_ptr);
|
||||
support::ForkedCall call;
|
||||
int ret = call.startScript(command, convert_ptr);
|
||||
|
||||
if (ret != 0) {
|
||||
LYXERR(Debug::GRAPHICS, "PreviewLoader::startLoading()\n"
|
||||
|
@ -18,8 +18,6 @@
|
||||
|
||||
#include "Buffer.h"
|
||||
#include "Converter.h"
|
||||
#include "support/debug.h"
|
||||
#include "support/gettext.h"
|
||||
#include "ErrorList.h"
|
||||
#include "Exporter.h"
|
||||
#include "Format.h"
|
||||
@ -27,8 +25,9 @@
|
||||
|
||||
#include "frontends/alert.h"
|
||||
|
||||
#include "support/debug.h"
|
||||
#include "support/filetools.h"
|
||||
#include "support/Forkedcall.h"
|
||||
#include "support/gettext.h"
|
||||
#include "support/lstrings.h"
|
||||
#include "support/lyxalgo.h"
|
||||
#include "support/lyxlib.h"
|
||||
|
@ -1,99 +0,0 @@
|
||||
/**
|
||||
* \file ForkedCallQueue.cpp
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Alfredo Braunstein (based on an idea from Angus Leeming)
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "support/ForkedCallQueue.h"
|
||||
|
||||
#include "support/debug.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
|
||||
using std::string;
|
||||
using std::endl;
|
||||
|
||||
|
||||
namespace lyx {
|
||||
namespace support {
|
||||
|
||||
ForkedCallQueue & ForkedCallQueue::get()
|
||||
{
|
||||
static ForkedCallQueue singleton;
|
||||
return singleton;
|
||||
}
|
||||
|
||||
|
||||
Forkedcall::SignalTypePtr ForkedCallQueue::add(string const & process)
|
||||
{
|
||||
Forkedcall::SignalTypePtr ptr;
|
||||
ptr.reset(new Forkedcall::SignalType);
|
||||
callQueue_.push(Process(process, ptr));
|
||||
if (!running_) {
|
||||
startCaller();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void ForkedCallQueue::callNext()
|
||||
{
|
||||
if (callQueue_.empty())
|
||||
return;
|
||||
Process pro = callQueue_.front();
|
||||
callQueue_.pop();
|
||||
// Bind our chain caller
|
||||
pro.second->connect(boost::bind(&ForkedCallQueue::callback,
|
||||
this, _1, _2));
|
||||
Forkedcall call;
|
||||
// If we fail to fork the process, then emit the signal
|
||||
// to tell the outside world that it failed.
|
||||
if (call.startscript(pro.first, pro.second) > 0) {
|
||||
pro.second->operator()(0,1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ForkedCallQueue::callback(pid_t, int)
|
||||
{
|
||||
if (callQueue_.empty())
|
||||
stopCaller();
|
||||
else
|
||||
callNext();
|
||||
}
|
||||
|
||||
|
||||
ForkedCallQueue::ForkedCallQueue()
|
||||
: running_(false)
|
||||
{}
|
||||
|
||||
|
||||
void ForkedCallQueue::startCaller()
|
||||
{
|
||||
LYXERR(Debug::GRAPHICS, "ForkedCallQueue: waking up");
|
||||
running_ = true ;
|
||||
callNext();
|
||||
}
|
||||
|
||||
|
||||
void ForkedCallQueue::stopCaller()
|
||||
{
|
||||
running_ = false ;
|
||||
LYXERR(Debug::GRAPHICS, "ForkedCallQueue: I'm going to sleep");
|
||||
}
|
||||
|
||||
|
||||
bool ForkedCallQueue::running() const
|
||||
{
|
||||
return running_ ;
|
||||
}
|
||||
|
||||
} // namespace support
|
||||
} // namespace lyx
|
@ -1,68 +0,0 @@
|
||||
// -*- C++ -*-
|
||||
/**
|
||||
* \file ForkedCallQueue.h
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Alfredo Braunstein (based on an idea from Angus Leeming)
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*
|
||||
* This class implements a queue of forked processes. In order not to
|
||||
* hose the system with multiple processes running simultaneously, you can
|
||||
* request the addition of your process to this queue and it will be
|
||||
* executed when its turn comes.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FORKEDCALLQUEUE_H
|
||||
#define FORKEDCALLQUEUE_H
|
||||
|
||||
#include "support/Forkedcall.h"
|
||||
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace lyx {
|
||||
namespace support {
|
||||
|
||||
class ForkedCallQueue {
|
||||
public:
|
||||
/// A process in the queue
|
||||
typedef std::pair<std::string, Forkedcall::SignalTypePtr> Process;
|
||||
/** Add a process to the queue. Processes are forked sequentially
|
||||
* only one is running at a time.
|
||||
* Connect to the returned signal and you'll be informed when
|
||||
* the process has ended.
|
||||
*/
|
||||
Forkedcall::SignalTypePtr add(std::string const & process);
|
||||
/// Query whether the queue is running a forked process now.
|
||||
bool running() const;
|
||||
/// Get the and only instance of the class
|
||||
static ForkedCallQueue & get();
|
||||
|
||||
private:
|
||||
|
||||
/** this class is a singleton class... use
|
||||
* ForkedCallQueue::get() instead
|
||||
*/
|
||||
ForkedCallQueue();
|
||||
/// in-progress queue
|
||||
std::queue<Process> callQueue_;
|
||||
///
|
||||
bool running_;
|
||||
///
|
||||
void callNext();
|
||||
///
|
||||
void startCaller();
|
||||
///
|
||||
void stopCaller();
|
||||
///
|
||||
void callback(pid_t, int);
|
||||
};
|
||||
|
||||
} // namespace support
|
||||
} // namespace lyx
|
||||
|
||||
#endif // FORKEDCALLQUEUE_H
|
@ -1,34 +1,21 @@
|
||||
/**
|
||||
* \file Forkedcall.cpp
|
||||
* \file ForkedCalls.cpp
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Asger Alstrup
|
||||
*
|
||||
* Interface cleaned up by
|
||||
* \author Angus Leeming
|
||||
* \author Alfredo Braunstein
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*
|
||||
* An instance of Class Forkedcall represents a single child process.
|
||||
*
|
||||
* Class Forkedcall uses fork() and execvp() to lauch the child process.
|
||||
*
|
||||
* Once launched, control is returned immediately to the parent process
|
||||
* but a Signal can be emitted upon completion of the child.
|
||||
*
|
||||
* The child process is not killed when the Forkedcall instance goes out of
|
||||
* scope, but it can be killed by an explicit invocation of the kill() member
|
||||
* function.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "support/Forkedcall.h"
|
||||
#include "support/ForkedCalls.h"
|
||||
|
||||
#include "support/debug.h"
|
||||
#include "support/filetools.h"
|
||||
#include "support/ForkedcallsController.h"
|
||||
#include "support/lstrings.h"
|
||||
#include "support/lyxlib.h"
|
||||
#include "support/os.h"
|
||||
@ -38,13 +25,13 @@
|
||||
|
||||
#include <vector>
|
||||
#include <cerrno>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
# define SIGHUP 1
|
||||
# define SIGKILL 9
|
||||
# include <process.h>
|
||||
# include <windows.h>
|
||||
|
||||
# include <process.h>
|
||||
#else
|
||||
# include <csignal>
|
||||
# include <cstdlib>
|
||||
@ -52,22 +39,32 @@
|
||||
# include <unistd.h>
|
||||
# endif
|
||||
# include <sys/wait.h>
|
||||
# ifndef CXX_GLOBAL_CSTD
|
||||
using std::signal;
|
||||
using std::strerror;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
using boost::bind;
|
||||
|
||||
using std::endl;
|
||||
using std::equal_to;
|
||||
using std::find_if;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#ifndef CXX_GLOBAL_CSTD
|
||||
using std::strerror;
|
||||
#endif
|
||||
|
||||
namespace lyx {
|
||||
namespace support {
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Murder
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
class Murder : public boost::signals::trackable {
|
||||
public:
|
||||
//
|
||||
@ -83,9 +80,8 @@ public:
|
||||
//
|
||||
void kill()
|
||||
{
|
||||
if (pid_ != 0) {
|
||||
if (pid_ != 0)
|
||||
support::kill(pid_, SIGKILL);
|
||||
}
|
||||
lyxerr << "Killed " << pid_ << std::endl;
|
||||
delete this;
|
||||
}
|
||||
@ -114,6 +110,12 @@ private:
|
||||
} // namespace anon
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ForkedProcess
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
ForkedProcess::ForkedProcess()
|
||||
: pid_(0), retval_(0)
|
||||
{}
|
||||
@ -143,7 +145,7 @@ int ForkedProcess::run(Starttype type)
|
||||
break;
|
||||
case DontWait: {
|
||||
// Integrate into the Controller
|
||||
ForkedcallsController & contr = ForkedcallsController::get();
|
||||
ForkedCallsController & contr = ForkedCallsController::get();
|
||||
contr.addCall(*this);
|
||||
break;
|
||||
}
|
||||
@ -261,10 +263,17 @@ int ForkedProcess::waitForChild()
|
||||
}
|
||||
|
||||
|
||||
int Forkedcall::startscript(Starttype wait, string const & what)
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ForkedCall
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
int ForkedCall::startScript(Starttype wait, string const & what)
|
||||
{
|
||||
if (wait != Wait) {
|
||||
retval_ = startscript(what, SignalTypePtr());
|
||||
retval_ = startScript(what, SignalTypePtr());
|
||||
return retval_;
|
||||
}
|
||||
|
||||
@ -274,7 +283,7 @@ int Forkedcall::startscript(Starttype wait, string const & what)
|
||||
}
|
||||
|
||||
|
||||
int Forkedcall::startscript(string const & what, SignalTypePtr signal)
|
||||
int ForkedCall::startScript(string const & what, SignalTypePtr signal)
|
||||
{
|
||||
command_ = what;
|
||||
signal_ = signal;
|
||||
@ -284,7 +293,7 @@ int Forkedcall::startscript(string const & what, SignalTypePtr signal)
|
||||
|
||||
|
||||
// generate child in background
|
||||
int Forkedcall::generateChild()
|
||||
int ForkedCall::generateChild()
|
||||
{
|
||||
string line = trim(command_);
|
||||
if (line.empty())
|
||||
@ -383,5 +392,258 @@ int Forkedcall::generateChild()
|
||||
return cpid;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ForkedCallQueue
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
ForkedCallQueue & ForkedCallQueue::get()
|
||||
{
|
||||
static ForkedCallQueue singleton;
|
||||
return singleton;
|
||||
}
|
||||
|
||||
|
||||
ForkedCall::SignalTypePtr ForkedCallQueue::add(string const & process)
|
||||
{
|
||||
ForkedCall::SignalTypePtr ptr;
|
||||
ptr.reset(new ForkedCall::SignalType);
|
||||
callQueue_.push(Process(process, ptr));
|
||||
if (!running_)
|
||||
startCaller();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void ForkedCallQueue::callNext()
|
||||
{
|
||||
if (callQueue_.empty())
|
||||
return;
|
||||
Process pro = callQueue_.front();
|
||||
callQueue_.pop();
|
||||
// Bind our chain caller
|
||||
pro.second->connect(boost::bind(&ForkedCallQueue::callback,
|
||||
this, _1, _2));
|
||||
ForkedCall call;
|
||||
// If we fail to fork the process, then emit the signal
|
||||
// to tell the outside world that it failed.
|
||||
if (call.startScript(pro.first, pro.second) > 0)
|
||||
pro.second->operator()(0,1);
|
||||
}
|
||||
|
||||
|
||||
void ForkedCallQueue::callback(pid_t, int)
|
||||
{
|
||||
if (callQueue_.empty())
|
||||
stopCaller();
|
||||
else
|
||||
callNext();
|
||||
}
|
||||
|
||||
|
||||
ForkedCallQueue::ForkedCallQueue()
|
||||
: running_(false)
|
||||
{}
|
||||
|
||||
|
||||
void ForkedCallQueue::startCaller()
|
||||
{
|
||||
LYXERR(Debug::GRAPHICS, "ForkedCallQueue: waking up");
|
||||
running_ = true ;
|
||||
callNext();
|
||||
}
|
||||
|
||||
|
||||
void ForkedCallQueue::stopCaller()
|
||||
{
|
||||
running_ = false ;
|
||||
LYXERR(Debug::GRAPHICS, "ForkedCallQueue: I'm going to sleep");
|
||||
}
|
||||
|
||||
|
||||
bool ForkedCallQueue::running() const
|
||||
{
|
||||
return running_ ;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ForkedCallsController
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(_WIN32)
|
||||
string const getChildErrorMessage()
|
||||
{
|
||||
DWORD const error_code = ::GetLastError();
|
||||
|
||||
HLOCAL t_message = 0;
|
||||
bool const ok = ::FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
0, error_code,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &t_message, 0, 0
|
||||
) != 0;
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "LyX: Error waiting for child: " << error_code;
|
||||
|
||||
if (ok) {
|
||||
ss << ": " << (LPTSTR)t_message;
|
||||
::LocalFree(t_message);
|
||||
} else
|
||||
ss << ": Error unknown.";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Ensure, that only one controller exists inside process
|
||||
ForkedCallsController & ForkedCallsController::get()
|
||||
{
|
||||
static ForkedCallsController singleton;
|
||||
return singleton;
|
||||
}
|
||||
|
||||
|
||||
ForkedCallsController::ForkedCallsController()
|
||||
{}
|
||||
|
||||
|
||||
// open question: should we stop childs here?
|
||||
// Asger says no: I like to have my xdvi open after closing LyX. Maybe
|
||||
// I want to print or something.
|
||||
ForkedCallsController::~ForkedCallsController()
|
||||
{}
|
||||
|
||||
|
||||
void ForkedCallsController::addCall(ForkedProcess const & newcall)
|
||||
{
|
||||
forkedCalls.push_back(newcall.clone());
|
||||
}
|
||||
|
||||
|
||||
// Check the list of dead children and emit any associated signals.
|
||||
void ForkedCallsController::handleCompletedProcesses()
|
||||
{
|
||||
ListType::iterator it = forkedCalls.begin();
|
||||
ListType::iterator end = forkedCalls.end();
|
||||
while (it != end) {
|
||||
ForkedProcessPtr actCall = *it;
|
||||
bool remove_it = false;
|
||||
|
||||
#if defined(_WIN32)
|
||||
HANDLE const hProcess = HANDLE(actCall->pid());
|
||||
|
||||
DWORD const wait_status = ::WaitForSingleObject(hProcess, 0);
|
||||
|
||||
switch (wait_status) {
|
||||
case WAIT_TIMEOUT:
|
||||
// Still running
|
||||
break;
|
||||
case WAIT_OBJECT_0: {
|
||||
DWORD exit_code = 0;
|
||||
if (!GetExitCodeProcess(hProcess, &exit_code)) {
|
||||
lyxerr << "GetExitCodeProcess failed waiting for child\n"
|
||||
<< getChildErrorMessage() << std::endl;
|
||||
// Child died, so pretend it returned 1
|
||||
actCall->setRetValue(1);
|
||||
} else {
|
||||
actCall->setRetValue(exit_code);
|
||||
}
|
||||
remove_it = true;
|
||||
break;
|
||||
}
|
||||
case WAIT_FAILED:
|
||||
lyxerr << "WaitForSingleObject failed waiting for child\n"
|
||||
<< getChildErrorMessage() << std::endl;
|
||||
actCall->setRetValue(1);
|
||||
remove_it = true;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
pid_t pid = actCall->pid();
|
||||
int stat_loc;
|
||||
pid_t const waitrpid = waitpid(pid, &stat_loc, WNOHANG);
|
||||
|
||||
if (waitrpid == -1) {
|
||||
lyxerr << "LyX: Error waiting for child: "
|
||||
<< strerror(errno) << endl;
|
||||
|
||||
// Child died, so pretend it returned 1
|
||||
actCall->setRetValue(1);
|
||||
remove_it = true;
|
||||
|
||||
} else if (waitrpid == 0) {
|
||||
// Still running. Move on to the next child.
|
||||
|
||||
} else if (WIFEXITED(stat_loc)) {
|
||||
// Ok, the return value goes into retval.
|
||||
actCall->setRetValue(WEXITSTATUS(stat_loc));
|
||||
remove_it = true;
|
||||
|
||||
} else if (WIFSIGNALED(stat_loc)) {
|
||||
// Child died, so pretend it returned 1
|
||||
actCall->setRetValue(1);
|
||||
remove_it = true;
|
||||
|
||||
} else if (WIFSTOPPED(stat_loc)) {
|
||||
lyxerr << "LyX: Child (pid: " << pid
|
||||
<< ") stopped on signal "
|
||||
<< WSTOPSIG(stat_loc)
|
||||
<< ". Waiting for child to finish." << endl;
|
||||
|
||||
} else {
|
||||
lyxerr << "LyX: Something rotten happened while "
|
||||
"waiting for child " << pid << endl;
|
||||
|
||||
// Child died, so pretend it returned 1
|
||||
actCall->setRetValue(1);
|
||||
remove_it = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (remove_it) {
|
||||
forkedCalls.erase(it);
|
||||
actCall->emitSignal();
|
||||
|
||||
/* start all over: emiting the signal can result
|
||||
* in changing the list (Ab)
|
||||
*/
|
||||
it = forkedCalls.begin();
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ForkedCallsController::iterator ForkedCallsController::find_pid(pid_t pid)
|
||||
{
|
||||
return find_if(forkedCalls.begin(), forkedCalls.end(),
|
||||
bind(equal_to<pid_t>(),
|
||||
bind(&ForkedCall::pid, _1),
|
||||
pid));
|
||||
}
|
||||
|
||||
|
||||
// Kill the process prematurely and remove it from the list
|
||||
// within tolerance secs
|
||||
void ForkedCallsController::kill(pid_t pid, int tolerance)
|
||||
{
|
||||
ListType::iterator it = find_pid(pid);
|
||||
if (it == forkedCalls.end())
|
||||
return;
|
||||
|
||||
(*it)->kill(tolerance);
|
||||
forkedCalls.erase(it);
|
||||
}
|
||||
|
||||
} // namespace support
|
||||
} // namespace lyx
|
@ -1,30 +1,18 @@
|
||||
// -*- C++ -*-
|
||||
/**
|
||||
* \file Forkedcall.h
|
||||
* \file ForkedCalls.h
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Asger Alstrup
|
||||
*
|
||||
* Interface cleaned up by
|
||||
* \author Angus Leeming
|
||||
* \author Alfredo Braunstein
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*
|
||||
* An instance of Class Forkedcall represents a single child process.
|
||||
*
|
||||
* Class Forkedcall uses fork() and execvp() to lauch the child process.
|
||||
*
|
||||
* Once launched, control is returned immediately to the parent process
|
||||
* but a Signal can be emitted upon completion of the child.
|
||||
*
|
||||
* The child process is not killed when the Forkedcall instance goes out of
|
||||
* scope, but it can be killed by an explicit invocation of the kill() member
|
||||
* function.
|
||||
*/
|
||||
|
||||
#ifndef FORKEDCALL_H
|
||||
#define FORKEDCALL_H
|
||||
#ifndef FORKEDCALLS_H
|
||||
#define FORKEDCALLS_H
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/signal.hpp>
|
||||
@ -33,6 +21,12 @@
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace lyx {
|
||||
namespace support {
|
||||
@ -134,18 +128,31 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class Forkedcall : public ForkedProcess {
|
||||
/*
|
||||
* An instance of class ForkedCall represents a single child process.
|
||||
*
|
||||
* Class ForkedCall uses fork() and execvp() to lauch the child process.
|
||||
*
|
||||
* Once launched, control is returned immediately to the parent process
|
||||
* but a Signal can be emitted upon completion of the child.
|
||||
*
|
||||
* The child process is not killed when the ForkedCall instance goes out of
|
||||
* scope, but it can be killed by an explicit invocation of the kill() member
|
||||
* function.
|
||||
*/
|
||||
|
||||
class ForkedCall : public ForkedProcess {
|
||||
public:
|
||||
///
|
||||
virtual boost::shared_ptr<ForkedProcess> clone() const {
|
||||
return boost::shared_ptr<ForkedProcess>(new Forkedcall(*this));
|
||||
return boost::shared_ptr<ForkedProcess>(new ForkedCall(*this));
|
||||
}
|
||||
|
||||
/** Start the child process.
|
||||
*
|
||||
* The command "what" is passed to execvp() for execution.
|
||||
*
|
||||
* There are two startscript commands available. They differ in that
|
||||
* There are two startScript commands available. They differ in that
|
||||
* the second receives a signal that is executed on completion of
|
||||
* the command. This makes sense only for a command executed
|
||||
* in the background, ie DontWait.
|
||||
@ -153,17 +160,107 @@ public:
|
||||
* The other startscript command can be executed either blocking
|
||||
* or non-blocking, but no signal will be emitted on finishing.
|
||||
*/
|
||||
int startscript(Starttype, std::string const & what);
|
||||
int startScript(Starttype, std::string const & what);
|
||||
|
||||
///
|
||||
int startscript(std::string const & what, SignalTypePtr);
|
||||
int startScript(std::string const & what, SignalTypePtr);
|
||||
|
||||
private:
|
||||
///
|
||||
virtual int generateChild();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This class implements a queue of forked processes. In order not to
|
||||
* hose the system with multiple processes running simultaneously, you can
|
||||
* request the addition of your process to this queue and it will be
|
||||
* executed when its turn comes.
|
||||
*
|
||||
*/
|
||||
|
||||
class ForkedCallQueue {
|
||||
public:
|
||||
/// A process in the queue
|
||||
typedef std::pair<std::string, ForkedCall::SignalTypePtr> Process;
|
||||
/** Add a process to the queue. Processes are forked sequentially
|
||||
* only one is running at a time.
|
||||
* Connect to the returned signal and you'll be informed when
|
||||
* the process has ended.
|
||||
*/
|
||||
ForkedCall::SignalTypePtr add(std::string const & process);
|
||||
/// Query whether the queue is running a forked process now.
|
||||
bool running() const;
|
||||
/// Get the and only instance of the class
|
||||
static ForkedCallQueue & get();
|
||||
|
||||
private:
|
||||
/** this class is a singleton class... use
|
||||
* ForkedCallQueue::get() instead
|
||||
*/
|
||||
ForkedCallQueue();
|
||||
/// in-progress queue
|
||||
std::queue<Process> callQueue_;
|
||||
///
|
||||
bool running_;
|
||||
///
|
||||
void callNext();
|
||||
///
|
||||
void startCaller();
|
||||
///
|
||||
void stopCaller();
|
||||
///
|
||||
void callback(pid_t, int);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A class for the control of child processes launched using
|
||||
* fork() and execvp().
|
||||
*/
|
||||
|
||||
class ForkedCallsController {
|
||||
public:
|
||||
/// Get hold of the only controller that can exist inside the process.
|
||||
static ForkedCallsController & get();
|
||||
|
||||
/// Add a new child process to the list of controlled processes.
|
||||
void addCall(ForkedProcess const &);
|
||||
|
||||
/** Those child processes that are found to have finished are removed
|
||||
* from the list and their callback function is passed the final
|
||||
* return state.
|
||||
*/
|
||||
void handleCompletedProcesses();
|
||||
|
||||
/** Kill this process prematurely and remove it from the list.
|
||||
* The process is killed within tolerance secs.
|
||||
* See forkedcall.[Ch] for details.
|
||||
*/
|
||||
void kill(pid_t, int tolerance = 5);
|
||||
|
||||
private:
|
||||
ForkedCallsController();
|
||||
ForkedCallsController(ForkedCallsController const &);
|
||||
~ForkedCallsController();
|
||||
|
||||
typedef boost::shared_ptr<ForkedProcess> ForkedProcessPtr;
|
||||
typedef std::list<ForkedProcessPtr> ListType;
|
||||
typedef ListType::iterator iterator;
|
||||
|
||||
iterator find_pid(pid_t);
|
||||
|
||||
/// The child processes
|
||||
ListType forkedCalls;
|
||||
};
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
// a wrapper for GetLastError() and FormatMessage().
|
||||
std::string const getChildErrorMessage();
|
||||
#endif
|
||||
|
||||
} // namespace support
|
||||
} // namespace lyx
|
||||
|
||||
#endif // FORKEDCALL_H
|
||||
#endif // FORKEDCALLS_H
|
@ -1,226 +0,0 @@
|
||||
/**
|
||||
* \file ForkedcallsController.cpp
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Asger Alstrup Nielsen
|
||||
* \author Angus Leeming
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*
|
||||
* A class for the control of child processes launched using
|
||||
* fork() and execvp().
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "support/ForkedcallsController.h"
|
||||
|
||||
#include "support/debug.h"
|
||||
#include "support/Forkedcall.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <sstream>
|
||||
# include <windows.h>
|
||||
|
||||
#else
|
||||
# include <cerrno>
|
||||
# include <csignal>
|
||||
# include <cstdlib>
|
||||
# ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
# endif
|
||||
# include <sys/wait.h>
|
||||
|
||||
# ifndef CXX_GLOBAL_CSTD
|
||||
using std::signal;
|
||||
using std::strerror;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
using boost::bind;
|
||||
|
||||
using std::endl;
|
||||
using std::equal_to;
|
||||
using std::find_if;
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace lyx {
|
||||
namespace support {
|
||||
|
||||
#if defined(_WIN32)
|
||||
string const getChildErrorMessage()
|
||||
{
|
||||
DWORD const error_code = ::GetLastError();
|
||||
|
||||
HLOCAL t_message = 0;
|
||||
bool const ok = ::FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
0, error_code,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &t_message, 0, 0
|
||||
) != 0;
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "LyX: Error waiting for child: " << error_code;
|
||||
|
||||
if (ok) {
|
||||
ss << ": " << (LPTSTR)t_message;
|
||||
::LocalFree(t_message);
|
||||
} else
|
||||
ss << ": Error unknown.";
|
||||
|
||||
return ss.str().c_str();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Ensure, that only one controller exists inside process
|
||||
ForkedcallsController & ForkedcallsController::get()
|
||||
{
|
||||
static ForkedcallsController singleton;
|
||||
return singleton;
|
||||
}
|
||||
|
||||
|
||||
ForkedcallsController::ForkedcallsController()
|
||||
{}
|
||||
|
||||
|
||||
// open question: should we stop childs here?
|
||||
// Asger says no: I like to have my xdvi open after closing LyX. Maybe
|
||||
// I want to print or something.
|
||||
ForkedcallsController::~ForkedcallsController()
|
||||
{}
|
||||
|
||||
|
||||
void ForkedcallsController::addCall(ForkedProcess const & newcall)
|
||||
{
|
||||
forkedCalls.push_back(newcall.clone());
|
||||
}
|
||||
|
||||
|
||||
// Check the list of dead children and emit any associated signals.
|
||||
void ForkedcallsController::handleCompletedProcesses()
|
||||
{
|
||||
ListType::iterator it = forkedCalls.begin();
|
||||
ListType::iterator end = forkedCalls.end();
|
||||
while (it != end) {
|
||||
ForkedProcessPtr actCall = *it;
|
||||
bool remove_it = false;
|
||||
|
||||
#if defined(_WIN32)
|
||||
HANDLE const hProcess = HANDLE(actCall->pid());
|
||||
|
||||
DWORD const wait_status = ::WaitForSingleObject(hProcess, 0);
|
||||
|
||||
switch (wait_status) {
|
||||
case WAIT_TIMEOUT:
|
||||
// Still running
|
||||
break;
|
||||
case WAIT_OBJECT_0: {
|
||||
DWORD exit_code = 0;
|
||||
if (!GetExitCodeProcess(hProcess, &exit_code)) {
|
||||
lyxerr << "GetExitCodeProcess failed waiting for child\n"
|
||||
<< getChildErrorMessage() << std::endl;
|
||||
// Child died, so pretend it returned 1
|
||||
actCall->setRetValue(1);
|
||||
} else {
|
||||
actCall->setRetValue(exit_code);
|
||||
}
|
||||
remove_it = true;
|
||||
break;
|
||||
}
|
||||
case WAIT_FAILED:
|
||||
lyxerr << "WaitForSingleObject failed waiting for child\n"
|
||||
<< getChildErrorMessage() << std::endl;
|
||||
actCall->setRetValue(1);
|
||||
remove_it = true;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
pid_t pid = actCall->pid();
|
||||
int stat_loc;
|
||||
pid_t const waitrpid = waitpid(pid, &stat_loc, WNOHANG);
|
||||
|
||||
if (waitrpid == -1) {
|
||||
lyxerr << "LyX: Error waiting for child: "
|
||||
<< strerror(errno) << endl;
|
||||
|
||||
// Child died, so pretend it returned 1
|
||||
actCall->setRetValue(1);
|
||||
remove_it = true;
|
||||
|
||||
} else if (waitrpid == 0) {
|
||||
// Still running. Move on to the next child.
|
||||
|
||||
} else if (WIFEXITED(stat_loc)) {
|
||||
// Ok, the return value goes into retval.
|
||||
actCall->setRetValue(WEXITSTATUS(stat_loc));
|
||||
remove_it = true;
|
||||
|
||||
} else if (WIFSIGNALED(stat_loc)) {
|
||||
// Child died, so pretend it returned 1
|
||||
actCall->setRetValue(1);
|
||||
remove_it = true;
|
||||
|
||||
} else if (WIFSTOPPED(stat_loc)) {
|
||||
lyxerr << "LyX: Child (pid: " << pid
|
||||
<< ") stopped on signal "
|
||||
<< WSTOPSIG(stat_loc)
|
||||
<< ". Waiting for child to finish." << endl;
|
||||
|
||||
} else {
|
||||
lyxerr << "LyX: Something rotten happened while "
|
||||
"waiting for child " << pid << endl;
|
||||
|
||||
// Child died, so pretend it returned 1
|
||||
actCall->setRetValue(1);
|
||||
remove_it = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (remove_it) {
|
||||
forkedCalls.erase(it);
|
||||
actCall->emitSignal();
|
||||
|
||||
/* start all over: emiting the signal can result
|
||||
* in changing the list (Ab)
|
||||
*/
|
||||
it = forkedCalls.begin();
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ForkedcallsController::iterator
|
||||
ForkedcallsController::find_pid(pid_t pid)
|
||||
{
|
||||
return find_if(forkedCalls.begin(), forkedCalls.end(),
|
||||
bind(equal_to<pid_t>(),
|
||||
bind(&Forkedcall::pid, _1),
|
||||
pid));
|
||||
}
|
||||
|
||||
|
||||
// Kill the process prematurely and remove it from the list
|
||||
// within tolerance secs
|
||||
void ForkedcallsController::kill(pid_t pid, int tolerance)
|
||||
{
|
||||
ListType::iterator it = find_pid(pid);
|
||||
if (it == forkedCalls.end())
|
||||
return;
|
||||
|
||||
(*it)->kill(tolerance);
|
||||
forkedCalls.erase(it);
|
||||
}
|
||||
|
||||
} // namespace support
|
||||
} // namespace lyx
|
@ -1,79 +0,0 @@
|
||||
// -*- C++ -*-
|
||||
/**
|
||||
* \file ForkedcallsController.h
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Asger Alstrup Nielsen
|
||||
* \author Angus Leeming
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*
|
||||
* A class for the control of child processes launched using
|
||||
* fork() and execvp().
|
||||
*/
|
||||
|
||||
#ifndef FORKEDCALLSCONTROLLER_H
|
||||
#define FORKEDCALLSCONTROLLER_H
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace lyx {
|
||||
namespace support {
|
||||
|
||||
class ForkedProcess;
|
||||
|
||||
class ForkedcallsController {
|
||||
public:
|
||||
/// Get hold of the only controller that can exist inside the process.
|
||||
static ForkedcallsController & get();
|
||||
|
||||
/// Add a new child process to the list of controlled processes.
|
||||
void addCall(ForkedProcess const &);
|
||||
|
||||
/** Those child processes that are found to have finished are removed
|
||||
* from the list and their callback function is passed the final
|
||||
* return state.
|
||||
*/
|
||||
void handleCompletedProcesses();
|
||||
|
||||
/** Kill this process prematurely and remove it from the list.
|
||||
* The process is killed within tolerance secs.
|
||||
* See forkedcall.[Ch] for details.
|
||||
*/
|
||||
void kill(pid_t, int tolerance = 5);
|
||||
|
||||
private:
|
||||
ForkedcallsController();
|
||||
ForkedcallsController(ForkedcallsController const &);
|
||||
~ForkedcallsController();
|
||||
|
||||
typedef boost::shared_ptr<ForkedProcess> ForkedProcessPtr;
|
||||
typedef std::list<ForkedProcessPtr> ListType;
|
||||
typedef ListType::iterator iterator;
|
||||
|
||||
iterator find_pid(pid_t);
|
||||
|
||||
/// The child processes
|
||||
ListType forkedCalls;
|
||||
};
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
// a wrapper for GetLastError() and FormatMessage().
|
||||
std::string const getChildErrorMessage();
|
||||
#endif
|
||||
|
||||
} // namespace support
|
||||
} // namespace lyx
|
||||
|
||||
#endif // FORKEDCALLSCONTROLLER_H
|
@ -44,12 +44,8 @@ liblyxsupport_la_SOURCES = \
|
||||
FileName.h \
|
||||
filetools.cpp \
|
||||
filetools.h \
|
||||
Forkedcall.cpp \
|
||||
Forkedcall.h \
|
||||
ForkedCallQueue.cpp \
|
||||
ForkedCallQueue.h \
|
||||
ForkedcallsController.cpp \
|
||||
ForkedcallsController.h \
|
||||
ForkedCalls.cpp \
|
||||
ForkedCalls.h \
|
||||
gettext.cpp \
|
||||
gettext.h \
|
||||
getcwd.cpp \
|
||||
|
Loading…
Reference in New Issue
Block a user