mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 13:18:28 +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/debug.h"
|
||||||
#include "support/FileFilterList.h"
|
#include "support/FileFilterList.h"
|
||||||
#include "support/filetools.h"
|
#include "support/filetools.h"
|
||||||
#include "support/Forkedcall.h"
|
#include "support/ForkedCalls.h"
|
||||||
#include "support/gettext.h"
|
#include "support/gettext.h"
|
||||||
#include "support/gzstream.h"
|
#include "support/gzstream.h"
|
||||||
#include "support/lstrings.h"
|
#include "support/lstrings.h"
|
||||||
|
@ -15,14 +15,14 @@
|
|||||||
#include "ISpell.h"
|
#include "ISpell.h"
|
||||||
|
|
||||||
#include "BufferParams.h"
|
#include "BufferParams.h"
|
||||||
#include "support/debug.h"
|
|
||||||
#include "Encoding.h"
|
#include "Encoding.h"
|
||||||
#include "support/gettext.h"
|
|
||||||
#include "Language.h"
|
#include "Language.h"
|
||||||
#include "LyXRC.h"
|
#include "LyXRC.h"
|
||||||
#include "WordLangTuple.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/lstrings.h"
|
||||||
#include "support/unicode.h"
|
#include "support/unicode.h"
|
||||||
|
|
||||||
|
@ -18,10 +18,8 @@
|
|||||||
#include "BufferView.h"
|
#include "BufferView.h"
|
||||||
#include "CoordCache.h"
|
#include "CoordCache.h"
|
||||||
#include "Cursor.h"
|
#include "Cursor.h"
|
||||||
#include "support/debug.h"
|
|
||||||
#include "Font.h"
|
#include "Font.h"
|
||||||
#include "FuncRequest.h"
|
#include "FuncRequest.h"
|
||||||
#include "support/gettext.h"
|
|
||||||
#include "GuiApplication.h"
|
#include "GuiApplication.h"
|
||||||
#include "GuiKeySymbol.h"
|
#include "GuiKeySymbol.h"
|
||||||
#include "GuiPainter.h"
|
#include "GuiPainter.h"
|
||||||
@ -37,8 +35,10 @@
|
|||||||
#include "graphics/GraphicsImage.h"
|
#include "graphics/GraphicsImage.h"
|
||||||
#include "graphics/GraphicsLoader.h"
|
#include "graphics/GraphicsLoader.h"
|
||||||
|
|
||||||
|
#include "support/debug.h"
|
||||||
|
#include "support/gettext.h"
|
||||||
#include "support/FileName.h"
|
#include "support/FileName.h"
|
||||||
#include "support/ForkedcallsController.h"
|
#include "support/ForkedCalls.h"
|
||||||
|
|
||||||
#include "frontends/Application.h"
|
#include "frontends/Application.h"
|
||||||
#include "frontends/FontMetrics.h"
|
#include "frontends/FontMetrics.h"
|
||||||
@ -79,7 +79,7 @@ using std::string;
|
|||||||
namespace lyx {
|
namespace lyx {
|
||||||
|
|
||||||
using support::FileName;
|
using support::FileName;
|
||||||
using support::ForkedcallsController;
|
using support::ForkedCallsController;
|
||||||
|
|
||||||
|
|
||||||
/// return the LyX mouse button state from Qt's
|
/// 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
|
// Use this opportunity to deal with any child processes that
|
||||||
// have finished but are waiting to communicate this fact
|
// have finished but are waiting to communicate this fact
|
||||||
// to the rest of LyX.
|
// to the rest of LyX.
|
||||||
ForkedcallsController & fcc = ForkedcallsController::get();
|
ForkedCallsController & fcc = ForkedCallsController::get();
|
||||||
fcc.handleCompletedProcesses();
|
fcc.handleCompletedProcesses();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,12 +13,12 @@
|
|||||||
#include "GraphicsConverter.h"
|
#include "GraphicsConverter.h"
|
||||||
|
|
||||||
#include "Converter.h"
|
#include "Converter.h"
|
||||||
#include "support/debug.h"
|
|
||||||
#include "Format.h"
|
#include "Format.h"
|
||||||
|
|
||||||
#include "support/filetools.h"
|
|
||||||
#include "support/ForkedCallQueue.h"
|
|
||||||
#include "support/convert.h"
|
#include "support/convert.h"
|
||||||
|
#include "support/debug.h"
|
||||||
|
#include "support/filetools.h"
|
||||||
|
#include "support/ForkedCalls.h"
|
||||||
#include "support/lstrings.h"
|
#include "support/lstrings.h"
|
||||||
#include "support/lyxlib.h"
|
#include "support/lyxlib.h"
|
||||||
#include "support/os.h"
|
#include "support/os.h"
|
||||||
@ -33,7 +33,7 @@ namespace support = lyx::support;
|
|||||||
using support::addExtension;
|
using support::addExtension;
|
||||||
using support::changeExtension;
|
using support::changeExtension;
|
||||||
using support::FileName;
|
using support::FileName;
|
||||||
using support::Forkedcall;
|
using support::ForkedCall;
|
||||||
using support::ForkedCallQueue;
|
using support::ForkedCallQueue;
|
||||||
using support::getExtension;
|
using support::getExtension;
|
||||||
using support::libScriptSearch;
|
using support::libScriptSearch;
|
||||||
@ -193,7 +193,7 @@ void Converter::Impl::startConversion()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Forkedcall::SignalTypePtr
|
ForkedCall::SignalTypePtr
|
||||||
ptr = ForkedCallQueue::get().add(script_command_);
|
ptr = ForkedCallQueue::get().add(script_command_);
|
||||||
|
|
||||||
ptr->connect(boost::bind(&Impl::converted, this, _1, _2));
|
ptr->connect(boost::bind(&Impl::converted, this, _1, _2));
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "BufferParams.h"
|
#include "BufferParams.h"
|
||||||
#include "Converter.h"
|
#include "Converter.h"
|
||||||
#include "support/debug.h"
|
|
||||||
#include "Encoding.h"
|
#include "Encoding.h"
|
||||||
#include "Format.h"
|
#include "Format.h"
|
||||||
#include "InsetIterator.h"
|
#include "InsetIterator.h"
|
||||||
@ -31,12 +30,12 @@
|
|||||||
|
|
||||||
#include "insets/Inset.h"
|
#include "insets/Inset.h"
|
||||||
|
|
||||||
|
#include "support/convert.h"
|
||||||
|
#include "support/debug.h"
|
||||||
#include "support/filetools.h"
|
#include "support/filetools.h"
|
||||||
#include "support/Forkedcall.h"
|
#include "support/ForkedCalls.h"
|
||||||
#include "support/ForkedcallsController.h"
|
|
||||||
#include "support/lstrings.h"
|
#include "support/lstrings.h"
|
||||||
#include "support/lyxlib.h"
|
#include "support/lyxlib.h"
|
||||||
#include "support/convert.h"
|
|
||||||
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
@ -229,7 +228,7 @@ public:
|
|||||||
Buffer const & buffer() const { return buffer_; }
|
Buffer const & buffer() const { return buffer_; }
|
||||||
|
|
||||||
private:
|
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 finishedGenerating(pid_t, int);
|
||||||
///
|
///
|
||||||
void dumpPreamble(odocstream &) const;
|
void dumpPreamble(odocstream &) const;
|
||||||
@ -384,7 +383,7 @@ InProgress::InProgress(string const & filename_base,
|
|||||||
void InProgress::stop() const
|
void InProgress::stop() const
|
||||||
{
|
{
|
||||||
if (pid)
|
if (pid)
|
||||||
lyx::support::ForkedcallsController::get().kill(pid, 0);
|
lyx::support::ForkedCallsController::get().kill(pid, 0);
|
||||||
|
|
||||||
if (!metrics_file.empty())
|
if (!metrics_file.empty())
|
||||||
metrics_file.removeFile();
|
metrics_file.removeFile();
|
||||||
@ -608,12 +607,12 @@ void PreviewLoader::Impl::startLoading()
|
|||||||
string const command = support::libScriptSearch(cs.str());
|
string const command = support::libScriptSearch(cs.str());
|
||||||
|
|
||||||
// Initiate the conversion from LaTeX to bitmap images files.
|
// Initiate the conversion from LaTeX to bitmap images files.
|
||||||
support::Forkedcall::SignalTypePtr
|
support::ForkedCall::SignalTypePtr
|
||||||
convert_ptr(new support::Forkedcall::SignalType);
|
convert_ptr(new support::ForkedCall::SignalType);
|
||||||
convert_ptr->connect(bind(&Impl::finishedGenerating, this, _1, _2));
|
convert_ptr->connect(bind(&Impl::finishedGenerating, this, _1, _2));
|
||||||
|
|
||||||
support::Forkedcall call;
|
support::ForkedCall call;
|
||||||
int ret = call.startscript(command, convert_ptr);
|
int ret = call.startScript(command, convert_ptr);
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
LYXERR(Debug::GRAPHICS, "PreviewLoader::startLoading()\n"
|
LYXERR(Debug::GRAPHICS, "PreviewLoader::startLoading()\n"
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "Converter.h"
|
#include "Converter.h"
|
||||||
#include "support/debug.h"
|
|
||||||
#include "support/gettext.h"
|
|
||||||
#include "ErrorList.h"
|
#include "ErrorList.h"
|
||||||
#include "Exporter.h"
|
#include "Exporter.h"
|
||||||
#include "Format.h"
|
#include "Format.h"
|
||||||
@ -27,8 +25,9 @@
|
|||||||
|
|
||||||
#include "frontends/alert.h"
|
#include "frontends/alert.h"
|
||||||
|
|
||||||
|
#include "support/debug.h"
|
||||||
#include "support/filetools.h"
|
#include "support/filetools.h"
|
||||||
#include "support/Forkedcall.h"
|
#include "support/gettext.h"
|
||||||
#include "support/lstrings.h"
|
#include "support/lstrings.h"
|
||||||
#include "support/lyxalgo.h"
|
#include "support/lyxalgo.h"
|
||||||
#include "support/lyxlib.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.
|
* This file is part of LyX, the document processor.
|
||||||
* Licence details can be found in the file COPYING.
|
* Licence details can be found in the file COPYING.
|
||||||
*
|
*
|
||||||
* \author Asger Alstrup
|
* \author Asger Alstrup
|
||||||
*
|
|
||||||
* Interface cleaned up by
|
|
||||||
* \author Angus Leeming
|
* \author Angus Leeming
|
||||||
|
* \author Alfredo Braunstein
|
||||||
*
|
*
|
||||||
* Full author contact details are available in file CREDITS.
|
* 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 <config.h>
|
||||||
|
|
||||||
#include "support/Forkedcall.h"
|
#include "support/ForkedCalls.h"
|
||||||
|
|
||||||
#include "support/debug.h"
|
#include "support/debug.h"
|
||||||
#include "support/filetools.h"
|
#include "support/filetools.h"
|
||||||
#include "support/ForkedcallsController.h"
|
|
||||||
#include "support/lstrings.h"
|
#include "support/lstrings.h"
|
||||||
#include "support/lyxlib.h"
|
#include "support/lyxlib.h"
|
||||||
#include "support/os.h"
|
#include "support/os.h"
|
||||||
@ -38,13 +25,13 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# define SIGHUP 1
|
# define SIGHUP 1
|
||||||
# define SIGKILL 9
|
# define SIGKILL 9
|
||||||
# include <process.h>
|
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
|
# include <process.h>
|
||||||
#else
|
#else
|
||||||
# include <csignal>
|
# include <csignal>
|
||||||
# include <cstdlib>
|
# include <cstdlib>
|
||||||
@ -52,22 +39,32 @@
|
|||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
# endif
|
# endif
|
||||||
# include <sys/wait.h>
|
# include <sys/wait.h>
|
||||||
|
# ifndef CXX_GLOBAL_CSTD
|
||||||
|
using std::signal;
|
||||||
|
using std::strerror;
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using boost::bind;
|
||||||
|
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
using std::equal_to;
|
||||||
|
using std::find_if;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
#ifndef CXX_GLOBAL_CSTD
|
|
||||||
using std::strerror;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace lyx {
|
namespace lyx {
|
||||||
namespace support {
|
namespace support {
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Murder
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class Murder : public boost::signals::trackable {
|
class Murder : public boost::signals::trackable {
|
||||||
public:
|
public:
|
||||||
//
|
//
|
||||||
@ -83,9 +80,8 @@ public:
|
|||||||
//
|
//
|
||||||
void kill()
|
void kill()
|
||||||
{
|
{
|
||||||
if (pid_ != 0) {
|
if (pid_ != 0)
|
||||||
support::kill(pid_, SIGKILL);
|
support::kill(pid_, SIGKILL);
|
||||||
}
|
|
||||||
lyxerr << "Killed " << pid_ << std::endl;
|
lyxerr << "Killed " << pid_ << std::endl;
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
@ -114,6 +110,12 @@ private:
|
|||||||
} // namespace anon
|
} // namespace anon
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// ForkedProcess
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ForkedProcess::ForkedProcess()
|
ForkedProcess::ForkedProcess()
|
||||||
: pid_(0), retval_(0)
|
: pid_(0), retval_(0)
|
||||||
{}
|
{}
|
||||||
@ -143,7 +145,7 @@ int ForkedProcess::run(Starttype type)
|
|||||||
break;
|
break;
|
||||||
case DontWait: {
|
case DontWait: {
|
||||||
// Integrate into the Controller
|
// Integrate into the Controller
|
||||||
ForkedcallsController & contr = ForkedcallsController::get();
|
ForkedCallsController & contr = ForkedCallsController::get();
|
||||||
contr.addCall(*this);
|
contr.addCall(*this);
|
||||||
break;
|
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) {
|
if (wait != Wait) {
|
||||||
retval_ = startscript(what, SignalTypePtr());
|
retval_ = startScript(what, SignalTypePtr());
|
||||||
return retval_;
|
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;
|
command_ = what;
|
||||||
signal_ = signal;
|
signal_ = signal;
|
||||||
@ -284,7 +293,7 @@ int Forkedcall::startscript(string const & what, SignalTypePtr signal)
|
|||||||
|
|
||||||
|
|
||||||
// generate child in background
|
// generate child in background
|
||||||
int Forkedcall::generateChild()
|
int ForkedCall::generateChild()
|
||||||
{
|
{
|
||||||
string line = trim(command_);
|
string line = trim(command_);
|
||||||
if (line.empty())
|
if (line.empty())
|
||||||
@ -383,5 +392,258 @@ int Forkedcall::generateChild()
|
|||||||
return cpid;
|
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 support
|
||||||
} // namespace lyx
|
} // namespace lyx
|
@ -1,30 +1,18 @@
|
|||||||
// -*- C++ -*-
|
// -*- C++ -*-
|
||||||
/**
|
/**
|
||||||
* \file Forkedcall.h
|
* \file ForkedCalls.h
|
||||||
* This file is part of LyX, the document processor.
|
* This file is part of LyX, the document processor.
|
||||||
* Licence details can be found in the file COPYING.
|
* Licence details can be found in the file COPYING.
|
||||||
*
|
*
|
||||||
* \author Asger Alstrup
|
* \author Asger Alstrup
|
||||||
*
|
|
||||||
* Interface cleaned up by
|
|
||||||
* \author Angus Leeming
|
* \author Angus Leeming
|
||||||
|
* \author Alfredo Braunstein
|
||||||
*
|
*
|
||||||
* Full author contact details are available in file CREDITS.
|
* 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
|
#ifndef FORKEDCALLS_H
|
||||||
#define FORKEDCALL_H
|
#define FORKEDCALLS_H
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/signal.hpp>
|
#include <boost/signal.hpp>
|
||||||
@ -33,6 +21,12 @@
|
|||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <queue>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
namespace lyx {
|
namespace lyx {
|
||||||
namespace support {
|
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:
|
public:
|
||||||
///
|
///
|
||||||
virtual boost::shared_ptr<ForkedProcess> clone() const {
|
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.
|
/** Start the child process.
|
||||||
*
|
*
|
||||||
* The command "what" is passed to execvp() for execution.
|
* 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 second receives a signal that is executed on completion of
|
||||||
* the command. This makes sense only for a command executed
|
* the command. This makes sense only for a command executed
|
||||||
* in the background, ie DontWait.
|
* in the background, ie DontWait.
|
||||||
@ -153,17 +160,107 @@ public:
|
|||||||
* The other startscript command can be executed either blocking
|
* The other startscript command can be executed either blocking
|
||||||
* or non-blocking, but no signal will be emitted on finishing.
|
* 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:
|
private:
|
||||||
///
|
///
|
||||||
virtual int generateChild();
|
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 support
|
||||||
} // namespace lyx
|
} // 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 \
|
FileName.h \
|
||||||
filetools.cpp \
|
filetools.cpp \
|
||||||
filetools.h \
|
filetools.h \
|
||||||
Forkedcall.cpp \
|
ForkedCalls.cpp \
|
||||||
Forkedcall.h \
|
ForkedCalls.h \
|
||||||
ForkedCallQueue.cpp \
|
|
||||||
ForkedCallQueue.h \
|
|
||||||
ForkedcallsController.cpp \
|
|
||||||
ForkedcallsController.h \
|
|
||||||
gettext.cpp \
|
gettext.cpp \
|
||||||
gettext.h \
|
gettext.h \
|
||||||
getcwd.cpp \
|
getcwd.cpp \
|
||||||
|
Loading…
Reference in New Issue
Block a user