#include <boost/bind.hpp>
-#include <vector>
#include <cerrno>
+#include <queue>
#include <sstream>
+#include <utility>
+#include <vector>
#ifdef _WIN32
# define SIGHUP 1
# define SIGKILL 9
# include <windows.h>
# include <process.h>
+# undef max
#else
# include <csignal>
# include <cstdlib>
# 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;
+using namespace std;
+using boost::bind;
namespace lyx {
namespace support {
//
static void killItDead(int secs, pid_t pid)
{
- if (secs > 0) {
+ if (secs > 0)
new Murder(secs, pid);
- } else if (pid != 0) {
+ else if (pid != 0)
support::kill(pid, SIGKILL);
- }
}
//
{
if (pid_ != 0)
support::kill(pid_, SIGKILL);
- lyxerr << "Killed " << pid_ << std::endl;
+ lyxerr << "Killed " << pid_ << endl;
delete this;
}
private:
//
Murder(int secs, pid_t pid)
- : timeout_(0), pid_(pid)
+ : timeout_(1000*secs, Timeout::ONETIME), pid_(pid)
{
- timeout_ = new Timeout(1000*secs, Timeout::ONETIME);
- timeout_->timeout.connect(boost::bind(&Murder::kill, this));
- timeout_->start();
+ timeout_.timeout.connect(boost::bind(&Murder::kill, this));
+ timeout_.start();
}
//
- ~Murder()
- {
- delete timeout_;
- }
- //
- Timeout * timeout_;
+ Timeout timeout_;
//
pid_t pid_;
};
// Spawn the child process
int ForkedProcess::run(Starttype type)
{
- retval_ = 0;
+ retval_ = 0;
pid_ = generateChild();
if (pid_ <= 0) { // child or fork failed.
retval_ = 1;
break;
case DontWait: {
// Integrate into the Controller
- ForkedCallsController & contr = ForkedCallsController::get();
- contr.addCall(*this);
+ ForkedCallsController::addCall(*this);
break;
}
}
return;
}
- // The weird (std::max)(a,b) signature prevents expansion
- // of an evil MSVC macro.
- int const tolerance = (std::max)(0, tol);
+ int const tolerance = max(0, tol);
if (tolerance == 0) {
// Kill it dead NOW!
Murder::killItDead(0, pid());
-
} else {
int ret = support::kill(pid(), SIGHUP);
// The process is already dead if wait_for_death is false
bool const wait_for_death = (ret == 0 && errno != ESRCH);
- if (wait_for_death) {
+ if (wait_for_death)
Murder::killItDead(tolerance, pid());
- }
}
}
DWORD exit_code = 0;
if (!GetExitCodeProcess(hProcess, &exit_code)) {
lyxerr << "GetExitCodeProcess failed waiting for child\n"
- << getChildErrorMessage() << std::endl;
+ << getChildErrorMessage() << endl;
} else
retval_ = exit_code;
break;
}
case WAIT_FAILED:
lyxerr << "WaitForSingleObject failed waiting for child\n"
- << getChildErrorMessage() << std::endl;
+ << getChildErrorMessage() << endl;
break;
}
for (; ait != aend; ++ait)
if (*ait)
lyxerr << '\t'<< *ait << '\n';
- lyxerr << "</command>" << std::endl;
+ lyxerr << "</command>" << endl;
}
#ifdef _WIN32
//
/////////////////////////////////////////////////////////////////////
+namespace ForkedCallQueue {
-ForkedCallQueue & ForkedCallQueue::get()
-{
- static ForkedCallQueue singleton;
- return singleton;
-}
+/// A process in the queue
+typedef pair<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(string const & process);
+
+/// in-progress queue
+static queue<Process> callQueue_;
+/// flag whether queue is running
+static bool running_ = 0;
-ForkedCall::SignalTypePtr ForkedCallQueue::add(string const & process)
+///
+void startCaller();
+///
+void stopCaller();
+///
+void callback(pid_t, int);
+
+ForkedCall::SignalTypePtr add(string const & process)
{
ForkedCall::SignalTypePtr ptr;
ptr.reset(new ForkedCall::SignalType);
}
-void ForkedCallQueue::callNext()
+void 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));
+ pro.second->connect(boost::bind(&ForkedCallQueue::callback, _1, _2));
ForkedCall call;
// If we fail to fork the process, then emit the signal
// to tell the outside world that it failed.
}
-void ForkedCallQueue::callback(pid_t, int)
+void callback(pid_t, int)
{
if (callQueue_.empty())
stopCaller();
}
-ForkedCallQueue::ForkedCallQueue()
- : running_(false)
-{}
-
-
-void ForkedCallQueue::startCaller()
+void startCaller()
{
LYXERR(Debug::GRAPHICS, "ForkedCallQueue: waking up");
running_ = true ;
}
-void ForkedCallQueue::stopCaller()
+void stopCaller()
{
running_ = false ;
LYXERR(Debug::GRAPHICS, "ForkedCallQueue: I'm going to sleep");
}
-bool ForkedCallQueue::running() const
+bool running()
{
- return running_ ;
+ return running_;
}
+} // namespace ForkedCallsQueue
+
+
/////////////////////////////////////////////////////////////////////
//
(LPTSTR) &t_message, 0, 0
) != 0;
- std::ostringstream ss;
+ ostringstream ss;
ss << "LyX: Error waiting for child: " << error_code;
if (ok) {
#endif
-// Ensure, that only one controller exists inside process
-ForkedCallsController & ForkedCallsController::get()
-{
- static ForkedCallsController singleton;
- return singleton;
-}
+namespace ForkedCallsController {
+typedef boost::shared_ptr<ForkedProcess> ForkedProcessPtr;
+typedef list<ForkedProcessPtr> ListType;
+typedef ListType::iterator iterator;
-ForkedCallsController::ForkedCallsController()
-{}
+/// The child processes
+static ListType forkedCalls;
-// 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()
-{}
+iterator find_pid(pid_t pid)
+{
+ return find_if(forkedCalls.begin(), forkedCalls.end(),
+ bind(equal_to<pid_t>(),
+ bind(&ForkedCall::pid, _1),
+ pid));
+}
-void ForkedCallsController::addCall(ForkedProcess const & newcall)
+void addCall(ForkedProcess const & newcall)
{
forkedCalls.push_back(newcall.clone());
}
// Check the list of dead children and emit any associated signals.
-void ForkedCallsController::handleCompletedProcesses()
+void handleCompletedProcesses()
{
ListType::iterator it = forkedCalls.begin();
ListType::iterator end = forkedCalls.end();
DWORD exit_code = 0;
if (!GetExitCodeProcess(hProcess, &exit_code)) {
lyxerr << "GetExitCodeProcess failed waiting for child\n"
- << getChildErrorMessage() << std::endl;
+ << getChildErrorMessage() << endl;
// Child died, so pretend it returned 1
actCall->setRetValue(1);
} else {
}
case WAIT_FAILED:
lyxerr << "WaitForSingleObject failed waiting for child\n"
- << getChildErrorMessage() << std::endl;
+ << getChildErrorMessage() << endl;
actCall->setRetValue(1);
remove_it = true;
break;
}
-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)
+void kill(pid_t pid, int tolerance)
{
ListType::iterator it = find_pid(pid);
if (it == forkedCalls.end())
forkedCalls.erase(it);
}
+} // namespace ForkedCallsController
+
} // namespace support
} // namespace lyx